aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@primarydata.com>2014-08-08 11:00:57 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-08-22 18:04:43 -0400
commit7c3af975257383ece54b83c0505d3e0656cb7daf (patch)
tree44688dff0d435b29531366be55e42f5f99928a9c
parent94970014c46223cbcdfbfc67b89596a412f9e3dd (diff)
nfs: don't sleep with inode lock in lock_and_join_requests
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>
-rw-r--r--fs/nfs/pagelist.c17
-rw-r--r--fs/nfs/write.c12
-rw-r--r--include/linux/nfs_page.h1
3 files changed, 29 insertions, 1 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 30c9626f96b0..4ec67f8d70aa 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -168,6 +168,23 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
168} 168}
169 169
170/* 170/*
171 * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it
172 * @req - a request in the group
173 *
174 * This is a blocking call to wait for the group lock to be cleared.
175 */
176void
177nfs_page_group_lock_wait(struct nfs_page *req)
178{
179 struct nfs_page *head = req->wb_head;
180
181 WARN_ON_ONCE(head != head->wb_head);
182
183 wait_on_bit(&head->wb_flags, PG_HEADLOCK,
184 TASK_UNINTERRUPTIBLE);
185}
186
187/*
171 * nfs_page_group_unlock - unlock the head of the page group 188 * nfs_page_group_unlock - unlock the head of the page group
172 * @req - request in group that is to be unlocked 189 * @req - request in group that is to be unlocked
173 */ 190 */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index e056f617adf2..175d5d073ccf 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -478,13 +478,23 @@ try_again:
478 return NULL; 478 return NULL;
479 } 479 }
480 480
481 /* lock each request in the page group */ 481 /* holding inode lock, so always make a non-blocking call to try the
482 * page group lock */
482 ret = nfs_page_group_lock(head, true); 483 ret = nfs_page_group_lock(head, true);
483 if (ret < 0) { 484 if (ret < 0) {
484 spin_unlock(&inode->i_lock); 485 spin_unlock(&inode->i_lock);
486
487 if (!nonblock && ret == -EAGAIN) {
488 nfs_page_group_lock_wait(head);
489 nfs_release_request(head);
490 goto try_again;
491 }
492
485 nfs_release_request(head); 493 nfs_release_request(head);
486 return ERR_PTR(ret); 494 return ERR_PTR(ret);
487 } 495 }
496
497 /* lock each request in the page group */
488 subreq = head; 498 subreq = head;
489 do { 499 do {
490 /* 500 /*
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 6ad2bbcad405..6c3e06ee2fb7 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -123,6 +123,7 @@ extern int nfs_wait_on_request(struct nfs_page *);
123extern void nfs_unlock_request(struct nfs_page *req); 123extern void nfs_unlock_request(struct nfs_page *req);
124extern void nfs_unlock_and_release_request(struct nfs_page *); 124extern void nfs_unlock_and_release_request(struct nfs_page *);
125extern int nfs_page_group_lock(struct nfs_page *, bool); 125extern int nfs_page_group_lock(struct nfs_page *, bool);
126extern void nfs_page_group_lock_wait(struct nfs_page *);
126extern void nfs_page_group_unlock(struct nfs_page *); 127extern void nfs_page_group_unlock(struct nfs_page *);
127extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); 128extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
128 129