From 274a1dc919c8dc46e4517cee0e7e92e746bf16e7 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Mon, 15 Sep 2014 14:14:43 -0400 Subject: nfs: don't sleep with inode lock in lock_and_join_requests commit 7c3af975257383ece54b83c0505d3e0656cb7daf upstream. 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 Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pagelist.c | 18 ++++++++++++++++++ fs/nfs/write.c | 12 +++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'fs/nfs') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ab96711d518f..f56b6351b660 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -174,6 +174,24 @@ 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, + nfs_wait_bit_uninterruptible, + TASK_UNINTERRUPTIBLE); +} + /* * nfs_page_group_unlock - unlock the head of the page group * @req - request in group that is to be unlocked diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 014d23c7d16e..ecb0f9fd5632 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -453,13 +453,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 { /* -- cgit v1.2.3