NFSv4: More CLOSE/OPEN races
authorTrond Myklebust <trond.myklebust@primarydata.com>
Fri, 23 Jan 2015 23:06:09 +0000 (18:06 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Sat, 24 Jan 2015 04:06:44 +0000 (23:06 -0500)
If an OPEN RPC call races with a CLOSE or OPEN_DOWNGRADE so that it
updates the nfs_state structure before the CLOSE/OPEN_DOWNGRADE has
a chance to do so, then we know that the state->flags need to be
recalculated from scratch.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs4proc.c

index 4863dec108652d8db8f1f3247c8d724160e53926..a6c04a5812d0c744b416b60f1806d9cff8d6bd8e 100644 (file)
@@ -1167,6 +1167,16 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state,
        return false;
 }
 
+static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
+{
+       if (state->n_wronly)
+               set_bit(NFS_O_WRONLY_STATE, &state->flags);
+       if (state->n_rdonly)
+               set_bit(NFS_O_RDONLY_STATE, &state->flags);
+       if (state->n_rdwr)
+               set_bit(NFS_O_RDWR_STATE, &state->flags);
+}
+
 static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
                nfs4_stateid *stateid, fmode_t fmode)
 {
@@ -1185,8 +1195,12 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
        }
        if (stateid == NULL)
                return;
-       if (!nfs_need_update_open_stateid(state, stateid))
+       /* Handle races with OPEN */
+       if (!nfs4_stateid_match_other(stateid, &state->open_stateid) ||
+           !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
+               nfs_resync_open_stateid_locked(state);
                return;
+       }
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
                nfs4_stateid_copy(&state->stateid, stateid);
        nfs4_stateid_copy(&state->open_stateid, stateid);