aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c150
1 files changed, 74 insertions, 76 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 47ec112b266c..96c7578cbe1e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -147,6 +147,42 @@ get_nfs4_file(struct nfs4_file *fi)
147 kref_get(&fi->fi_ref); 147 kref_get(&fi->fi_ref);
148} 148}
149 149
150static int num_delegations;
151
152/*
153 * Open owner state (share locks)
154 */
155
156/* hash tables for nfs4_stateowner */
157#define OWNER_HASH_BITS 8
158#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
159#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
160
161#define ownerid_hashval(id) \
162 ((id) & OWNER_HASH_MASK)
163#define ownerstr_hashval(clientid, ownername) \
164 (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
165
166static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
167static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
168
169/* hash table for nfs4_file */
170#define FILE_HASH_BITS 8
171#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
172#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
173/* hash table for (open)nfs4_stateid */
174#define STATEID_HASH_BITS 10
175#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
176#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
177
178#define file_hashval(x) \
179 hash_ptr(x, FILE_HASH_BITS)
180#define stateid_hashval(owner_id, file_id) \
181 (((owner_id) + (file_id)) & STATEID_HASH_MASK)
182
183static struct list_head file_hashtbl[FILE_HASH_SIZE];
184static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
185
150static struct nfs4_delegation * 186static struct nfs4_delegation *
151alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) 187alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
152{ 188{
@@ -155,9 +191,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
155 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; 191 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
156 192
157 dprintk("NFSD alloc_init_deleg\n"); 193 dprintk("NFSD alloc_init_deleg\n");
194 if (num_delegations > STATEID_HASH_SIZE * 4)
195 return NULL;
158 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); 196 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
159 if (dp == NULL) 197 if (dp == NULL)
160 return dp; 198 return dp;
199 num_delegations++;
161 INIT_LIST_HEAD(&dp->dl_perfile); 200 INIT_LIST_HEAD(&dp->dl_perfile);
162 INIT_LIST_HEAD(&dp->dl_perclnt); 201 INIT_LIST_HEAD(&dp->dl_perclnt);
163 INIT_LIST_HEAD(&dp->dl_recall_lru); 202 INIT_LIST_HEAD(&dp->dl_recall_lru);
@@ -192,6 +231,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
192 dprintk("NFSD: freeing dp %p\n",dp); 231 dprintk("NFSD: freeing dp %p\n",dp);
193 put_nfs4_file(dp->dl_file); 232 put_nfs4_file(dp->dl_file);
194 kmem_cache_free(deleg_slab, dp); 233 kmem_cache_free(deleg_slab, dp);
234 num_delegations--;
195 } 235 }
196} 236}
197 237
@@ -330,22 +370,29 @@ put_nfs4_client(struct nfs4_client *clp)
330} 370}
331 371
332static void 372static void
373shutdown_callback_client(struct nfs4_client *clp)
374{
375 struct rpc_clnt *clnt = clp->cl_callback.cb_client;
376
377 /* shutdown rpc client, ending any outstanding recall rpcs */
378 if (clnt) {
379 clp->cl_callback.cb_client = NULL;
380 rpc_shutdown_client(clnt);
381 rpciod_down();
382 }
383}
384
385static void
333expire_client(struct nfs4_client *clp) 386expire_client(struct nfs4_client *clp)
334{ 387{
335 struct nfs4_stateowner *sop; 388 struct nfs4_stateowner *sop;
336 struct nfs4_delegation *dp; 389 struct nfs4_delegation *dp;
337 struct nfs4_callback *cb = &clp->cl_callback;
338 struct rpc_clnt *clnt = clp->cl_callback.cb_client;
339 struct list_head reaplist; 390 struct list_head reaplist;
340 391
341 dprintk("NFSD: expire_client cl_count %d\n", 392 dprintk("NFSD: expire_client cl_count %d\n",
342 atomic_read(&clp->cl_count)); 393 atomic_read(&clp->cl_count));
343 394
344 /* shutdown rpc client, ending any outstanding recall rpcs */ 395 shutdown_callback_client(clp);
345 if (atomic_read(&cb->cb_set) == 1 && clnt) {
346 rpc_shutdown_client(clnt);
347 clnt = clp->cl_callback.cb_client = NULL;
348 }
349 396
350 INIT_LIST_HEAD(&reaplist); 397 INIT_LIST_HEAD(&reaplist);
351 spin_lock(&recall_lock); 398 spin_lock(&recall_lock);
@@ -936,40 +983,6 @@ out:
936 return status; 983 return status;
937} 984}
938 985
939/*
940 * Open owner state (share locks)
941 */
942
943/* hash tables for nfs4_stateowner */
944#define OWNER_HASH_BITS 8
945#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
946#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
947
948#define ownerid_hashval(id) \
949 ((id) & OWNER_HASH_MASK)
950#define ownerstr_hashval(clientid, ownername) \
951 (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
952
953static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
954static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
955
956/* hash table for nfs4_file */
957#define FILE_HASH_BITS 8
958#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
959#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
960/* hash table for (open)nfs4_stateid */
961#define STATEID_HASH_BITS 10
962#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
963#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
964
965#define file_hashval(x) \
966 hash_ptr(x, FILE_HASH_BITS)
967#define stateid_hashval(owner_id, file_id) \
968 (((owner_id) + (file_id)) & STATEID_HASH_MASK)
969
970static struct list_head file_hashtbl[FILE_HASH_SIZE];
971static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
972
973/* OPEN Share state helper functions */ 986/* OPEN Share state helper functions */
974static inline struct nfs4_file * 987static inline struct nfs4_file *
975alloc_init_file(struct inode *ino) 988alloc_init_file(struct inode *ino)
@@ -1186,8 +1199,7 @@ move_to_close_lru(struct nfs4_stateowner *sop)
1186{ 1199{
1187 dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); 1200 dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
1188 1201
1189 unhash_stateowner(sop); 1202 list_move_tail(&sop->so_close_lru, &close_lru);
1190 list_add_tail(&sop->so_close_lru, &close_lru);
1191 sop->so_time = get_seconds(); 1203 sop->so_time = get_seconds();
1192} 1204}
1193 1205
@@ -1916,8 +1928,7 @@ nfs4_laundromat(void)
1916 } 1928 }
1917 dprintk("NFSD: purging unused open stateowner (so_id %d)\n", 1929 dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
1918 sop->so_id); 1930 sop->so_id);
1919 list_del(&sop->so_close_lru); 1931 release_stateowner(sop);
1920 nfs4_put_stateowner(sop);
1921 } 1932 }
1922 if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) 1933 if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
1923 clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; 1934 clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
@@ -2495,36 +2506,27 @@ nfs4_transform_lock_offset(struct file_lock *lock)
2495 lock->fl_end = OFFSET_MAX; 2506 lock->fl_end = OFFSET_MAX;
2496} 2507}
2497 2508
2498static int 2509/* Hack!: For now, we're defining this just so we can use a pointer to it
2499nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) 2510 * as a unique cookie to identify our (NFSv4's) posix locks. */
2500{ 2511static struct lock_manager_operations nfsd_posix_mng_ops = {
2501 struct nfs4_stateowner *local = NULL; 2512};
2502 int status = 0;
2503
2504 if (hashval >= LOCK_HASH_SIZE)
2505 goto out;
2506 list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {
2507 if (local == sop) {
2508 status = 1;
2509 goto out;
2510 }
2511 }
2512out:
2513 return status;
2514}
2515
2516 2513
2517static inline void 2514static inline void
2518nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 2515nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
2519{ 2516{
2520 struct nfs4_stateowner *sop = (struct nfs4_stateowner *) fl->fl_owner; 2517 struct nfs4_stateowner *sop;
2521 unsigned int hval = lockownerid_hashval(sop->so_id); 2518 unsigned int hval;
2522 2519
2523 deny->ld_sop = NULL; 2520 if (fl->fl_lmops == &nfsd_posix_mng_ops) {
2524 if (nfs4_verify_lock_stateowner(sop, hval)) { 2521 sop = (struct nfs4_stateowner *) fl->fl_owner;
2522 hval = lockownerid_hashval(sop->so_id);
2525 kref_get(&sop->so_ref); 2523 kref_get(&sop->so_ref);
2526 deny->ld_sop = sop; 2524 deny->ld_sop = sop;
2527 deny->ld_clientid = sop->so_client->cl_clientid; 2525 deny->ld_clientid = sop->so_client->cl_clientid;
2526 } else {
2527 deny->ld_sop = NULL;
2528 deny->ld_clientid.cl_boot = 0;
2529 deny->ld_clientid.cl_id = 0;
2528 } 2530 }
2529 deny->ld_start = fl->fl_start; 2531 deny->ld_start = fl->fl_start;
2530 deny->ld_length = ~(u64)0; 2532 deny->ld_length = ~(u64)0;
@@ -2736,6 +2738,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2736 file_lock.fl_pid = current->tgid; 2738 file_lock.fl_pid = current->tgid;
2737 file_lock.fl_file = filp; 2739 file_lock.fl_file = filp;
2738 file_lock.fl_flags = FL_POSIX; 2740 file_lock.fl_flags = FL_POSIX;
2741 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2739 2742
2740 file_lock.fl_start = lock->lk_offset; 2743 file_lock.fl_start = lock->lk_offset;
2741 if ((lock->lk_length == ~(u64)0) || 2744 if ((lock->lk_length == ~(u64)0) ||
@@ -2841,6 +2844,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2841 file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner; 2844 file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
2842 file_lock.fl_pid = current->tgid; 2845 file_lock.fl_pid = current->tgid;
2843 file_lock.fl_flags = FL_POSIX; 2846 file_lock.fl_flags = FL_POSIX;
2847 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2844 2848
2845 file_lock.fl_start = lockt->lt_offset; 2849 file_lock.fl_start = lockt->lt_offset;
2846 if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) 2850 if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length))
@@ -2900,6 +2904,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2900 file_lock.fl_pid = current->tgid; 2904 file_lock.fl_pid = current->tgid;
2901 file_lock.fl_file = filp; 2905 file_lock.fl_file = filp;
2902 file_lock.fl_flags = FL_POSIX; 2906 file_lock.fl_flags = FL_POSIX;
2907 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2903 file_lock.fl_start = locku->lu_offset; 2908 file_lock.fl_start = locku->lu_offset;
2904 2909
2905 if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) 2910 if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length))
@@ -3211,15 +3216,8 @@ __nfs4_state_shutdown(void)
3211 int i; 3216 int i;
3212 struct nfs4_client *clp = NULL; 3217 struct nfs4_client *clp = NULL;
3213 struct nfs4_delegation *dp = NULL; 3218 struct nfs4_delegation *dp = NULL;
3214 struct nfs4_stateowner *sop = NULL;
3215 struct list_head *pos, *next, reaplist; 3219 struct list_head *pos, *next, reaplist;
3216 3220
3217 list_for_each_safe(pos, next, &close_lru) {
3218 sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
3219 list_del(&sop->so_close_lru);
3220 nfs4_put_stateowner(sop);
3221 }
3222
3223 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 3221 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
3224 while (!list_empty(&conf_id_hashtbl[i])) { 3222 while (!list_empty(&conf_id_hashtbl[i])) {
3225 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 3223 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
@@ -3244,8 +3242,6 @@ __nfs4_state_shutdown(void)
3244 } 3242 }
3245 3243
3246 cancel_delayed_work(&laundromat_work); 3244 cancel_delayed_work(&laundromat_work);
3247 flush_workqueue(laundry_wq);
3248 destroy_workqueue(laundry_wq);
3249 nfsd4_shutdown_recdir(); 3245 nfsd4_shutdown_recdir();
3250 nfs4_init = 0; 3246 nfs4_init = 0;
3251} 3247}
@@ -3253,6 +3249,8 @@ __nfs4_state_shutdown(void)
3253void 3249void
3254nfs4_state_shutdown(void) 3250nfs4_state_shutdown(void)
3255{ 3251{
3252 cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work);
3253 destroy_workqueue(laundry_wq);
3256 nfs4_lock_state(); 3254 nfs4_lock_state();
3257 nfs4_release_reclaim(); 3255 nfs4_release_reclaim();
3258 __nfs4_state_shutdown(); 3256 __nfs4_state_shutdown();