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>

+5 -13
+2 -2
fs/nfs/pagelist.c
··· 135 nfs_unlock_request(req); 136 } 137 138 - /** 139 * nfs_clear_request - Free up all resources allocated to the request 140 * @req: 141 * 142 * Release page and open context resources associated with a read/write 143 * request after it has completed. 144 */ 145 - void nfs_clear_request(struct nfs_page *req) 146 { 147 struct page *page = req->wb_page; 148 struct nfs_open_context *ctx = req->wb_context;
··· 135 nfs_unlock_request(req); 136 } 137 138 + /* 139 * nfs_clear_request - Free up all resources allocated to the request 140 * @req: 141 * 142 * Release page and open context resources associated with a read/write 143 * request after it has completed. 144 */ 145 + static void nfs_clear_request(struct nfs_page *req) 146 { 147 struct page *page = req->wb_page; 148 struct nfs_open_context *ctx = req->wb_context;
+3 -10
fs/nfs/write.c
··· 389 spin_lock(&inode->i_lock); 390 error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); 391 BUG_ON(error); 392 - if (!nfsi->npages) { 393 - igrab(inode); 394 - if (nfs_have_delegation(inode, FMODE_WRITE)) 395 - nfsi->change_attr++; 396 - } 397 set_bit(PG_MAPPED, &req->wb_flags); 398 SetPagePrivate(req->wb_page); 399 set_page_private(req->wb_page, (unsigned long)req); ··· 420 clear_bit(PG_MAPPED, &req->wb_flags); 421 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); 422 nfsi->npages--; 423 - if (!nfsi->npages) { 424 - spin_unlock(&inode->i_lock); 425 - iput(inode); 426 - } else 427 - spin_unlock(&inode->i_lock); 428 nfs_release_request(req); 429 } 430
··· 389 spin_lock(&inode->i_lock); 390 error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); 391 BUG_ON(error); 392 + if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) 393 + nfsi->change_attr++; 394 set_bit(PG_MAPPED, &req->wb_flags); 395 SetPagePrivate(req->wb_page); 396 set_page_private(req->wb_page, (unsigned long)req); ··· 423 clear_bit(PG_MAPPED, &req->wb_flags); 424 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); 425 nfsi->npages--; 426 + spin_unlock(&inode->i_lock); 427 nfs_release_request(req); 428 } 429
-1
include/linux/nfs_page.h
··· 78 struct page *page, 79 unsigned int offset, 80 unsigned int count); 81 - extern void nfs_clear_request(struct nfs_page *req); 82 extern void nfs_release_request(struct nfs_page *req); 83 84
··· 78 struct page *page, 79 unsigned int offset, 80 unsigned int count); 81 extern void nfs_release_request(struct nfs_page *req); 82 83