nfsd4: extend state lock over seqid replay logic
There are currently a couple races in the seqid replay code: a retransmission could come while we're still encoding the original reply, or a new seqid-mutating call could come as we're encoding a replay. So, extend the state lock over the encoding (both encoding of a replayed reply and caching of the original encoded reply). I really hate doing this, and previously added the stateowner reference-counting code to avoid it (which was insufficient)--but I don't see a less complicated alternative at the moment. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
@@ -408,8 +408,8 @@ out:
|
|||||||
if (open->op_stateowner) {
|
if (open->op_stateowner) {
|
||||||
nfs4_get_stateowner(open->op_stateowner);
|
nfs4_get_stateowner(open->op_stateowner);
|
||||||
cstate->replay_owner = open->op_stateowner;
|
cstate->replay_owner = open->op_stateowner;
|
||||||
}
|
} else
|
||||||
nfs4_unlock_state();
|
nfs4_unlock_state();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1227,6 +1227,7 @@ encode_op:
|
|||||||
be32_to_cpu(status));
|
be32_to_cpu(status));
|
||||||
|
|
||||||
if (cstate->replay_owner) {
|
if (cstate->replay_owner) {
|
||||||
|
nfs4_unlock_state();
|
||||||
nfs4_put_stateowner(cstate->replay_owner);
|
nfs4_put_stateowner(cstate->replay_owner);
|
||||||
cstate->replay_owner = NULL;
|
cstate->replay_owner = NULL;
|
||||||
}
|
}
|
||||||
|
@@ -3501,7 +3501,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
|
|
||||||
nfsd4_create_clid_dir(sop->so_client);
|
nfsd4_create_clid_dir(sop->so_client);
|
||||||
out:
|
out:
|
||||||
nfs4_unlock_state();
|
if (!cstate->replay_owner)
|
||||||
|
nfs4_unlock_state();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3568,7 +3569,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
|
|||||||
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
|
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
out:
|
out:
|
||||||
nfs4_unlock_state();
|
if (!cstate->replay_owner)
|
||||||
|
nfs4_unlock_state();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3609,7 +3611,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if (list_empty(&so->so_stateids))
|
if (list_empty(&so->so_stateids))
|
||||||
move_to_close_lru(so);
|
move_to_close_lru(so);
|
||||||
out:
|
out:
|
||||||
nfs4_unlock_state();
|
if (!cstate->replay_owner)
|
||||||
|
nfs4_unlock_state();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4071,7 +4074,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
out:
|
out:
|
||||||
if (status && lock->lk_is_new && lock_sop)
|
if (status && lock->lk_is_new && lock_sop)
|
||||||
release_lockowner(lock_sop);
|
release_lockowner(lock_sop);
|
||||||
nfs4_unlock_state();
|
if (!cstate->replay_owner)
|
||||||
|
nfs4_unlock_state();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user