diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-24 01:04:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:06:35 -0400 |
commit | 3e9e3dbe0fe36c824ce2c5d7b05997c87a64bbdc (patch) | |
tree | f8291afbbe83259c5309d1b4b968359f1bf63fd4 /fs | |
parent | ea1da636e956ad1591a74904f23d98bbc26a644b (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.c | 76 |
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 | ||
2586 | static struct nfs4_stateowner * | 2586 | static struct nfs4_stateowner * |
2587 | find_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 | |||
2602 | static struct nfs4_stateowner * | ||
2603 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, | 2587 | find_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) | |||
2697 | int | 2681 | int |
2698 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) | 2682 | nfsd4_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 | |||
3056 | nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) | 3033 | nfsd4_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 | } |
3093 | out: | 3083 | out: |
3094 | nfs4_unlock_state(); | 3084 | nfs4_unlock_state(); |