Commit b85934f2 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] nfs: Fix a possible client deadlock

From: Trond Myklebust <trond.myklebust@fys.uio.no>

Fix a bug in the NFS write code whereby writepage() may end up deadlocking
on clear_inode().
parent 7aebcc3f
...@@ -228,8 +228,19 @@ nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -228,8 +228,19 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
unsigned long end_index; unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE; unsigned offset = PAGE_CACHE_SIZE;
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
int inode_referenced = 0;
int err; int err;
/*
* Note: We need to ensure that we have a reference to the inode
* if we are to do asynchronous writes. If not, waiting
* in nfs_wait_on_request() may deadlock with clear_inode().
*
* If igrab() fails here, then it is in any case safe to
* call nfs_wb_page(), since there will be no pending writes.
*/
if (igrab(inode) != 0)
inode_referenced = 1;
end_index = i_size >> PAGE_CACHE_SHIFT; end_index = i_size >> PAGE_CACHE_SHIFT;
/* Ensure we've flushed out any previous writes */ /* Ensure we've flushed out any previous writes */
...@@ -247,7 +258,8 @@ nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -247,7 +258,8 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
goto out; goto out;
do_it: do_it:
lock_kernel(); lock_kernel();
if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode)) { if (NFS_SERVER(inode)->wsize >= PAGE_CACHE_SIZE && !IS_SYNC(inode) &&
inode_referenced) {
err = nfs_writepage_async(NULL, inode, page, 0, offset); err = nfs_writepage_async(NULL, inode, page, 0, offset);
if (err >= 0) if (err >= 0)
err = 0; err = 0;
...@@ -259,6 +271,8 @@ nfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -259,6 +271,8 @@ nfs_writepage(struct page *page, struct writeback_control *wbc)
unlock_kernel(); unlock_kernel();
out: out:
unlock_page(page); unlock_page(page);
if (inode_referenced)
iput(inode);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment