提交 03da3169 编写于 作者: T Trond Myklebust 提交者: J. Bruce Fields

nfsd: Fix races with check_stateid_generation()

The various functions that call check_stateid_generation() in order
to compare a client-supplied stateid with the nfs4_stid state, usually
need to atomically check for closed state. Those that perform the
check after locking the st_mutex using nfsd4_lock_ol_stateid()
should now be OK, but we do want to fix up the others.
Signed-off-by: NTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: NJ. Bruce Fields <bfields@redhat.com>
上级 9271d7e5
...@@ -4906,6 +4906,18 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s ...@@ -4906,6 +4906,18 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s
return nfserr_old_stateid; return nfserr_old_stateid;
} }
static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session)
{
__be32 ret;
spin_lock(&s->sc_lock);
ret = nfsd4_verify_open_stid(s);
if (ret == nfs_ok)
ret = check_stateid_generation(in, &s->sc_stateid, has_session);
spin_unlock(&s->sc_lock);
return ret;
}
static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols)
{ {
if (ols->st_stateowner->so_is_open_owner && if (ols->st_stateowner->so_is_open_owner &&
...@@ -4934,7 +4946,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) ...@@ -4934,7 +4946,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
s = find_stateid_locked(cl, stateid); s = find_stateid_locked(cl, stateid);
if (!s) if (!s)
goto out_unlock; goto out_unlock;
status = check_stateid_generation(stateid, &s->sc_stateid, 1); status = nfsd4_stid_check_stateid_generation(stateid, s, 1);
if (status) if (status)
goto out_unlock; goto out_unlock;
switch (s->sc_type) { switch (s->sc_type) {
...@@ -5095,7 +5107,7 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, ...@@ -5095,7 +5107,7 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
&s, nn); &s, nn);
if (status) if (status)
return status; return status;
status = check_stateid_generation(stateid, &s->sc_stateid, status = nfsd4_stid_check_stateid_generation(stateid, s,
nfsd4_has_session(cstate)); nfsd4_has_session(cstate));
if (status) if (status)
goto out; goto out;
...@@ -5188,6 +5200,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -5188,6 +5200,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
s = find_stateid_locked(cl, stateid); s = find_stateid_locked(cl, stateid);
if (!s) if (!s)
goto out_unlock; goto out_unlock;
spin_lock(&s->sc_lock);
switch (s->sc_type) { switch (s->sc_type) {
case NFS4_DELEG_STID: case NFS4_DELEG_STID:
ret = nfserr_locks_held; ret = nfserr_locks_held;
...@@ -5199,11 +5212,13 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -5199,11 +5212,13 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
ret = nfserr_locks_held; ret = nfserr_locks_held;
break; break;
case NFS4_LOCK_STID: case NFS4_LOCK_STID:
spin_unlock(&s->sc_lock);
refcount_inc(&s->sc_count); refcount_inc(&s->sc_count);
spin_unlock(&cl->cl_lock); spin_unlock(&cl->cl_lock);
ret = nfsd4_free_lock_stateid(stateid, s); ret = nfsd4_free_lock_stateid(stateid, s);
goto out; goto out;
case NFS4_REVOKED_DELEG_STID: case NFS4_REVOKED_DELEG_STID:
spin_unlock(&s->sc_lock);
dp = delegstateid(s); dp = delegstateid(s);
list_del_init(&dp->dl_recall_lru); list_del_init(&dp->dl_recall_lru);
spin_unlock(&cl->cl_lock); spin_unlock(&cl->cl_lock);
...@@ -5212,6 +5227,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -5212,6 +5227,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out; goto out;
/* Default falls through and returns nfserr_bad_stateid */ /* Default falls through and returns nfserr_bad_stateid */
} }
spin_unlock(&s->sc_lock);
out_unlock: out_unlock:
spin_unlock(&cl->cl_lock); spin_unlock(&cl->cl_lock);
out: out:
...@@ -5491,7 +5507,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -5491,7 +5507,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status) if (status)
goto out; goto out;
dp = delegstateid(s); dp = delegstateid(s);
status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate));
if (status) if (status)
goto put_stateid; goto put_stateid;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册