Commit 274a1dc9 authored by Weston Andros Adamson's avatar Weston Andros Adamson Committed by Greg Kroah-Hartman

nfs: don't sleep with inode lock in lock_and_join_requests

commit 7c3af975 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: default avatarFengguang Wu <fengguang.wu@intel.com>
Signed-off-by: default avatarWeston Andros Adamson <dros@primarydata.com>
Reviewed-by: default avatarPeng Tao <tao.peng@primarydata.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ae3f3485
...@@ -174,6 +174,24 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock) ...@@ -174,6 +174,24 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
return -EAGAIN; 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 * nfs_page_group_unlock - unlock the head of the page group
* @req - request in group that is to be unlocked * @req - request in group that is to be unlocked
......
...@@ -453,13 +453,23 @@ nfs_lock_and_join_requests(struct page *page, bool nonblock) ...@@ -453,13 +453,23 @@ nfs_lock_and_join_requests(struct page *page, bool nonblock)
return NULL; 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); ret = nfs_page_group_lock(head, true);
if (ret < 0) { if (ret < 0) {
spin_unlock(&inode->i_lock); 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); nfs_release_request(head);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/* lock each request in the page group */
subreq = head; subreq = head;
do { do {
/* /*
......
...@@ -121,6 +121,7 @@ extern int nfs_wait_on_request(struct nfs_page *); ...@@ -121,6 +121,7 @@ extern int nfs_wait_on_request(struct nfs_page *);
extern void nfs_unlock_request(struct nfs_page *req); extern void nfs_unlock_request(struct nfs_page *req);
extern void nfs_unlock_and_release_request(struct nfs_page *); extern void nfs_unlock_and_release_request(struct nfs_page *);
extern int nfs_page_group_lock(struct nfs_page *, bool); 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 void nfs_page_group_unlock(struct nfs_page *);
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment