NFS: Fix a hang in the writeback path
Now that the inode scalability patches have been merged, it is no longer safe to call igrab() under the inode->i_lock. Now that we no longer call nfs_clear_request() until the nfs_page is being freed, we know that we are always holding a reference to the nfs_open_context, which again holds a reference to the path, and so the inode cannot be freed until the last nfs_page has been removed from the radix tree and freed. We can therefore skip the igrab()/iput() altogether. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
16c29dafcc
commit
4d65c520fb
|
@ -135,14 +135,14 @@ void nfs_clear_page_tag_locked(struct nfs_page *req)
|
||||||
nfs_unlock_request(req);
|
nfs_unlock_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* nfs_clear_request - Free up all resources allocated to the request
|
* nfs_clear_request - Free up all resources allocated to the request
|
||||||
* @req:
|
* @req:
|
||||||
*
|
*
|
||||||
* Release page and open context resources associated with a read/write
|
* Release page and open context resources associated with a read/write
|
||||||
* request after it has completed.
|
* request after it has completed.
|
||||||
*/
|
*/
|
||||||
void nfs_clear_request(struct nfs_page *req)
|
static void nfs_clear_request(struct nfs_page *req)
|
||||||
{
|
{
|
||||||
struct page *page = req->wb_page;
|
struct page *page = req->wb_page;
|
||||||
struct nfs_open_context *ctx = req->wb_context;
|
struct nfs_open_context *ctx = req->wb_context;
|
||||||
|
|
|
@ -389,11 +389,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
|
error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
|
||||||
BUG_ON(error);
|
BUG_ON(error);
|
||||||
if (!nfsi->npages) {
|
if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
|
||||||
igrab(inode);
|
nfsi->change_attr++;
|
||||||
if (nfs_have_delegation(inode, FMODE_WRITE))
|
|
||||||
nfsi->change_attr++;
|
|
||||||
}
|
|
||||||
set_bit(PG_MAPPED, &req->wb_flags);
|
set_bit(PG_MAPPED, &req->wb_flags);
|
||||||
SetPagePrivate(req->wb_page);
|
SetPagePrivate(req->wb_page);
|
||||||
set_page_private(req->wb_page, (unsigned long)req);
|
set_page_private(req->wb_page, (unsigned long)req);
|
||||||
|
@ -423,11 +420,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
||||||
clear_bit(PG_MAPPED, &req->wb_flags);
|
clear_bit(PG_MAPPED, &req->wb_flags);
|
||||||
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
|
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
|
||||||
nfsi->npages--;
|
nfsi->npages--;
|
||||||
if (!nfsi->npages) {
|
spin_unlock(&inode->i_lock);
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
iput(inode);
|
|
||||||
} else
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
nfs_release_request(req);
|
nfs_release_request(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
|
||||||
struct page *page,
|
struct page *page,
|
||||||
unsigned int offset,
|
unsigned int offset,
|
||||||
unsigned int count);
|
unsigned int count);
|
||||||
extern void nfs_clear_request(struct nfs_page *req);
|
|
||||||
extern void nfs_release_request(struct nfs_page *req);
|
extern void nfs_release_request(struct nfs_page *req);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue