NFSv4: Don't allow a cached open with a revoked delegation
authorTrond Myklebust <trondmy@gmail.com>
Thu, 31 Oct 2019 22:40:32 +0000 (18:40 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Nov 2019 18:16:06 +0000 (19:16 +0100)
[ Upstream commit be3df3dd4c70ee020587a943a31b98a0fb4b6424 ]

If the delegation is marked as being revoked, we must not use it
for cached opens.

Fixes: 869f9dfa4d6d ("NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/nfs4proc.c

index dff600ae0d7477333a3e41749cffe58ad77c7e3a..46afd7cdcc378b93e9ce678bb6ad7c5ca32474e9 100644 (file)
@@ -52,6 +52,16 @@ nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
        return false;
 }
 
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode)
+{
+       struct nfs_delegation *delegation;
+
+       delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (nfs4_is_valid_delegation(delegation, 0))
+               return delegation;
+       return NULL;
+}
+
 static int
 nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
 {
index e9d55579687393552b0d83c46dfcafc56dbace89..2c6cb7fb7d5ee1c4c288d1486e782b028b15184b 100644 (file)
@@ -62,6 +62,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
 int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
 bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred);
 
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode);
 void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
 int nfs4_have_delegation(struct inode *inode, fmode_t flags);
 int nfs4_check_delegation(struct inode *inode, fmode_t flags);
index 8354dfae7038e53bb1f456d43b056f5036cf8754..ca4249ae644f293389bcea1bd85f11732440555d 100644 (file)
@@ -1368,8 +1368,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
                return 0;
        if ((delegation->type & fmode) != fmode)
                return 0;
-       if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
-               return 0;
        switch (claim) {
        case NFS4_OPEN_CLAIM_NULL:
        case NFS4_OPEN_CLAIM_FH:
@@ -1628,7 +1626,6 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo
 static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
 {
        struct nfs4_state *state = opendata->state;
-       struct nfs_inode *nfsi = NFS_I(state->inode);
        struct nfs_delegation *delegation;
        int open_mode = opendata->o_arg.open_flags;
        fmode_t fmode = opendata->o_arg.fmode;
@@ -1645,7 +1642,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                }
                spin_unlock(&state->owner->so_lock);
                rcu_read_lock();
-               delegation = rcu_dereference(nfsi->delegation);
+               delegation = nfs4_get_valid_delegation(state->inode);
                if (!can_open_delegated(delegation, fmode, claim)) {
                        rcu_read_unlock();
                        break;
@@ -2142,7 +2139,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
                        goto out_no_action;
                rcu_read_lock();
-               delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
+               delegation = nfs4_get_valid_delegation(data->state->inode);
                if (can_open_delegated(delegation, data->o_arg.fmode, claim))
                        goto unlock_no_action;
                rcu_read_unlock();