NFSv4: Use the right stateid for delegations in setattr, read and write

When we're using a delegation to represent our open state, we should
ensure that we use the stateid that was used to create that delegation.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
Trond Myklebust 2016-05-16 17:42:44 -04:00 committed by Anna Schumaker
parent 93b717fd81
commit abf4e13cc1
5 changed files with 28 additions and 14 deletions

View File

@ -875,15 +875,16 @@ int nfs_delegations_present(struct nfs_client *clp)
/** /**
* nfs4_copy_delegation_stateid - Copy inode's state ID information * nfs4_copy_delegation_stateid - Copy inode's state ID information
* @dst: stateid data structure to fill in
* @inode: inode to check * @inode: inode to check
* @flags: delegation type requirement * @flags: delegation type requirement
* @dst: stateid data structure to fill in
* @cred: optional argument to retrieve credential
* *
* Returns "true" and fills in "dst->data" * if inode had a delegation, * Returns "true" and fills in "dst->data" * if inode had a delegation,
* otherwise "false" is returned. * otherwise "false" is returned.
*/ */
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
fmode_t flags) nfs4_stateid *dst, struct rpc_cred **cred)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
@ -896,6 +897,8 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
if (ret) { if (ret) {
nfs4_stateid_copy(dst, &delegation->stateid); nfs4_stateid_copy(dst, &delegation->stateid);
nfs_mark_delegation_referenced(delegation); nfs_mark_delegation_referenced(delegation);
if (cred)
*cred = get_rpccred(delegation->cred);
} }
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;

View File

@ -56,7 +56,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type); int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid); int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred);
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
int nfs4_have_delegation(struct inode *inode, fmode_t flags); int nfs4_have_delegation(struct inode *inode, fmode_t flags);

View File

@ -438,8 +438,9 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
struct nfs41_server_scope **); struct nfs41_server_scope **);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
fmode_t, const struct nfs_lockowner *); const struct nfs_lockowner *, nfs4_stateid *,
struct rpc_cred **);
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);

View File

@ -2692,6 +2692,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
.rpc_resp = &res, .rpc_resp = &res,
.rpc_cred = cred, .rpc_cred = cred,
}; };
struct rpc_cred *delegation_cred = NULL;
unsigned long timestamp = jiffies; unsigned long timestamp = jiffies;
fmode_t fmode; fmode_t fmode;
bool truncate; bool truncate;
@ -2707,7 +2708,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false; truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
fmode = truncate ? FMODE_WRITE : FMODE_READ; fmode = truncate ? FMODE_WRITE : FMODE_READ;
if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) { if (nfs4_copy_delegation_stateid(inode, fmode, &arg.stateid, &delegation_cred)) {
/* Use that stateid */ /* Use that stateid */
} else if (truncate && state != NULL) { } else if (truncate && state != NULL) {
struct nfs_lockowner lockowner = { struct nfs_lockowner lockowner = {
@ -2716,13 +2717,17 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
}; };
if (!nfs4_valid_open_stateid(state)) if (!nfs4_valid_open_stateid(state))
return -EBADF; return -EBADF;
if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, if (nfs4_select_rw_stateid(state, FMODE_WRITE, &lockowner,
&lockowner) == -EIO) &arg.stateid, &delegation_cred) == -EIO)
return -EBADF; return -EBADF;
} else } else
nfs4_stateid_copy(&arg.stateid, &zero_stateid); nfs4_stateid_copy(&arg.stateid, &zero_stateid);
if (delegation_cred)
msg.rpc_cred = delegation_cred;
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
put_rpccred(delegation_cred);
if (status == 0 && state != NULL) if (status == 0 && state != NULL)
renew_lease(server, timestamp); renew_lease(server, timestamp);
trace_nfs4_setattr(inode, &arg.stateid, status); trace_nfs4_setattr(inode, &arg.stateid, status);
@ -4301,7 +4306,7 @@ int nfs4_set_rw_stateid(nfs4_stateid *stateid,
if (l_ctx != NULL) if (l_ctx != NULL)
lockowner = &l_ctx->lockowner; lockowner = &l_ctx->lockowner;
return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner); return nfs4_select_rw_stateid(ctx->state, fmode, lockowner, stateid, NULL);
} }
EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);

View File

@ -988,15 +988,20 @@ static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
* Byte-range lock aware utility to initialize the stateid of read/write * Byte-range lock aware utility to initialize the stateid of read/write
* requests. * requests.
*/ */
int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, int nfs4_select_rw_stateid(struct nfs4_state *state,
fmode_t fmode, const struct nfs_lockowner *lockowner) fmode_t fmode, const struct nfs_lockowner *lockowner,
nfs4_stateid *dst, struct rpc_cred **cred)
{ {
int ret = nfs4_copy_lock_stateid(dst, state, lockowner); int ret;
if (cred != NULL)
*cred = NULL;
ret = nfs4_copy_lock_stateid(dst, state, lockowner);
if (ret == -EIO) if (ret == -EIO)
/* A lost lock - don't even consider delegations */ /* A lost lock - don't even consider delegations */
goto out; goto out;
/* returns true if delegation stateid found and copied */ /* returns true if delegation stateid found and copied */
if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) { if (nfs4_copy_delegation_stateid(state->inode, fmode, dst, cred)) {
ret = 0; ret = 0;
goto out; goto out;
} }