NFS: Fix a hang in the writeback path
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 25 Mar 2011 18:15:11 +0000 (14:15 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sun, 27 Mar 2011 15:48:07 +0000 (17:48 +0200)
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>
fs/nfs/pagelist.c
fs/nfs/write.c
include/linux/nfs_page.h

index 87a593c2b055503e727c2cda93a396ecb2681fb5..c80add6e2213ab6d4f301a2ca06134b4a4f5581c 100644 (file)
@@ -135,14 +135,14 @@ void nfs_clear_page_tag_locked(struct nfs_page *req)
                nfs_unlock_request(req);
 }
 
-/**
+/*
  * nfs_clear_request - Free up all resources allocated to the request
  * @req:
  *
  * Release page and open context resources associated with a read/write
  * 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 nfs_open_context *ctx = req->wb_context;
index 85d75254328ebd1c822187e51a3f5b5e9fc320b7..af0c6279a4a7c131cd9c2a80e0764ba8ea50a6c9 100644 (file)
@@ -389,11 +389,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
        spin_lock(&inode->i_lock);
        error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
        BUG_ON(error);
-       if (!nfsi->npages) {
-               igrab(inode);
-               if (nfs_have_delegation(inode, FMODE_WRITE))
-                       nfsi->change_attr++;
-       }
+       if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
+               nfsi->change_attr++;
        set_bit(PG_MAPPED, &req->wb_flags);
        SetPagePrivate(req->wb_page);
        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);
        radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
        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);
 }
 
index 8023e4e25133cbcebbbd97b85c33df1943d34e13..91af2e49fa3ab1a532bdc22143da19021f0248da 100644 (file)
@@ -78,7 +78,6 @@ extern        struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
                                            struct page *page,
                                            unsigned int offset,
                                            unsigned int count);
-extern void nfs_clear_request(struct nfs_page *req);
 extern void nfs_release_request(struct nfs_page *req);