aboutsummaryrefslogtreecommitdiff
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorPeng Tao2015-09-22 11:35:22 +0800
committerTrond Myklebust2015-09-23 08:55:32 -0400
commit500d701f336b2771d34e46da7875a4782515a652 (patch)
tree217881fc9e1b5cc45f1f2b4042c6a161f84aebd0 /fs/nfs/nfs4proc.c
parent834e465bba38f2768747bccb5f00e951e72d2bf5 (diff)
NFS41: make close wait for layoutreturn
If we send a layoutreturn asynchronously before close, the close might reach server first and layoutreturn would fail with BADSTATEID because there is nothing keeping the layout stateid alive. Also do not pretend sending layoutreturn if we are not. Signed-off-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ef6b46e08ac6..f93b9cdb4934 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2658,6 +2658,15 @@ out:
return err;
}
+static bool
+nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
+{
+ if (inode == NULL || !nfs_have_layout(inode))
+ return false;
+
+ return pnfs_wait_on_layoutreturn(inode, task);
+}
+
struct nfs4_closedata {
struct inode *inode;
struct nfs4_state *state;
@@ -2776,6 +2785,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
goto out_no_action;
}
+ if (nfs4_wait_on_layoutreturn(inode, task)) {
+ nfs_release_seqid(calldata->arg.seqid);
+ goto out_wait;
+ }
+
if (calldata->arg.fmode == 0)
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
if (calldata->roc)
@@ -5321,6 +5335,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
d_data = (struct nfs4_delegreturndata *)data;
+ if (nfs4_wait_on_layoutreturn(d_data->inode, task))
+ return;
+
if (d_data->roc)
pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier);