diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-05-16 17:42:44 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2016-05-17 15:48:07 -0400 |
commit | abf4e13cc1e16ed83ec8363d44f76149034b2851 (patch) | |
tree | 7b22583a6a05c09e1ca32f3bb3d4730a81fd50d9 | |
parent | 93b717fd81bf6b9a73c3702e9b079b4de8148b34 (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.c | 9 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 13 |
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 | */ |
885 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, | 886 | bool 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); | |||
56 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); | 56 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); |
57 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type); | 57 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type); |
58 | int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid); | 58 | int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid); |
59 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); | 59 | bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred); |
60 | 60 | ||
61 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); | 61 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
62 | int nfs4_have_delegation(struct inode *inode, fmode_t flags); | 62 | int 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 **); |
439 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 439 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
440 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 440 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
441 | extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, | 441 | extern 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 | ||
444 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); | 445 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
445 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 446 | extern 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 | } |
4306 | EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); | 4311 | EXPORT_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 | */ |
991 | int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | 991 | int 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 | } |