aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-12-04 12:09:45 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-12-04 12:32:19 -0500
commitf22e5edd2244609aed3906207a62223e7707a34d (patch)
treec11810758dfb6e4314e1945cc30c6187d9c5cd8a /fs
parentc297c8b99b07f496ff69a719cfb8e8fe852832ed (diff)
NFSv4.1: Prevent a 3-way deadlock between layoutreturn, open and state recovery
Andy Adamson reports: The state manager is recovering expired state and recovery OPENs are being processed. If kswapd is pruning inodes at the same time, a deadlock can occur when kswapd calls evict_inode on an NFSv4.1 inode with a layout, and the resultant layoutreturn gets an error that the state mangager is to handle, causing the layoutreturn to wait on the (NFS client) cl_rpcwaitq. At the same time an open is waiting for the inode deletion to complete in __wait_on_freeing_inode. If the open is either the open called by the state manager, or an open from the same open owner that is holding the NFSv4 sequence id which causes the OPEN from the state manager to wait for the sequence id on the Seqid_waitqueue, then the state is deadlocked with kswapd. The fix is simply to have layoutreturn ignore all errors except NFS4ERR_DELAY. We already know that layouts are dropped on all server reboots, and that it has to be coded to deal with the "forgetful client model" that doesn't send layoutreturns. Reported-by: Andy Adamson <andros@netapp.com> Link: http://lkml.kernel.org/r/1385402270-14284-1-git-send-email-andros@netapp.com Signed-off-by: Trond Myklebust <Trond.Myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4proc.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f01e2aa53210..e040359983ce 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7599,7 +7599,14 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
7599 return; 7599 return;
7600 7600
7601 server = NFS_SERVER(lrp->args.inode); 7601 server = NFS_SERVER(lrp->args.inode);
7602 if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { 7602 switch (task->tk_status) {
7603 default:
7604 task->tk_status = 0;
7605 case 0:
7606 break;
7607 case -NFS4ERR_DELAY:
7608 if (nfs4_async_handle_error(task, server, NULL) != -EAGAIN)
7609 break;
7603 rpc_restart_call_prepare(task); 7610 rpc_restart_call_prepare(task);
7604 return; 7611 return;
7605 } 7612 }