Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d65c520 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 16c29daf
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -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;
+3 −10
Original line number Original line Diff line number Diff line
@@ -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);
		if (nfs_have_delegation(inode, FMODE_WRITE))
		nfsi->change_attr++;
		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,10 +420,6 @@ 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);
		iput(inode);
	} else
	spin_unlock(&inode->i_lock);
	spin_unlock(&inode->i_lock);
	nfs_release_request(req);
	nfs_release_request(req);
}
}
+0 −1
Original line number Original line Diff line number Diff line
@@ -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);