Skip to content

Commit

Permalink
nfsd: Ensure we don't recognise lock stateids after freeing them
Browse files Browse the repository at this point in the history
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: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
trondmypd authored and J. Bruce Fields committed Nov 27, 2017
1 parent fb500a7 commit 659aefb
Showing 1 changed file with 8 additions and 11 deletions.
19 changes: 8 additions & 11 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -5149,7 +5149,9 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
struct nfs4_ol_stateid *stp = openlockstateid(s);
__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);
if (ret)
Expand All @@ -5160,11 +5162,13 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
lockowner(stp->st_stateowner)))
goto out;

stp->st_stid.sc_type = NFS4_CLOSED_STID;
release_lock_stateid(stp);
ret = nfs_ok;

out:
mutex_unlock(&stp->st_mutex);
out_put_stid:
nfs4_put_stid(s);
return ret;
}
Expand Down Expand Up @@ -5733,6 +5737,8 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
lockdep_assert_held(&clp->cl_lock);

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) {
refcount_inc(&lst->st_stid.sc_count);
return lst;
Expand Down Expand Up @@ -5807,7 +5813,6 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
struct nfs4_lockowner *lo;
struct nfs4_ol_stateid *lst;
unsigned int strhashval;
bool hashed;

lo = find_lockowner_str(cl, &lock->lk_new_owner);
if (!lo) {
Expand All @@ -5830,15 +5835,7 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
goto out;
}

mutex_lock(&lst->st_mutex);

/* 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);
if (nfsd4_lock_ol_stateid(lst) != nfs_ok) {
nfs4_put_stid(&lst->st_stid);
goto retry;
}
Expand Down

0 comments on commit 659aefb

Please sign in to comment.