Commit 3f8f2548 authored by NeilBrown's avatar NeilBrown Committed by Trond Myklebust

NFSv4: ensure __nfs4_find_lock_state returns consistent result.

If a file has both flock locks and OFD locks, then it is possible that
two different nfs4 lock states could apply to file accesses from a
single process.

It is not possible to know, efficiently, which one is "correct".
Presumably the state which represents a lock that covers the region
undergoing IO would be the "correct" one to use, but finding that has
a non-trivial cost and would provide miniscule value.

Currently we just return whichever is first in the list, which could
result in inconsistent behaviour if an application ever put it self in
this position.  As consistent behaviour is preferable (when perfectly
correct behaviour is not available), change the search to return a
consistent result in this circumstance.
Specifically: if there is both a flock and OFD lock state, always return
the flock one.
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent cfd278c2
......@@ -797,21 +797,33 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
/*
* Search the state->lock_states for an existing lock_owner
* that is compatible with current->files
* that is compatible with either of the given owners.
* If the second is non-zero, then the first refers to a Posix-lock
* owner (current->files) and the second refers to a flock/OFD
* owner (struct file*). In that case, prefer a match for the first
* owner.
* If both sorts of locks are held on the one file we cannot know
* which stateid was intended to be used, so a "correct" choice cannot
* be made. Failing that, a "consistent" choice is preferable. The
* consistent choice we make is to prefer the first owner, that of a
* Posix lock.
*/
static struct nfs4_lock_state *
__nfs4_find_lock_state(struct nfs4_state *state,
fl_owner_t fl_owner, fl_owner_t fl_owner2)
{
struct nfs4_lock_state *pos;
struct nfs4_lock_state *pos, *ret = NULL;
list_for_each_entry(pos, &state->lock_states, ls_locks) {
if (pos->ls_owner != fl_owner &&
pos->ls_owner != fl_owner2)
continue;
atomic_inc(&pos->ls_count);
return pos;
if (pos->ls_owner == fl_owner) {
ret = pos;
break;
}
if (pos->ls_owner == fl_owner2)
ret = pos;
}
return NULL;
if (ret)
atomic_inc(&ret->ls_count);
return ret;
}
/*
......
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