diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 328 |
1 files changed, 237 insertions, 91 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9ca16dc09e04..e8c98f009670 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -49,12 +49,20 @@ | |||
49 | time_t nfsd4_lease = 90; /* default lease time */ | 49 | time_t nfsd4_lease = 90; /* default lease time */ |
50 | time_t nfsd4_grace = 90; | 50 | time_t nfsd4_grace = 90; |
51 | static time_t boot_time; | 51 | static time_t boot_time; |
52 | static stateid_t zerostateid; /* bits all 0 */ | 52 | |
53 | static stateid_t onestateid; /* bits all 1 */ | 53 | #define all_ones {{~0,~0},~0} |
54 | static const stateid_t one_stateid = { | ||
55 | .si_generation = ~0, | ||
56 | .si_opaque = all_ones, | ||
57 | }; | ||
58 | static const stateid_t zero_stateid = { | ||
59 | /* all fields zero */ | ||
60 | }; | ||
61 | |||
54 | static u64 current_sessionid = 1; | 62 | static u64 current_sessionid = 1; |
55 | 63 | ||
56 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) | 64 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) |
57 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) | 65 | #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) |
58 | 66 | ||
59 | /* forward declarations */ | 67 | /* forward declarations */ |
60 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); | 68 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); |
@@ -133,21 +141,21 @@ unsigned int max_delegations; | |||
133 | * Open owner state (share locks) | 141 | * Open owner state (share locks) |
134 | */ | 142 | */ |
135 | 143 | ||
136 | /* hash tables for open owners */ | 144 | /* hash tables for lock and open owners */ |
137 | #define OPEN_OWNER_HASH_BITS 8 | 145 | #define OWNER_HASH_BITS 8 |
138 | #define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS) | 146 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) |
139 | #define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1) | 147 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) |
140 | 148 | ||
141 | static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) | 149 | static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) |
142 | { | 150 | { |
143 | unsigned int ret; | 151 | unsigned int ret; |
144 | 152 | ||
145 | ret = opaque_hashval(ownername->data, ownername->len); | 153 | ret = opaque_hashval(ownername->data, ownername->len); |
146 | ret += clientid; | 154 | ret += clientid; |
147 | return ret & OPEN_OWNER_HASH_MASK; | 155 | return ret & OWNER_HASH_MASK; |
148 | } | 156 | } |
149 | 157 | ||
150 | static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE]; | 158 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; |
151 | 159 | ||
152 | /* hash table for nfs4_file */ | 160 | /* hash table for nfs4_file */ |
153 | #define FILE_HASH_BITS 8 | 161 | #define FILE_HASH_BITS 8 |
@@ -514,6 +522,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo) | |||
514 | 522 | ||
515 | list_del(&lo->lo_owner.so_strhash); | 523 | list_del(&lo->lo_owner.so_strhash); |
516 | list_del(&lo->lo_perstateid); | 524 | list_del(&lo->lo_perstateid); |
525 | list_del(&lo->lo_owner_ino_hash); | ||
517 | while (!list_empty(&lo->lo_owner.so_stateids)) { | 526 | while (!list_empty(&lo->lo_owner.so_stateids)) { |
518 | stp = list_first_entry(&lo->lo_owner.so_stateids, | 527 | stp = list_first_entry(&lo->lo_owner.so_stateids, |
519 | struct nfs4_ol_stateid, st_perstateowner); | 528 | struct nfs4_ol_stateid, st_perstateowner); |
@@ -985,12 +994,11 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
985 | clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); | 994 | clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); |
986 | if (clp == NULL) | 995 | if (clp == NULL) |
987 | return NULL; | 996 | return NULL; |
988 | clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); | 997 | clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); |
989 | if (clp->cl_name.data == NULL) { | 998 | if (clp->cl_name.data == NULL) { |
990 | kfree(clp); | 999 | kfree(clp); |
991 | return NULL; | 1000 | return NULL; |
992 | } | 1001 | } |
993 | memcpy(clp->cl_name.data, name.data, name.len); | ||
994 | clp->cl_name.len = name.len; | 1002 | clp->cl_name.len = name.len; |
995 | return clp; | 1003 | return clp; |
996 | } | 1004 | } |
@@ -1058,7 +1066,6 @@ expire_client(struct nfs4_client *clp) | |||
1058 | spin_unlock(&recall_lock); | 1066 | spin_unlock(&recall_lock); |
1059 | while (!list_empty(&reaplist)) { | 1067 | while (!list_empty(&reaplist)) { |
1060 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); | 1068 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); |
1061 | list_del_init(&dp->dl_recall_lru); | ||
1062 | unhash_delegation(dp); | 1069 | unhash_delegation(dp); |
1063 | } | 1070 | } |
1064 | while (!list_empty(&clp->cl_openowners)) { | 1071 | while (!list_empty(&clp->cl_openowners)) { |
@@ -2301,7 +2308,7 @@ nfsd4_free_slabs(void) | |||
2301 | nfsd4_free_slab(&deleg_slab); | 2308 | nfsd4_free_slab(&deleg_slab); |
2302 | } | 2309 | } |
2303 | 2310 | ||
2304 | static int | 2311 | int |
2305 | nfsd4_init_slabs(void) | 2312 | nfsd4_init_slabs(void) |
2306 | { | 2313 | { |
2307 | openowner_slab = kmem_cache_create("nfsd4_openowners", | 2314 | openowner_slab = kmem_cache_create("nfsd4_openowners", |
@@ -2373,7 +2380,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj | |||
2373 | 2380 | ||
2374 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) | 2381 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) |
2375 | { | 2382 | { |
2376 | list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]); | 2383 | list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); |
2377 | list_add(&oo->oo_perclient, &clp->cl_openowners); | 2384 | list_add(&oo->oo_perclient, &clp->cl_openowners); |
2378 | } | 2385 | } |
2379 | 2386 | ||
@@ -2436,7 +2443,9 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) | |||
2436 | struct nfs4_stateowner *so; | 2443 | struct nfs4_stateowner *so; |
2437 | struct nfs4_openowner *oo; | 2444 | struct nfs4_openowner *oo; |
2438 | 2445 | ||
2439 | list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) { | 2446 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { |
2447 | if (!so->so_is_open_owner) | ||
2448 | continue; | ||
2440 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { | 2449 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { |
2441 | oo = openowner(so); | 2450 | oo = openowner(so); |
2442 | renew_client(oo->oo_owner.so_client); | 2451 | renew_client(oo->oo_owner.so_client); |
@@ -2580,7 +2589,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, | |||
2580 | if (open->op_file == NULL) | 2589 | if (open->op_file == NULL) |
2581 | return nfserr_jukebox; | 2590 | return nfserr_jukebox; |
2582 | 2591 | ||
2583 | strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); | 2592 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); |
2584 | oo = find_openstateowner_str(strhashval, open); | 2593 | oo = find_openstateowner_str(strhashval, open); |
2585 | open->op_openowner = oo; | 2594 | open->op_openowner = oo; |
2586 | if (!oo) { | 2595 | if (!oo) { |
@@ -3123,7 +3132,6 @@ nfs4_laundromat(void) | |||
3123 | spin_unlock(&recall_lock); | 3132 | spin_unlock(&recall_lock); |
3124 | list_for_each_safe(pos, next, &reaplist) { | 3133 | list_for_each_safe(pos, next, &reaplist) { |
3125 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3134 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
3126 | list_del_init(&dp->dl_recall_lru); | ||
3127 | unhash_delegation(dp); | 3135 | unhash_delegation(dp); |
3128 | } | 3136 | } |
3129 | test_val = nfsd4_lease; | 3137 | test_val = nfsd4_lease; |
@@ -3718,13 +3726,11 @@ out: | |||
3718 | } | 3726 | } |
3719 | 3727 | ||
3720 | 3728 | ||
3721 | /* | ||
3722 | * Lock owner state (byte-range locks) | ||
3723 | */ | ||
3724 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) | 3729 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) |
3725 | #define LOCK_HASH_BITS 8 | 3730 | |
3726 | #define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) | 3731 | #define LOCKOWNER_INO_HASH_BITS 8 |
3727 | #define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) | 3732 | #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) |
3733 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) | ||
3728 | 3734 | ||
3729 | static inline u64 | 3735 | static inline u64 |
3730 | end_offset(u64 start, u64 len) | 3736 | end_offset(u64 start, u64 len) |
@@ -3746,16 +3752,14 @@ last_byte_offset(u64 start, u64 len) | |||
3746 | return end > start ? end - 1: NFS4_MAX_UINT64; | 3752 | return end > start ? end - 1: NFS4_MAX_UINT64; |
3747 | } | 3753 | } |
3748 | 3754 | ||
3749 | static inline unsigned int | 3755 | static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername) |
3750 | lock_ownerstr_hashval(struct inode *inode, u32 cl_id, | ||
3751 | struct xdr_netobj *ownername) | ||
3752 | { | 3756 | { |
3753 | return (file_hashval(inode) + cl_id | 3757 | return (file_hashval(inode) + cl_id |
3754 | + opaque_hashval(ownername->data, ownername->len)) | 3758 | + opaque_hashval(ownername->data, ownername->len)) |
3755 | & LOCK_HASH_MASK; | 3759 | & LOCKOWNER_INO_HASH_MASK; |
3756 | } | 3760 | } |
3757 | 3761 | ||
3758 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 3762 | static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE]; |
3759 | 3763 | ||
3760 | /* | 3764 | /* |
3761 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that | 3765 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that |
@@ -3809,23 +3813,39 @@ nevermind: | |||
3809 | deny->ld_type = NFS4_WRITE_LT; | 3813 | deny->ld_type = NFS4_WRITE_LT; |
3810 | } | 3814 | } |
3811 | 3815 | ||
3816 | static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner) | ||
3817 | { | ||
3818 | struct nfs4_ol_stateid *lst; | ||
3819 | |||
3820 | if (!same_owner_str(&lo->lo_owner, owner, clid)) | ||
3821 | return false; | ||
3822 | lst = list_first_entry(&lo->lo_owner.so_stateids, | ||
3823 | struct nfs4_ol_stateid, st_perstateowner); | ||
3824 | return lst->st_file->fi_inode == inode; | ||
3825 | } | ||
3826 | |||
3812 | static struct nfs4_lockowner * | 3827 | static struct nfs4_lockowner * |
3813 | find_lockowner_str(struct inode *inode, clientid_t *clid, | 3828 | find_lockowner_str(struct inode *inode, clientid_t *clid, |
3814 | struct xdr_netobj *owner) | 3829 | struct xdr_netobj *owner) |
3815 | { | 3830 | { |
3816 | unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); | 3831 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); |
3817 | struct nfs4_stateowner *op; | 3832 | struct nfs4_lockowner *lo; |
3818 | 3833 | ||
3819 | list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { | 3834 | list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { |
3820 | if (same_owner_str(op, owner, clid)) | 3835 | if (same_lockowner_ino(lo, inode, clid, owner)) |
3821 | return lockowner(op); | 3836 | return lo; |
3822 | } | 3837 | } |
3823 | return NULL; | 3838 | return NULL; |
3824 | } | 3839 | } |
3825 | 3840 | ||
3826 | static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) | 3841 | static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) |
3827 | { | 3842 | { |
3828 | list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]); | 3843 | struct inode *inode = open_stp->st_file->fi_inode; |
3844 | unsigned int inohash = lockowner_ino_hashval(inode, | ||
3845 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); | ||
3846 | |||
3847 | list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); | ||
3848 | list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); | ||
3829 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); | 3849 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); |
3830 | } | 3850 | } |
3831 | 3851 | ||
@@ -3834,7 +3854,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s | |||
3834 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has | 3854 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has |
3835 | * occurred. | 3855 | * occurred. |
3836 | * | 3856 | * |
3837 | * strhashval = lock_ownerstr_hashval | 3857 | * strhashval = ownerstr_hashval |
3838 | */ | 3858 | */ |
3839 | 3859 | ||
3840 | static struct nfs4_lockowner * | 3860 | static struct nfs4_lockowner * |
@@ -3892,6 +3912,37 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
3892 | __set_bit(access, &lock_stp->st_access_bmap); | 3912 | __set_bit(access, &lock_stp->st_access_bmap); |
3893 | } | 3913 | } |
3894 | 3914 | ||
3915 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | ||
3916 | { | ||
3917 | struct nfs4_file *fi = ost->st_file; | ||
3918 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | ||
3919 | struct nfs4_client *cl = oo->oo_owner.so_client; | ||
3920 | struct nfs4_lockowner *lo; | ||
3921 | unsigned int strhashval; | ||
3922 | |||
3923 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); | ||
3924 | if (lo) { | ||
3925 | if (!cstate->minorversion) | ||
3926 | return nfserr_bad_seqid; | ||
3927 | /* XXX: a lockowner always has exactly one stateid: */ | ||
3928 | *lst = list_first_entry(&lo->lo_owner.so_stateids, | ||
3929 | struct nfs4_ol_stateid, st_perstateowner); | ||
3930 | return nfs_ok; | ||
3931 | } | ||
3932 | strhashval = ownerstr_hashval(cl->cl_clientid.cl_id, | ||
3933 | &lock->v.new.owner); | ||
3934 | lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); | ||
3935 | if (lo == NULL) | ||
3936 | return nfserr_jukebox; | ||
3937 | *lst = alloc_init_lock_stateid(lo, fi, ost); | ||
3938 | if (*lst == NULL) { | ||
3939 | release_lockowner(lo); | ||
3940 | return nfserr_jukebox; | ||
3941 | } | ||
3942 | *new = true; | ||
3943 | return nfs_ok; | ||
3944 | } | ||
3945 | |||
3895 | /* | 3946 | /* |
3896 | * LOCK operation | 3947 | * LOCK operation |
3897 | */ | 3948 | */ |
@@ -3907,7 +3958,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3907 | struct file_lock file_lock; | 3958 | struct file_lock file_lock; |
3908 | struct file_lock conflock; | 3959 | struct file_lock conflock; |
3909 | __be32 status = 0; | 3960 | __be32 status = 0; |
3910 | unsigned int strhashval; | 3961 | bool new_state = false; |
3911 | int lkflg; | 3962 | int lkflg; |
3912 | int err; | 3963 | int err; |
3913 | 3964 | ||
@@ -3933,10 +3984,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3933 | * lock stateid. | 3984 | * lock stateid. |
3934 | */ | 3985 | */ |
3935 | struct nfs4_ol_stateid *open_stp = NULL; | 3986 | struct nfs4_ol_stateid *open_stp = NULL; |
3936 | 3987 | ||
3988 | if (nfsd4_has_session(cstate)) | ||
3989 | /* See rfc 5661 18.10.3: given clientid is ignored: */ | ||
3990 | memcpy(&lock->v.new.clientid, | ||
3991 | &cstate->session->se_client->cl_clientid, | ||
3992 | sizeof(clientid_t)); | ||
3993 | |||
3937 | status = nfserr_stale_clientid; | 3994 | status = nfserr_stale_clientid; |
3938 | if (!nfsd4_has_session(cstate) && | 3995 | if (STALE_CLIENTID(&lock->lk_new_clientid)) |
3939 | STALE_CLIENTID(&lock->lk_new_clientid)) | ||
3940 | goto out; | 3996 | goto out; |
3941 | 3997 | ||
3942 | /* validate and update open stateid and open seqid */ | 3998 | /* validate and update open stateid and open seqid */ |
@@ -3948,25 +4004,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3948 | goto out; | 4004 | goto out; |
3949 | open_sop = openowner(open_stp->st_stateowner); | 4005 | open_sop = openowner(open_stp->st_stateowner); |
3950 | status = nfserr_bad_stateid; | 4006 | status = nfserr_bad_stateid; |
3951 | if (!nfsd4_has_session(cstate) && | 4007 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, |
3952 | !same_clid(&open_sop->oo_owner.so_client->cl_clientid, | ||
3953 | &lock->v.new.clientid)) | 4008 | &lock->v.new.clientid)) |
3954 | goto out; | 4009 | goto out; |
3955 | /* create lockowner and lock stateid */ | 4010 | status = lookup_or_create_lock_state(cstate, open_stp, lock, |
3956 | fp = open_stp->st_file; | 4011 | &lock_stp, &new_state); |
3957 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 4012 | if (status) |
3958 | open_sop->oo_owner.so_client->cl_clientid.cl_id, | ||
3959 | &lock->v.new.owner); | ||
3960 | /* XXX: Do we need to check for duplicate stateowners on | ||
3961 | * the same file, or should they just be allowed (and | ||
3962 | * create new stateids)? */ | ||
3963 | status = nfserr_jukebox; | ||
3964 | lock_sop = alloc_init_lock_stateowner(strhashval, | ||
3965 | open_sop->oo_owner.so_client, open_stp, lock); | ||
3966 | if (lock_sop == NULL) | ||
3967 | goto out; | ||
3968 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); | ||
3969 | if (lock_stp == NULL) | ||
3970 | goto out; | 4013 | goto out; |
3971 | } else { | 4014 | } else { |
3972 | /* lock (lock owner + lock stateid) already exists */ | 4015 | /* lock (lock owner + lock stateid) already exists */ |
@@ -3976,10 +4019,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3976 | NFS4_LOCK_STID, &lock_stp); | 4019 | NFS4_LOCK_STID, &lock_stp); |
3977 | if (status) | 4020 | if (status) |
3978 | goto out; | 4021 | goto out; |
3979 | lock_sop = lockowner(lock_stp->st_stateowner); | ||
3980 | fp = lock_stp->st_file; | ||
3981 | } | 4022 | } |
3982 | /* lock_sop and lock_stp have been created or found */ | 4023 | lock_sop = lockowner(lock_stp->st_stateowner); |
4024 | fp = lock_stp->st_file; | ||
3983 | 4025 | ||
3984 | lkflg = setlkflg(lock->lk_type); | 4026 | lkflg = setlkflg(lock->lk_type); |
3985 | status = nfs4_check_openmode(lock_stp, lkflg); | 4027 | status = nfs4_check_openmode(lock_stp, lkflg); |
@@ -4054,7 +4096,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4054 | break; | 4096 | break; |
4055 | } | 4097 | } |
4056 | out: | 4098 | out: |
4057 | if (status && lock->lk_is_new && lock_sop) | 4099 | if (status && new_state) |
4058 | release_lockowner(lock_sop); | 4100 | release_lockowner(lock_sop); |
4059 | if (!cstate->replay_owner) | 4101 | if (!cstate->replay_owner) |
4060 | nfs4_unlock_state(); | 4102 | nfs4_unlock_state(); |
@@ -4251,7 +4293,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4251 | struct nfs4_ol_stateid *stp; | 4293 | struct nfs4_ol_stateid *stp; |
4252 | struct xdr_netobj *owner = &rlockowner->rl_owner; | 4294 | struct xdr_netobj *owner = &rlockowner->rl_owner; |
4253 | struct list_head matches; | 4295 | struct list_head matches; |
4254 | int i; | 4296 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); |
4255 | __be32 status; | 4297 | __be32 status; |
4256 | 4298 | ||
4257 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 4299 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
@@ -4266,22 +4308,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4266 | nfs4_lock_state(); | 4308 | nfs4_lock_state(); |
4267 | 4309 | ||
4268 | status = nfserr_locks_held; | 4310 | status = nfserr_locks_held; |
4269 | /* XXX: we're doing a linear search through all the lockowners. | ||
4270 | * Yipes! For now we'll just hope clients aren't really using | ||
4271 | * release_lockowner much, but eventually we have to fix these | ||
4272 | * data structures. */ | ||
4273 | INIT_LIST_HEAD(&matches); | 4311 | INIT_LIST_HEAD(&matches); |
4274 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | 4312 | |
4275 | list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) { | 4313 | list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) { |
4276 | if (!same_owner_str(sop, owner, clid)) | 4314 | if (sop->so_is_open_owner) |
4277 | continue; | 4315 | continue; |
4278 | list_for_each_entry(stp, &sop->so_stateids, | 4316 | if (!same_owner_str(sop, owner, clid)) |
4279 | st_perstateowner) { | 4317 | continue; |
4280 | lo = lockowner(sop); | 4318 | list_for_each_entry(stp, &sop->so_stateids, |
4281 | if (check_for_locks(stp->st_file, lo)) | 4319 | st_perstateowner) { |
4282 | goto out; | 4320 | lo = lockowner(sop); |
4283 | list_add(&lo->lo_list, &matches); | 4321 | if (check_for_locks(stp->st_file, lo)) |
4284 | } | 4322 | goto out; |
4323 | list_add(&lo->lo_list, &matches); | ||
4285 | } | 4324 | } |
4286 | } | 4325 | } |
4287 | /* Clients probably won't expect us to return with some (but not all) | 4326 | /* Clients probably won't expect us to return with some (but not all) |
@@ -4394,16 +4433,127 @@ nfs4_check_open_reclaim(clientid_t *clid) | |||
4394 | return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; | 4433 | return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; |
4395 | } | 4434 | } |
4396 | 4435 | ||
4436 | #ifdef CONFIG_NFSD_FAULT_INJECTION | ||
4437 | |||
4438 | void nfsd_forget_clients(u64 num) | ||
4439 | { | ||
4440 | struct nfs4_client *clp, *next; | ||
4441 | int count = 0; | ||
4442 | |||
4443 | nfs4_lock_state(); | ||
4444 | list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { | ||
4445 | nfsd4_remove_clid_dir(clp); | ||
4446 | expire_client(clp); | ||
4447 | if (++count == num) | ||
4448 | break; | ||
4449 | } | ||
4450 | nfs4_unlock_state(); | ||
4451 | |||
4452 | printk(KERN_INFO "NFSD: Forgot %d clients", count); | ||
4453 | } | ||
4454 | |||
4455 | static void release_lockowner_sop(struct nfs4_stateowner *sop) | ||
4456 | { | ||
4457 | release_lockowner(lockowner(sop)); | ||
4458 | } | ||
4459 | |||
4460 | static void release_openowner_sop(struct nfs4_stateowner *sop) | ||
4461 | { | ||
4462 | release_openowner(openowner(sop)); | ||
4463 | } | ||
4464 | |||
4465 | static int nfsd_release_n_owners(u64 num, bool is_open_owner, | ||
4466 | void (*release_sop)(struct nfs4_stateowner *)) | ||
4467 | { | ||
4468 | int i, count = 0; | ||
4469 | struct nfs4_stateowner *sop, *next; | ||
4470 | |||
4471 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | ||
4472 | list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) { | ||
4473 | if (sop->so_is_open_owner != is_open_owner) | ||
4474 | continue; | ||
4475 | release_sop(sop); | ||
4476 | if (++count == num) | ||
4477 | return count; | ||
4478 | } | ||
4479 | } | ||
4480 | return count; | ||
4481 | } | ||
4482 | |||
4483 | void nfsd_forget_locks(u64 num) | ||
4484 | { | ||
4485 | int count; | ||
4486 | |||
4487 | nfs4_lock_state(); | ||
4488 | count = nfsd_release_n_owners(num, false, release_lockowner_sop); | ||
4489 | nfs4_unlock_state(); | ||
4490 | |||
4491 | printk(KERN_INFO "NFSD: Forgot %d locks", count); | ||
4492 | } | ||
4493 | |||
4494 | void nfsd_forget_openowners(u64 num) | ||
4495 | { | ||
4496 | int count; | ||
4497 | |||
4498 | nfs4_lock_state(); | ||
4499 | count = nfsd_release_n_owners(num, true, release_openowner_sop); | ||
4500 | nfs4_unlock_state(); | ||
4501 | |||
4502 | printk(KERN_INFO "NFSD: Forgot %d open owners", count); | ||
4503 | } | ||
4504 | |||
4505 | int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *)) | ||
4506 | { | ||
4507 | int i, count = 0; | ||
4508 | struct nfs4_file *fp, *fnext; | ||
4509 | struct nfs4_delegation *dp, *dnext; | ||
4510 | |||
4511 | for (i = 0; i < FILE_HASH_SIZE; i++) { | ||
4512 | list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { | ||
4513 | list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { | ||
4514 | deleg_func(dp); | ||
4515 | if (++count == num) | ||
4516 | return count; | ||
4517 | } | ||
4518 | } | ||
4519 | } | ||
4520 | |||
4521 | return count; | ||
4522 | } | ||
4523 | |||
4524 | void nfsd_forget_delegations(u64 num) | ||
4525 | { | ||
4526 | unsigned int count; | ||
4527 | |||
4528 | nfs4_lock_state(); | ||
4529 | count = nfsd_process_n_delegations(num, unhash_delegation); | ||
4530 | nfs4_unlock_state(); | ||
4531 | |||
4532 | printk(KERN_INFO "NFSD: Forgot %d delegations", count); | ||
4533 | } | ||
4534 | |||
4535 | void nfsd_recall_delegations(u64 num) | ||
4536 | { | ||
4537 | unsigned int count; | ||
4538 | |||
4539 | nfs4_lock_state(); | ||
4540 | spin_lock(&recall_lock); | ||
4541 | count = nfsd_process_n_delegations(num, nfsd_break_one_deleg); | ||
4542 | spin_unlock(&recall_lock); | ||
4543 | nfs4_unlock_state(); | ||
4544 | |||
4545 | printk(KERN_INFO "NFSD: Recalled %d delegations", count); | ||
4546 | } | ||
4547 | |||
4548 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | ||
4549 | |||
4397 | /* initialization to perform at module load time: */ | 4550 | /* initialization to perform at module load time: */ |
4398 | 4551 | ||
4399 | int | 4552 | void |
4400 | nfs4_state_init(void) | 4553 | nfs4_state_init(void) |
4401 | { | 4554 | { |
4402 | int i, status; | 4555 | int i; |
4403 | 4556 | ||
4404 | status = nfsd4_init_slabs(); | ||
4405 | if (status) | ||
4406 | return status; | ||
4407 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 4557 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
4408 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); | 4558 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); |
4409 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 4559 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
@@ -4416,18 +4566,15 @@ nfs4_state_init(void) | |||
4416 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4566 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
4417 | INIT_LIST_HEAD(&file_hashtbl[i]); | 4567 | INIT_LIST_HEAD(&file_hashtbl[i]); |
4418 | } | 4568 | } |
4419 | for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { | 4569 | for (i = 0; i < OWNER_HASH_SIZE; i++) { |
4420 | INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); | 4570 | INIT_LIST_HEAD(&ownerstr_hashtbl[i]); |
4421 | } | ||
4422 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | ||
4423 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); | ||
4424 | } | 4571 | } |
4425 | memset(&onestateid, ~0, sizeof(stateid_t)); | 4572 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) |
4573 | INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); | ||
4426 | INIT_LIST_HEAD(&close_lru); | 4574 | INIT_LIST_HEAD(&close_lru); |
4427 | INIT_LIST_HEAD(&client_lru); | 4575 | INIT_LIST_HEAD(&client_lru); |
4428 | INIT_LIST_HEAD(&del_recall_lru); | 4576 | INIT_LIST_HEAD(&del_recall_lru); |
4429 | reclaim_str_hashtbl_size = 0; | 4577 | reclaim_str_hashtbl_size = 0; |
4430 | return 0; | ||
4431 | } | 4578 | } |
4432 | 4579 | ||
4433 | static void | 4580 | static void |
@@ -4526,7 +4673,6 @@ __nfs4_state_shutdown(void) | |||
4526 | spin_unlock(&recall_lock); | 4673 | spin_unlock(&recall_lock); |
4527 | list_for_each_safe(pos, next, &reaplist) { | 4674 | list_for_each_safe(pos, next, &reaplist) { |
4528 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 4675 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
4529 | list_del_init(&dp->dl_recall_lru); | ||
4530 | unhash_delegation(dp); | 4676 | unhash_delegation(dp); |
4531 | } | 4677 | } |
4532 | 4678 | ||