aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-09-22 13:38:54 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-09-27 14:32:31 -0400
commitaa05c87f23efe417adc7ff9b4193b7201ec0dd79 (patch)
tree27e8f8c28d1c68d51fbeb282ee970eb85496fb14 /fs/nfs
parentb3f9e7239074613aa6bdafa4caf7c104fe1e7276 (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.c17
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
44static bool
45nfs4_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
44static int 55static int
45nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) 56nfs4_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);