aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-06-24 01:04:20 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:06:35 -0400
commit3e9e3dbe0fe36c824ce2c5d7b05997c87a64bbdc (patch)
treef8291afbbe83259c5309d1b4b968359f1bf63fd4 /fs
parentea1da636e956ad1591a74904f23d98bbc26a644b (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c76
1 files changed, 33 insertions, 43 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 22e76e3f06a5..26d00465c28a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2584,22 +2584,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
2584} 2584}
2585 2585
2586static struct nfs4_stateowner * 2586static struct nfs4_stateowner *
2587find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
2588{
2589 struct nfs4_stateowner *local = NULL;
2590 int i;
2591
2592 for (i = 0; i < LOCK_HASH_SIZE; i++) {
2593 list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
2594 if (!cmp_owner_str(local, owner, clid))
2595 continue;
2596 return local;
2597 }
2598 }
2599 return NULL;
2600}
2601
2602static struct nfs4_stateowner *
2603find_lockstateowner_str(struct inode *inode, clientid_t *clid, 2587find_lockstateowner_str(struct inode *inode, clientid_t *clid,
2604 struct xdr_netobj *owner) 2588 struct xdr_netobj *owner)
2605{ 2589{
@@ -2697,7 +2681,7 @@ check_lock_length(u64 offset, u64 length)
2697int 2681int
2698nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) 2682nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
2699{ 2683{
2700 struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL; 2684 struct nfs4_stateowner *open_sop = NULL;
2701 struct nfs4_stateid *lock_stp; 2685 struct nfs4_stateid *lock_stp;
2702 struct file *filp; 2686 struct file *filp;
2703 struct file_lock file_lock; 2687 struct file_lock file_lock;
@@ -2756,16 +2740,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2756 strhashval = lock_ownerstr_hashval(fp->fi_inode, 2740 strhashval = lock_ownerstr_hashval(fp->fi_inode,
2757 open_sop->so_client->cl_clientid.cl_id, 2741 open_sop->so_client->cl_clientid.cl_id,
2758 &lock->v.new.owner); 2742 &lock->v.new.owner);
2759 /* 2743 /* XXX: Do we need to check for duplicate stateowners on
2760 * If we already have this lock owner, the client is in 2744 * the same file, or should they just be allowed (and
2761 * error (or our bookeeping is wrong!) 2745 * create new stateids)? */
2762 * for asking for a 'new lock'.
2763 */
2764 status = nfserr_bad_stateid;
2765 lock_sop = find_lockstateowner(&lock->v.new.owner,
2766 &lock->v.new.clientid);
2767 if (lock_sop)
2768 goto out;
2769 status = nfserr_resource; 2746 status = nfserr_resource;
2770 if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) 2747 if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
2771 goto out; 2748 goto out;
@@ -3056,8 +3033,11 @@ int
3056nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) 3033nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
3057{ 3034{
3058 clientid_t *clid = &rlockowner->rl_clientid; 3035 clientid_t *clid = &rlockowner->rl_clientid;
3059 struct nfs4_stateowner *local = NULL; 3036 struct nfs4_stateowner *sop;
3037 struct nfs4_stateid *stp;
3060 struct xdr_netobj *owner = &rlockowner->rl_owner; 3038 struct xdr_netobj *owner = &rlockowner->rl_owner;
3039 struct list_head matches;
3040 int i;
3061 int status; 3041 int status;
3062 3042
3063 dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 3043 dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -3073,22 +3053,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
3073 3053
3074 nfs4_lock_state(); 3054 nfs4_lock_state();
3075 3055
3076 status = nfs_ok; 3056 status = nfserr_locks_held;
3077 local = find_lockstateowner(owner, clid); 3057 /* XXX: we're doing a linear search through all the lockowners.
3078 if (local) { 3058 * Yipes! For now we'll just hope clients aren't really using
3079 struct nfs4_stateid *stp; 3059 * release_lockowner much, but eventually we have to fix these
3080 3060 * data structures. */
3081 /* check for any locks held by any stateid 3061 INIT_LIST_HEAD(&matches);
3082 * associated with the (lock) stateowner */ 3062 for (i = 0; i < LOCK_HASH_SIZE; i++) {
3083 status = nfserr_locks_held; 3063 list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
3084 list_for_each_entry(stp, &local->so_stateids, 3064 if (!cmp_owner_str(sop, owner, clid))
3085 st_perstateowner) { 3065 continue;
3086 if (check_for_locks(stp->st_vfs_file, local)) 3066 list_for_each_entry(stp, &sop->so_stateids,
3087 goto out; 3067 st_perstateowner) {
3068 if (check_for_locks(stp->st_vfs_file, sop))
3069 goto out;
3070 /* Note: so_perclient unused for lockowners,
3071 * so it's OK to fool with here. */
3072 list_add(&sop->so_perclient, &matches);
3073 }
3088 } 3074 }
3089 /* no locks held by (lock) stateowner */ 3075 }
3090 status = nfs_ok; 3076 /* Clients probably won't expect us to return with some (but not all)
3091 release_stateowner(local); 3077 * of the lockowner state released; so don't release any until all
3078 * have been checked. */
3079 status = nfs_ok;
3080 list_for_each_entry(sop, &matches, so_perclient) {
3081 release_stateowner(sop);
3092 } 3082 }
3093out: 3083out:
3094 nfs4_unlock_state(); 3084 nfs4_unlock_state();