diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-11-15 22:56:07 +0300 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-12-02 01:21:46 +0300 |
commit | cf80516579ceb87b91205e68fb31d5affd5aea8d (patch) | |
tree | ed88119568a2fd6aea6d05dc1250a2651268c1b6 /fs/nfs/nfs4proc.c | |
parent | d8434d4c54789bd8ac30b4a69037115b3594d2b3 (diff) | |
download | linux-cf80516579ceb87b91205e68fb31d5affd5aea8d.tar.xz |
NFSv4: Add encode/decode of the layoutreturn op in CLOSE
Add XDR encoding for the layoutreturn op, and storage for the layoutreturn
arguments to the CLOSE compound.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 87972cfa62bc..9b9b0eabef9b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3035,10 +3035,14 @@ struct nfs4_closedata { struct nfs4_state *state; struct nfs_closeargs arg; struct nfs_closeres res; + struct { + struct nfs4_layoutreturn_args arg; + struct nfs4_layoutreturn_res res; + u32 roc_barrier; + bool roc; + } lr; struct nfs_fattr fattr; unsigned long timestamp; - bool roc; - u32 roc_barrier; }; static void nfs4_free_closedata(void *data) @@ -3047,7 +3051,7 @@ static void nfs4_free_closedata(void *data) struct nfs4_state_owner *sp = calldata->state->owner; struct super_block *sb = calldata->state->inode->i_sb; - if (calldata->roc) + if (calldata->lr.roc) pnfs_roc_release(calldata->state->inode); nfs4_put_open_state(calldata->state); nfs_free_seqid(calldata->arg.seqid); @@ -3067,15 +3071,41 @@ static void nfs4_close_done(struct rpc_task *task, void *data) if (!nfs4_sequence_done(task, &calldata->res.seq_res)) return; trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status); + + /* Handle Layoutreturn errors */ + if (calldata->arg.lr_args && task->tk_status != 0) { + switch (calldata->res.lr_ret) { + default: + calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT; + break; + case 0: + calldata->arg.lr_args = NULL; + calldata->res.lr_res = NULL; + break; + case -NFS4ERR_ADMIN_REVOKED: + case -NFS4ERR_DELEG_REVOKED: + case -NFS4ERR_EXPIRED: + case -NFS4ERR_BAD_STATEID: + case -NFS4ERR_OLD_STATEID: + case -NFS4ERR_UNKNOWN_LAYOUTTYPE: + case -NFS4ERR_WRONG_CRED: + calldata->arg.lr_args = NULL; + calldata->res.lr_res = NULL; + calldata->res.lr_ret = 0; + rpc_restart_call_prepare(task); + return; + } + } + /* hmm. we are done with the inode, and in the process of freeing * the state_owner. we keep this around to process errors */ switch (task->tk_status) { case 0: res_stateid = &calldata->res.stateid; - if (calldata->roc) + if (calldata->lr.roc) pnfs_roc_set_barrier(state->inode, - calldata->roc_barrier); + calldata->lr.roc_barrier); renew_lease(server, calldata->timestamp); break; case -NFS4ERR_ADMIN_REVOKED: @@ -3151,7 +3181,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) goto out_no_action; } - if (nfs4_wait_on_layoutreturn(inode, task)) { + if (!calldata->arg.lr_args && nfs4_wait_on_layoutreturn(inode, task)) { nfs_release_seqid(calldata->arg.seqid); goto out_wait; } @@ -3165,8 +3195,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) else calldata->arg.bitmask = NULL; } - if (calldata->roc) - pnfs_roc_get_barrier(inode, &calldata->roc_barrier); + if (calldata->lr.roc) + pnfs_roc_get_barrier(inode, &calldata->lr.roc_barrier); calldata->arg.share_access = nfs4_map_atomic_open_share(NFS_SERVER(inode), @@ -3250,7 +3280,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) calldata->res.fattr = &calldata->fattr; calldata->res.seqid = calldata->arg.seqid; calldata->res.server = server; - calldata->roc = nfs4_roc(state->inode); + calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT; + calldata->lr.roc = nfs4_roc(state->inode); nfs_sb_active(calldata->inode->i_sb); msg.rpc_argp = &calldata->arg; |