Commit 3e9e3dbe authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] knfsd: nfsd4: allow multiple lockowners

>From the language of rfc3530 section 8.1.3 (e.g., the suggestion that a
"process id" might be a reasonable lockowner value) it's conceivable that a
client might want to use the same lockowner string on multiple files, so we may
as well allow that.  We expect each use of open_to_lockowner to create a
distinct seqid stream, though.

For now we're also allowing multiple uses of open_to_lockowner with the same
open, though it seems unlikely clients would actually do that.

Also add a comment reminding myself of some very non-scalable data structures.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ea1da636
...@@ -2583,22 +2583,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) ...@@ -2583,22 +2583,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
deny->ld_type = NFS4_WRITE_LT; deny->ld_type = NFS4_WRITE_LT;
} }
static struct nfs4_stateowner *
find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
{
struct nfs4_stateowner *local = NULL;
int i;
for (i = 0; i < LOCK_HASH_SIZE; i++) {
list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
if (!cmp_owner_str(local, owner, clid))
continue;
return local;
}
}
return NULL;
}
static struct nfs4_stateowner * static struct nfs4_stateowner *
find_lockstateowner_str(struct inode *inode, clientid_t *clid, find_lockstateowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner) struct xdr_netobj *owner)
...@@ -2697,7 +2681,7 @@ check_lock_length(u64 offset, u64 length) ...@@ -2697,7 +2681,7 @@ check_lock_length(u64 offset, u64 length)
int int
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
{ {
struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL; struct nfs4_stateowner *open_sop = NULL;
struct nfs4_stateid *lock_stp; struct nfs4_stateid *lock_stp;
struct file *filp; struct file *filp;
struct file_lock file_lock; struct file_lock file_lock;
...@@ -2756,16 +2740,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock ...@@ -2756,16 +2740,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
strhashval = lock_ownerstr_hashval(fp->fi_inode, strhashval = lock_ownerstr_hashval(fp->fi_inode,
open_sop->so_client->cl_clientid.cl_id, open_sop->so_client->cl_clientid.cl_id,
&lock->v.new.owner); &lock->v.new.owner);
/* /* XXX: Do we need to check for duplicate stateowners on
* If we already have this lock owner, the client is in * the same file, or should they just be allowed (and
* error (or our bookeeping is wrong!) * create new stateids)? */
* for asking for a 'new lock'.
*/
status = nfserr_bad_stateid;
lock_sop = find_lockstateowner(&lock->v.new.owner,
&lock->v.new.clientid);
if (lock_sop)
goto out;
status = nfserr_resource; status = nfserr_resource;
if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
goto out; goto out;
...@@ -3056,8 +3033,11 @@ int ...@@ -3056,8 +3033,11 @@ int
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{ {
clientid_t *clid = &rlockowner->rl_clientid; clientid_t *clid = &rlockowner->rl_clientid;
struct nfs4_stateowner *local = NULL; struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner; struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
int i;
int status; int status;
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
...@@ -3073,22 +3053,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * ...@@ -3073,22 +3053,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
nfs4_lock_state(); nfs4_lock_state();
status = nfs_ok;
local = find_lockstateowner(owner, clid);
if (local) {
struct nfs4_stateid *stp;
/* check for any locks held by any stateid
* associated with the (lock) stateowner */
status = nfserr_locks_held; status = nfserr_locks_held;
list_for_each_entry(stp, &local->so_stateids, /* XXX: we're doing a linear search through all the lockowners.
* Yipes! For now we'll just hope clients aren't really using
* release_lockowner much, but eventually we have to fix these
* data structures. */
INIT_LIST_HEAD(&matches);
for (i = 0; i < LOCK_HASH_SIZE; i++) {
list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
if (!cmp_owner_str(sop, owner, clid))
continue;
list_for_each_entry(stp, &sop->so_stateids,
st_perstateowner) { st_perstateowner) {
if (check_for_locks(stp->st_vfs_file, local)) if (check_for_locks(stp->st_vfs_file, sop))
goto out; goto out;
/* Note: so_perclient unused for lockowners,
* so it's OK to fool with here. */
list_add(&sop->so_perclient, &matches);
} }
/* no locks held by (lock) stateowner */ }
}
/* Clients probably won't expect us to return with some (but not all)
* of the lockowner state released; so don't release any until all
* have been checked. */
status = nfs_ok; status = nfs_ok;
release_stateowner(local); list_for_each_entry(sop, &matches, so_perclient) {
release_stateowner(sop);
} }
out: out:
nfs4_unlock_state(); nfs4_unlock_state();
......
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