nfs: don't sleep with inode lock in lock_and_join_requests
authorWeston Andros Adamson <dros@primarydata.com>
Fri, 8 Aug 2014 15:00:57 +0000 (11:00 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Fri, 22 Aug 2014 22:04:43 +0000 (18:04 -0400)
This handles the 'nonblock=false' case in nfs_lock_and_join_requests.
If the group is already locked and blocking is allowed, drop the inode lock
and wait for the group lock to be cleared before trying it all again.
This should fix warnings found in peterz's tree (sched/wait branch), where
might_sleep() checks are added to wait.[ch].

Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Reviewed-by: Peng Tao <tao.peng@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/pagelist.c
fs/nfs/write.c
include/linux/nfs_page.h

index 30c9626f96b071bd6b7a1fe2de8588d844469528..4ec67f8d70aa300c528829f4b2dfd55a9203c35c 100644 (file)
@@ -167,6 +167,23 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
        return -EAGAIN;
 }
 
+/*
+ * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it
+ * @req - a request in the group
+ *
+ * This is a blocking call to wait for the group lock to be cleared.
+ */
+void
+nfs_page_group_lock_wait(struct nfs_page *req)
+{
+       struct nfs_page *head = req->wb_head;
+
+       WARN_ON_ONCE(head != head->wb_head);
+
+       wait_on_bit(&head->wb_flags, PG_HEADLOCK,
+               TASK_UNINTERRUPTIBLE);
+}
+
 /*
  * nfs_page_group_unlock - unlock the head of the page group
  * @req - request in group that is to be unlocked
index e056f617adf2f927bcc86b8cda118479a9588bee..175d5d073ccf350db485daf81ab3030555d80a60 100644 (file)
@@ -478,13 +478,23 @@ try_again:
                return NULL;
        }
 
-       /* lock each request in the page group */
+       /* holding inode lock, so always make a non-blocking call to try the
+        * page group lock */
        ret = nfs_page_group_lock(head, true);
        if (ret < 0) {
                spin_unlock(&inode->i_lock);
+
+               if (!nonblock && ret == -EAGAIN) {
+                       nfs_page_group_lock_wait(head);
+                       nfs_release_request(head);
+                       goto try_again;
+               }
+
                nfs_release_request(head);
                return ERR_PTR(ret);
        }
+
+       /* lock each request in the page group */
        subreq = head;
        do {
                /*
index 6ad2bbcad4050c12105778c3011b5196fcbf4b9e..6c3e06ee2fb7af63cc5a87314baec589631619af 100644 (file)
@@ -123,6 +123,7 @@ extern  int nfs_wait_on_request(struct nfs_page *);
 extern void nfs_unlock_request(struct nfs_page *req);
 extern void nfs_unlock_and_release_request(struct nfs_page *);
 extern int nfs_page_group_lock(struct nfs_page *, bool);
+extern void nfs_page_group_lock_wait(struct nfs_page *);
 extern void nfs_page_group_unlock(struct nfs_page *);
 extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);