]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE
authorTrond Myklebust <trondmy@gmail.com>
Fri, 20 Sep 2019 11:23:47 +0000 (07:23 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Fri, 20 Sep 2019 19:56:19 +0000 (15:56 -0400)
If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
then bump the seqid before resending. Ensure we only bump the seqid
by 1.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c

index e8f74ed98e42c2664bdba02c4a380e901f99af79..16b2e5cc3e94ad665afb1daeea82152f58a3eeb2 100644 (file)
@@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
                const struct nfs_lock_context *, nfs4_stateid *,
                const struct cred **);
-extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
-               struct nfs4_state *state);
 extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
                struct nfs4_state *state);
 
index 9e283a8e8e93b4e0221cfe996a15a2925422c3af..0949bb535d7c61378c10cf9c4842b952826d1c73 100644 (file)
@@ -3313,6 +3313,75 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
        return pnfs_wait_on_layoutreturn(inode, task);
 }
 
+/*
+ * Update the seqid of an open stateid
+ */
+static void nfs4_sync_open_stateid(nfs4_stateid *dst,
+               struct nfs4_state *state)
+{
+       __be32 seqid_open;
+       u32 dst_seqid;
+       int seq;
+
+       for (;;) {
+               if (!nfs4_valid_open_stateid(state))
+                       break;
+               seq = read_seqbegin(&state->seqlock);
+               if (!nfs4_state_match_open_stateid_other(state, dst)) {
+                       nfs4_stateid_copy(dst, &state->open_stateid);
+                       if (read_seqretry(&state->seqlock, seq))
+                               continue;
+                       break;
+               }
+               seqid_open = state->open_stateid.seqid;
+               if (read_seqretry(&state->seqlock, seq))
+                       continue;
+
+               dst_seqid = be32_to_cpu(dst->seqid);
+               if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
+                       dst->seqid = seqid_open;
+               break;
+       }
+}
+
+/*
+ * Update the seqid of an open stateid after receiving
+ * NFS4ERR_OLD_STATEID
+ */
+static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
+               struct nfs4_state *state)
+{
+       __be32 seqid_open;
+       u32 dst_seqid;
+       bool ret;
+       int seq;
+
+       for (;;) {
+               ret = false;
+               if (!nfs4_valid_open_stateid(state))
+                       break;
+               seq = read_seqbegin(&state->seqlock);
+               if (!nfs4_state_match_open_stateid_other(state, dst)) {
+                       if (read_seqretry(&state->seqlock, seq))
+                               continue;
+                       break;
+               }
+               seqid_open = state->open_stateid.seqid;
+               if (read_seqretry(&state->seqlock, seq))
+                       continue;
+
+               dst_seqid = be32_to_cpu(dst->seqid);
+               if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
+                       dst->seqid = cpu_to_be32(dst_seqid + 1);
+               else
+                       dst->seqid = seqid_open;
+               ret = true;
+               break;
+       }
+
+       return ret;
+}
+
 struct nfs4_closedata {
        struct inode *inode;
        struct nfs4_state *state;
@@ -3387,7 +3456,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        break;
                case -NFS4ERR_OLD_STATEID:
                        /* Did we race with OPEN? */
-                       if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
+                       if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
                                                state))
                                goto out_restart;
                        goto out_release;
@@ -3456,8 +3525,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        } else if (is_rdwr)
                calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
 
-       if (!nfs4_valid_open_stateid(state) ||
-           !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
+       nfs4_sync_open_stateid(&calldata->arg.stateid, state);
+       if (!nfs4_valid_open_stateid(state))
                call_close = 0;
        spin_unlock(&state->owner->so_lock);
 
index e916aba7a7993192864e3196ad0364b785431167..0c6d53dc3672a5c4b0b92f475fba712f127edf59 100644 (file)
@@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        return ret;
 }
 
-bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
-{
-       bool ret;
-       int seq;
-
-       do {
-               ret = false;
-               seq = read_seqbegin(&state->seqlock);
-               if (nfs4_state_match_open_stateid_other(state, dst)) {
-                       dst->seqid = state->open_stateid.seqid;
-                       ret = true;
-               }
-       } while (read_seqretry(&state->seqlock, seq));
-       return ret;
-}
-
 bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
        bool ret;