Commit 659aefb6 authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields

nfsd: Ensure we don't recognise lock stateids after freeing them

In order to deal with lookup races, nfsd4_free_lock_stateid() needs
to be able to signal to other stateful functions that the lock stateid
is no longer valid. Right now, nfsd_lock() will check whether or not an
existing stateid is still hashed, but only in the "new lock" path.

To ensure the stateid invalidation is also recognised by the "existing lock"
path, and also by a second call to nfsd4_free_lock_stateid() itself, we can
change the type to NFS4_CLOSED_STID under the stp->st_mutex.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent fb500a7c
...@@ -5149,7 +5149,9 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) ...@@ -5149,7 +5149,9 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
struct nfs4_ol_stateid *stp = openlockstateid(s); struct nfs4_ol_stateid *stp = openlockstateid(s);
__be32 ret; __be32 ret;
mutex_lock(&stp->st_mutex); ret = nfsd4_lock_ol_stateid(stp);
if (ret)
goto out_put_stid;
ret = check_stateid_generation(stateid, &s->sc_stateid, 1); ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
if (ret) if (ret)
...@@ -5160,11 +5162,13 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) ...@@ -5160,11 +5162,13 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
lockowner(stp->st_stateowner))) lockowner(stp->st_stateowner)))
goto out; goto out;
stp->st_stid.sc_type = NFS4_CLOSED_STID;
release_lock_stateid(stp); release_lock_stateid(stp);
ret = nfs_ok; ret = nfs_ok;
out: out:
mutex_unlock(&stp->st_mutex); mutex_unlock(&stp->st_mutex);
out_put_stid:
nfs4_put_stid(s); nfs4_put_stid(s);
return ret; return ret;
} }
...@@ -5733,6 +5737,8 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) ...@@ -5733,6 +5737,8 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
lockdep_assert_held(&clp->cl_lock); lockdep_assert_held(&clp->cl_lock);
list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
if (lst->st_stid.sc_type != NFS4_LOCK_STID)
continue;
if (lst->st_stid.sc_file == fp) { if (lst->st_stid.sc_file == fp) {
refcount_inc(&lst->st_stid.sc_count); refcount_inc(&lst->st_stid.sc_count);
return lst; return lst;
...@@ -5807,7 +5813,6 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, ...@@ -5807,7 +5813,6 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
struct nfs4_lockowner *lo; struct nfs4_lockowner *lo;
struct nfs4_ol_stateid *lst; struct nfs4_ol_stateid *lst;
unsigned int strhashval; unsigned int strhashval;
bool hashed;
lo = find_lockowner_str(cl, &lock->lk_new_owner); lo = find_lockowner_str(cl, &lock->lk_new_owner);
if (!lo) { if (!lo) {
...@@ -5830,15 +5835,7 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, ...@@ -5830,15 +5835,7 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
goto out; goto out;
} }
mutex_lock(&lst->st_mutex); if (nfsd4_lock_ol_stateid(lst) != nfs_ok) {
/* See if it's still hashed to avoid race with FREE_STATEID */
spin_lock(&cl->cl_lock);
hashed = !list_empty(&lst->st_perfile);
spin_unlock(&cl->cl_lock);
if (!hashed) {
mutex_unlock(&lst->st_mutex);
nfs4_put_stid(&lst->st_stid); nfs4_put_stid(&lst->st_stid);
goto retry; goto retry;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment