Skip to content

Commit 45a74b1

Browse files
aweitsgregkh
authored andcommitted
nfs: Fix race in __update_open_stateid()
commit 361cad3 upstream. We've seen this in a packet capture - I've intermixed what I think was going on. The fix here is to grab the so_lock sooner. 1964379 -> Grarak#1 open (for write) reply seqid=1 1964393 -> Grarak#2 open (for read) reply seqid=2 __nfs4_close(), state->n_wronly-- nfs4_state_set_mode_locked(), changes state->state = [R] state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 1964398 -> Grarak#3 open (for write) call -> because close is already running 1964399 -> downgrade (to read) call seqid=2 (close of Grarak#1) 1964402 -> Grarak#3 open (for write) reply seqid=3 __update_open_stateid() nfs_set_open_stateid_locked(), changes state->flags state->flags is [RW] state->state is [R], state->n_wronly == 0, state->n_rdonly == 1 new sequence number is exposed now via nfs4_stateid_copy() next step would be update_open_stateflags(), pending so_lock 1964403 -> downgrade reply seqid=2, fails with OLD_STATEID (close of Grarak#1) nfs4_close_prepare() gets so_lock and recalcs flags -> send close 1964405 -> downgrade (to read) call seqid=3 (close of Grarak#1 retry) __update_open_stateid() gets so_lock * update_open_stateflags() updates state->n_wronly. nfs4_state_set_mode_locked() updates state->state state->flags is [RW] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 * should have suppressed the preceding nfs4_close_prepare() from sending open_downgrade 1964406 -> write call 1964408 -> downgrade (to read) reply seqid=4 (close of Grarak#1 retry) nfs_clear_open_stateid_locked() state->flags is [R] state->state is [RW], state->n_wronly == 1, state->n_rdonly == 1 1964409 -> write reply (fails, openmode) Signed-off-by: Andrew Elble <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 65b1cbf commit 45a74b1

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

fs/nfs/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
10051005
* Protect the call to nfs4_state_set_mode_locked and
10061006
* serialise the stateid update
10071007
*/
1008+
spin_lock(&state->owner->so_lock);
10081009
write_seqlock(&state->seqlock);
10091010
if (deleg_stateid != NULL) {
10101011
nfs4_stateid_copy(&state->stateid, deleg_stateid);
@@ -1013,7 +1014,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
10131014
if (open_stateid != NULL)
10141015
nfs_set_open_stateid_locked(state, open_stateid, fmode);
10151016
write_sequnlock(&state->seqlock);
1016-
spin_lock(&state->owner->so_lock);
10171017
update_open_stateflags(state, fmode);
10181018
spin_unlock(&state->owner->so_lock);
10191019
}

0 commit comments

Comments
 (0)