Explorar el Código

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>
Trond Myklebust hace 14 años
padre
commit
4d65c520fb
Se han modificado 3 ficheros con 5 adiciones y 13 borrados
  1. 2 2
      fs/nfs/pagelist.c
  2. 3 10
      fs/nfs/write.c
  3. 0 1
      include/linux/nfs_page.h

+ 2 - 2
fs/nfs/pagelist.c

@@ -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
fs/nfs/write.c

@@ -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) {
-		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);
 	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);
-		iput(inode);
-	} else
-		spin_unlock(&inode->i_lock);
+	spin_unlock(&inode->i_lock);
 	nfs_release_request(req);
 	nfs_release_request(req);
 }
 }
 
 

+ 0 - 1
include/linux/nfs_page.h

@@ -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);