From: Trond Myklebust Fix a bug in the NFS write code whereby writepage() may end up deadlocking on clear_inode(). --- fs/nfs/write.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletion(-) diff -puN fs/nfs/write.c~nfs-client-deadlock-fix fs/nfs/write.c --- 25/fs/nfs/write.c~nfs-client-deadlock-fix 2004-01-08 18:38:45.000000000 -0800 +++ 25-akpm/fs/nfs/write.c 2004-01-08 18:38:45.000000000 -0800 @@ -228,8 +228,19 @@ nfs_writepage(struct page *page, struct unsigned long end_index; unsigned offset = PAGE_CACHE_SIZE; loff_t i_size = i_size_read(inode); + int inode_referenced = 0; 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; /* Ensure we've flushed out any previous writes */ @@ -247,7 +258,8 @@ nfs_writepage(struct page *page, struct goto out; do_it: 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); if (err >= 0) err = 0; @@ -259,6 +271,8 @@ do_it: unlock_kernel(); out: unlock_page(page); + if (inode_referenced) + iput(inode); return err; } _