diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
| -rw-r--r-- | fs/nfsd/nfs4state.c | 150 |
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 | ||
| 150 | static 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 | |||
| 166 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; | ||
| 167 | static 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 | |||
| 183 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | ||
| 184 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
| 185 | |||
| 150 | static struct nfs4_delegation * | 186 | static struct nfs4_delegation * |
| 151 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 187 | alloc_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 | ||
| 332 | static void | 372 | static void |
| 373 | shutdown_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 | |||
| 385 | static void | ||
| 333 | expire_client(struct nfs4_client *clp) | 386 | expire_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 | |||
| 953 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; | ||
| 954 | static 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 | |||
| 970 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | ||
| 971 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
| 972 | |||
| 973 | /* OPEN Share state helper functions */ | 986 | /* OPEN Share state helper functions */ |
| 974 | static inline struct nfs4_file * | 987 | static inline struct nfs4_file * |
| 975 | alloc_init_file(struct inode *ino) | 988 | alloc_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 | ||
| 2498 | static int | 2509 | /* Hack!: For now, we're defining this just so we can use a pointer to it |
| 2499 | nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) | 2510 | * as a unique cookie to identify our (NFSv4's) posix locks. */ |
| 2500 | { | 2511 | static 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 | } | ||
| 2512 | out: | ||
| 2513 | return status; | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | 2513 | ||
| 2517 | static inline void | 2514 | static inline void |
| 2518 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 2515 | nfs4_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) | |||
| 3253 | void | 3249 | void |
| 3254 | nfs4_state_shutdown(void) | 3250 | nfs4_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(); |
