[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: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
ea1da636e9
commit
3e9e3dbe0f
@@ -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)
|
|||||||
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
|
|||||||
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
|
|||||||
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 *
|
|||||||
|
|
||||||
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();
|
||||||
|
Reference in New Issue
Block a user