]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
NFSv4: Fix delegation state recovery
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 19 Jul 2019 18:08:37 +0000 (14:08 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 16 Aug 2019 08:11:10 +0000 (10:11 +0200)
commit 5eb8d18ca0e001c6055da2b7f30d8f6dca23a44f upstream.

Once we clear the NFS_DELEGATED_STATE flag, we're telling
nfs_delegation_claim_opens() that we're done recovering all open state
for that stateid, so we really need to ensure that we test for all
open modes that are currently cached and recover them before exiting
nfs4_open_delegation_recall().

Fixes: 24311f884189d ("NFSv4: Recovery of recalled read delegations...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: stable@vger.kernel.org # v4.3+
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/nfs4proc.c

index 0ff3facf81dac61fe99c6eff078e0a23b000d2e4..0af854cce8ffa08958eb8ee584d82db5d78e0f6e 100644 (file)
@@ -153,7 +153,7 @@ again:
                /* Block nfs4_proc_unlck */
                mutex_lock(&sp->so_delegreturn_mutex);
                seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
-               err = nfs4_open_delegation_recall(ctx, state, stateid, type);
+               err = nfs4_open_delegation_recall(ctx, state, stateid);
                if (!err)
                        err = nfs_delegation_claim_locks(state, stateid);
                if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
index 5799777df5ec860d8eaee84d2ca495b31ea31d09..9eb87ae4c98276632ab799e5b66487df9cdcd3e4 100644 (file)
@@ -63,7 +63,7 @@ void nfs_reap_expired_delegations(struct nfs_client *clp);
 
 /* NFSv4 delegation-related procedures */
 int nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, const nfs4_stateid *stateid, int issync);
-int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
+int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
 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, const struct cred **cred);
 bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
index 6418cb6c079bd27dbdb1d93c59b5ce357a13f937..61a01e1399ac09e72f38c1b8b3071eaded003178 100644 (file)
@@ -2148,12 +2148,10 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
                case -NFS4ERR_BAD_HIGH_SLOT:
                case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                case -NFS4ERR_DEADSESSION:
-                       set_bit(NFS_DELEGATED_STATE, &state->flags);
                        nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
                        return -EAGAIN;
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_STALE_STATEID:
-                       set_bit(NFS_DELEGATED_STATE, &state->flags);
                        /* Don't recall a delegation if it was lost */
                        nfs4_schedule_lease_recovery(server->nfs_client);
                        return -EAGAIN;
@@ -2174,7 +2172,6 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
                        return -EAGAIN;
                case -NFS4ERR_DELAY:
                case -NFS4ERR_GRACE:
-                       set_bit(NFS_DELEGATED_STATE, &state->flags);
                        ssleep(1);
                        return -EAGAIN;
                case -ENOMEM:
@@ -2190,8 +2187,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
 }
 
 int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
-               struct nfs4_state *state, const nfs4_stateid *stateid,
-               fmode_t type)
+               struct nfs4_state *state, const nfs4_stateid *stateid)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_opendata *opendata;
@@ -2202,20 +2198,23 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
        if (IS_ERR(opendata))
                return PTR_ERR(opendata);
        nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
-       nfs_state_clear_delegation(state);
-       switch (type & (FMODE_READ|FMODE_WRITE)) {
-       case FMODE_READ|FMODE_WRITE:
-       case FMODE_WRITE:
+       if (!test_bit(NFS_O_RDWR_STATE, &state->flags)) {
                err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
                if (err)
-                       break;
+                       goto out;
+       }
+       if (!test_bit(NFS_O_WRONLY_STATE, &state->flags)) {
                err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
                if (err)
-                       break;
-               /* Fall through */
-       case FMODE_READ:
+                       goto out;
+       }
+       if (!test_bit(NFS_O_RDONLY_STATE, &state->flags)) {
                err = nfs4_open_recover_helper(opendata, FMODE_READ);
+               if (err)
+                       goto out;
        }
+       nfs_state_clear_delegation(state);
+out:
        nfs4_opendata_put(opendata);
        return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err);
 }