diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-25 14:15:11 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-27 11:48:07 -0400 |
commit | 4d65c520fb4abed970069d18c119cfe85624f46d (patch) | |
tree | 74671eb263380317f1e4a958a6a7f73749e98eec /fs/nfs/write.c | |
parent | 16c29dafcc86024048f1dbb8349d31cb22c7c55a (diff) |
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>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 13 |
1 files changed, 3 insertions, 10 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 85d75254328e..af0c6279a4a7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -389,11 +389,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
389 | spin_lock(&inode->i_lock); | 389 | spin_lock(&inode->i_lock); |
390 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 390 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
391 | BUG_ON(error); | 391 | BUG_ON(error); |
392 | if (!nfsi->npages) { | 392 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) |
393 | igrab(inode); | 393 | nfsi->change_attr++; |
394 | if (nfs_have_delegation(inode, FMODE_WRITE)) | ||
395 | nfsi->change_attr++; | ||
396 | } | ||
397 | set_bit(PG_MAPPED, &req->wb_flags); | 394 | set_bit(PG_MAPPED, &req->wb_flags); |
398 | SetPagePrivate(req->wb_page); | 395 | SetPagePrivate(req->wb_page); |
399 | set_page_private(req->wb_page, (unsigned long)req); | 396 | set_page_private(req->wb_page, (unsigned long)req); |
@@ -423,11 +420,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
423 | clear_bit(PG_MAPPED, &req->wb_flags); | 420 | clear_bit(PG_MAPPED, &req->wb_flags); |
424 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 421 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
425 | nfsi->npages--; | 422 | nfsi->npages--; |
426 | if (!nfsi->npages) { | 423 | spin_unlock(&inode->i_lock); |
427 | spin_unlock(&inode->i_lock); | ||
428 | iput(inode); | ||
429 | } else | ||
430 | spin_unlock(&inode->i_lock); | ||
431 | nfs_release_request(req); | 424 | nfs_release_request(req); |
432 | } | 425 | } |
433 | 426 | ||