aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-05-16 17:42:44 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-05-17 15:48:07 -0400
commitabf4e13cc1e16ed83ec8363d44f76149034b2851 (patch)
tree7b22583a6a05c09e1ca32f3bb3d4730a81fd50d9
parent93b717fd81bf6b9a73c3702e9b079b4de8148b34 (diff)
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>
-rw-r--r--fs/nfs/delegation.c9
-rw-r--r--fs/nfs/delegation.h2
-rw-r--r--fs/nfs/nfs4_fs.h5
-rw-r--r--fs/nfs/nfs4proc.c13
-rw-r--r--fs/nfs/nfs4state.c13
5 files changed, 28 insertions, 14 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 5166adcfc0fb..322c2585bc34 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -875,15 +875,16 @@ int nfs_delegations_present(struct nfs_client *clp)
875 875
876/** 876/**
877 * nfs4_copy_delegation_stateid - Copy inode's state ID information 877 * nfs4_copy_delegation_stateid - Copy inode's state ID information
878 * @dst: stateid data structure to fill in
879 * @inode: inode to check 878 * @inode: inode to check
880 * @flags: delegation type requirement 879 * @flags: delegation type requirement
880 * @dst: stateid data structure to fill in
881 * @cred: optional argument to retrieve credential
881 * 882 *
882 * Returns "true" and fills in "dst->data" * if inode had a delegation, 883 * Returns "true" and fills in "dst->data" * if inode had a delegation,
883 * otherwise "false" is returned. 884 * otherwise "false" is returned.
884 */ 885 */
885bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, 886bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
886 fmode_t flags) 887 nfs4_stateid *dst, struct rpc_cred **cred)
887{ 888{
888 struct nfs_inode *nfsi = NFS_I(inode); 889 struct nfs_inode *nfsi = NFS_I(inode);
889 struct nfs_delegation *delegation; 890 struct nfs_delegation *delegation;
@@ -896,6 +897,8 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
896 if (ret) { 897 if (ret) {
897 nfs4_stateid_copy(dst, &delegation->stateid); 898 nfs4_stateid_copy(dst, &delegation->stateid);
898 nfs_mark_delegation_referenced(delegation); 899 nfs_mark_delegation_referenced(delegation);
900 if (cred)
901 *cred = get_rpccred(delegation->cred);
899 } 902 }
900 rcu_read_unlock(); 903 rcu_read_unlock();
901 return ret; 904 return ret;
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 333063e032f0..64724d252a79 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -56,7 +56,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
56int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); 56int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
57int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type); 57int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
58int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid); 58int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
59bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); 59bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred);
60 60
61void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); 61void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
62int nfs4_have_delegation(struct inode *inode, fmode_t flags); 62int nfs4_have_delegation(struct inode *inode, fmode_t flags);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index b5d9f345c9f2..768456fa1b17 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -438,8 +438,9 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
438 struct nfs41_server_scope **); 438 struct nfs41_server_scope **);
439extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); 439extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
440extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); 440extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
441extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, 441extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
442 fmode_t, const struct nfs_lockowner *); 442 const struct nfs_lockowner *, nfs4_stateid *,
443 struct rpc_cred **);
443 444
444extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); 445extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
445extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); 446extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2516467ff17f..c9b66085d392 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2692,6 +2692,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2692 .rpc_resp = &res, 2692 .rpc_resp = &res,
2693 .rpc_cred = cred, 2693 .rpc_cred = cred,
2694 }; 2694 };
2695 struct rpc_cred *delegation_cred = NULL;
2695 unsigned long timestamp = jiffies; 2696 unsigned long timestamp = jiffies;
2696 fmode_t fmode; 2697 fmode_t fmode;
2697 bool truncate; 2698 bool truncate;
@@ -2707,7 +2708,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2707 truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false; 2708 truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
2708 fmode = truncate ? FMODE_WRITE : FMODE_READ; 2709 fmode = truncate ? FMODE_WRITE : FMODE_READ;
2709 2710
2710 if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) { 2711 if (nfs4_copy_delegation_stateid(inode, fmode, &arg.stateid, &delegation_cred)) {
2711 /* Use that stateid */ 2712 /* Use that stateid */
2712 } else if (truncate && state != NULL) { 2713 } else if (truncate && state != NULL) {
2713 struct nfs_lockowner lockowner = { 2714 struct nfs_lockowner lockowner = {
@@ -2716,13 +2717,17 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2716 }; 2717 };
2717 if (!nfs4_valid_open_stateid(state)) 2718 if (!nfs4_valid_open_stateid(state))
2718 return -EBADF; 2719 return -EBADF;
2719 if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, 2720 if (nfs4_select_rw_stateid(state, FMODE_WRITE, &lockowner,
2720 &lockowner) == -EIO) 2721 &arg.stateid, &delegation_cred) == -EIO)
2721 return -EBADF; 2722 return -EBADF;
2722 } else 2723 } else
2723 nfs4_stateid_copy(&arg.stateid, &zero_stateid); 2724 nfs4_stateid_copy(&arg.stateid, &zero_stateid);
2725 if (delegation_cred)
2726 msg.rpc_cred = delegation_cred;
2724 2727
2725 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 2728 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
2729
2730 put_rpccred(delegation_cred);
2726 if (status == 0 && state != NULL) 2731 if (status == 0 && state != NULL)
2727 renew_lease(server, timestamp); 2732 renew_lease(server, timestamp);
2728 trace_nfs4_setattr(inode, &arg.stateid, status); 2733 trace_nfs4_setattr(inode, &arg.stateid, status);
@@ -4301,7 +4306,7 @@ int nfs4_set_rw_stateid(nfs4_stateid *stateid,
4301 4306
4302 if (l_ctx != NULL) 4307 if (l_ctx != NULL)
4303 lockowner = &l_ctx->lockowner; 4308 lockowner = &l_ctx->lockowner;
4304 return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner); 4309 return nfs4_select_rw_stateid(ctx->state, fmode, lockowner, stateid, NULL);
4305} 4310}
4306EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); 4311EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
4307 4312
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index d630f9cca0f1..5075592df145 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -988,15 +988,20 @@ static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
988 * Byte-range lock aware utility to initialize the stateid of read/write 988 * Byte-range lock aware utility to initialize the stateid of read/write
989 * requests. 989 * requests.
990 */ 990 */
991int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, 991int nfs4_select_rw_stateid(struct nfs4_state *state,
992 fmode_t fmode, const struct nfs_lockowner *lockowner) 992 fmode_t fmode, const struct nfs_lockowner *lockowner,
993 nfs4_stateid *dst, struct rpc_cred **cred)
993{ 994{
994 int ret = nfs4_copy_lock_stateid(dst, state, lockowner); 995 int ret;
996
997 if (cred != NULL)
998 *cred = NULL;
999 ret = nfs4_copy_lock_stateid(dst, state, lockowner);
995 if (ret == -EIO) 1000 if (ret == -EIO)
996 /* A lost lock - don't even consider delegations */ 1001 /* A lost lock - don't even consider delegations */
997 goto out; 1002 goto out;
998 /* returns true if delegation stateid found and copied */ 1003 /* returns true if delegation stateid found and copied */
999 if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) { 1004 if (nfs4_copy_delegation_stateid(state->inode, fmode, dst, cred)) {
1000 ret = 0; 1005 ret = 0;
1001 goto out; 1006 goto out;
1002 } 1007 }