diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-09-22 13:38:54 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2016-09-27 14:32:31 -0400 |
commit | aa05c87f23efe417adc7ff9b4193b7201ec0dd79 (patch) | |
tree | 27e8f8c28d1c68d51fbeb282ee970eb85496fb14 /fs/nfs | |
parent | b3f9e7239074613aa6bdafa4caf7c104fe1e7276 (diff) |
NFSv4: nfs4_copy_delegation_stateid() must fail if the delegation is invalid
We must not allow the use of delegations that have been revoked or are
being returned.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Fixes: 869f9dfa4d6d ("NFSv4: Fix races between nfs_remove_bad_delegation()...")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org # v3.19+
Tested-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/delegation.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 86d2c748140b..b9c65421ed81 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -41,6 +41,17 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | |||
41 | set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); | 41 | set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); |
42 | } | 42 | } |
43 | 43 | ||
44 | static bool | ||
45 | nfs4_is_valid_delegation(const struct nfs_delegation *delegation, | ||
46 | fmode_t flags) | ||
47 | { | ||
48 | if (delegation != NULL && (delegation->type & flags) == flags && | ||
49 | !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) && | ||
50 | !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) | ||
51 | return true; | ||
52 | return false; | ||
53 | } | ||
54 | |||
44 | static int | 55 | static int |
45 | nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) | 56 | nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) |
46 | { | 57 | { |
@@ -50,9 +61,7 @@ nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) | |||
50 | flags &= FMODE_READ|FMODE_WRITE; | 61 | flags &= FMODE_READ|FMODE_WRITE; |
51 | rcu_read_lock(); | 62 | rcu_read_lock(); |
52 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 63 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
53 | if (delegation != NULL && (delegation->type & flags) == flags && | 64 | if (nfs4_is_valid_delegation(delegation, flags)) { |
54 | !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) && | ||
55 | !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { | ||
56 | if (mark) | 65 | if (mark) |
57 | nfs_mark_delegation_referenced(delegation); | 66 | nfs_mark_delegation_referenced(delegation); |
58 | ret = 1; | 67 | ret = 1; |
@@ -894,7 +903,7 @@ bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, | |||
894 | flags &= FMODE_READ|FMODE_WRITE; | 903 | flags &= FMODE_READ|FMODE_WRITE; |
895 | rcu_read_lock(); | 904 | rcu_read_lock(); |
896 | delegation = rcu_dereference(nfsi->delegation); | 905 | delegation = rcu_dereference(nfsi->delegation); |
897 | ret = (delegation != NULL && (delegation->type & flags) == flags); | 906 | ret = nfs4_is_valid_delegation(delegation, flags); |
898 | if (ret) { | 907 | if (ret) { |
899 | nfs4_stateid_copy(dst, &delegation->stateid); | 908 | nfs4_stateid_copy(dst, &delegation->stateid); |
900 | nfs_mark_delegation_referenced(delegation); | 909 | nfs_mark_delegation_referenced(delegation); |