mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 22:23:18 +00:00
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:
parent
93b717fd81
commit
abf4e13cc1
@ -875,15 +875,16 @@ int nfs_delegations_present(struct nfs_client *clp)
|
||||
|
||||
/**
|
||||
* nfs4_copy_delegation_stateid - Copy inode's state ID information
|
||||
* @dst: stateid data structure to fill in
|
||||
* @inode: inode to check
|
||||
* @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,
|
||||
* otherwise "false" is returned.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
@ -896,6 +897,8 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
|
||||
if (ret) {
|
||||
nfs4_stateid_copy(dst, &delegation->stateid);
|
||||
nfs_mark_delegation_referenced(delegation);
|
||||
if (cred)
|
||||
*cred = get_rpccred(delegation->cred);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
|
@ -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_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);
|
||||
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);
|
||||
int nfs4_have_delegation(struct inode *inode, fmode_t flags);
|
||||
|
@ -438,8 +438,9 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
|
||||
struct nfs41_server_scope **);
|
||||
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_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
|
||||
fmode_t, const struct nfs_lockowner *);
|
||||
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
|
||||
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 int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
|
||||
|
@ -2692,6 +2692,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
||||
.rpc_resp = &res,
|
||||
.rpc_cred = cred,
|
||||
};
|
||||
struct rpc_cred *delegation_cred = NULL;
|
||||
unsigned long timestamp = jiffies;
|
||||
fmode_t fmode;
|
||||
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;
|
||||
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 */
|
||||
} else if (truncate && state != NULL) {
|
||||
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))
|
||||
return -EBADF;
|
||||
if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
|
||||
&lockowner) == -EIO)
|
||||
if (nfs4_select_rw_stateid(state, FMODE_WRITE, &lockowner,
|
||||
&arg.stateid, &delegation_cred) == -EIO)
|
||||
return -EBADF;
|
||||
} else
|
||||
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);
|
||||
|
||||
put_rpccred(delegation_cred);
|
||||
if (status == 0 && state != NULL)
|
||||
renew_lease(server, timestamp);
|
||||
trace_nfs4_setattr(inode, &arg.stateid, status);
|
||||
@ -4301,7 +4306,7 @@ int nfs4_set_rw_stateid(nfs4_stateid *stateid,
|
||||
|
||||
if (l_ctx != NULL)
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
* requests.
|
||||
*/
|
||||
int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
|
||||
fmode_t fmode, const struct nfs_lockowner *lockowner)
|
||||
int nfs4_select_rw_stateid(struct nfs4_state *state,
|
||||
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)
|
||||
/* A lost lock - don't even consider delegations */
|
||||
goto out;
|
||||
/* 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;
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user