diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2015-01-24 00:06:09 +0100 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2015-01-24 05:06:44 +0100 |
commit | f95549cf24660255c880b3ea7ee2d7d08de1f5c5 (patch) | |
tree | ae5c01fed19ffc8834fe276d4d0077e78b9225c6 /fs/nfs/nfs4proc.c | |
parent | NFSv4: Fix an atomicity problem in CLOSE (diff) | |
download | linux-f95549cf24660255c880b3ea7ee2d7d08de1f5c5.tar.xz linux-f95549cf24660255c880b3ea7ee2d7d08de1f5c5.zip |
NFSv4: More CLOSE/OPEN races
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>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4863dec10865..a6c04a5812d0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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); |