diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 170 |
1 files changed, 91 insertions, 79 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7b566ec14e18..4cf04e11c66c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -148,7 +148,7 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
148 | /* hash table for nfs4_file */ | 148 | /* hash table for nfs4_file */ |
149 | #define FILE_HASH_BITS 8 | 149 | #define FILE_HASH_BITS 8 |
150 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 150 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
151 | #define FILE_HASH_MASK (FILE_HASH_SIZE - 1) | 151 | |
152 | /* hash table for (open)nfs4_stateid */ | 152 | /* hash table for (open)nfs4_stateid */ |
153 | #define STATEID_HASH_BITS 10 | 153 | #define STATEID_HASH_BITS 10 |
154 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) | 154 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) |
@@ -258,6 +258,7 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp) | |||
258 | if (atomic_dec_and_test(&fp->fi_delegees)) { | 258 | if (atomic_dec_and_test(&fp->fi_delegees)) { |
259 | vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); | 259 | vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); |
260 | fp->fi_lease = NULL; | 260 | fp->fi_lease = NULL; |
261 | fput(fp->fi_deleg_file); | ||
261 | fp->fi_deleg_file = NULL; | 262 | fp->fi_deleg_file = NULL; |
262 | } | 263 | } |
263 | } | 264 | } |
@@ -316,64 +317,6 @@ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | |||
316 | static struct list_head client_lru; | 317 | static struct list_head client_lru; |
317 | static struct list_head close_lru; | 318 | static struct list_head close_lru; |
318 | 319 | ||
319 | static void unhash_generic_stateid(struct nfs4_stateid *stp) | ||
320 | { | ||
321 | list_del(&stp->st_hash); | ||
322 | list_del(&stp->st_perfile); | ||
323 | list_del(&stp->st_perstateowner); | ||
324 | } | ||
325 | |||
326 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
327 | { | ||
328 | put_nfs4_file(stp->st_file); | ||
329 | kmem_cache_free(stateid_slab, stp); | ||
330 | } | ||
331 | |||
332 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
333 | { | ||
334 | struct file *file; | ||
335 | |||
336 | unhash_generic_stateid(stp); | ||
337 | file = find_any_file(stp->st_file); | ||
338 | if (file) | ||
339 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
340 | free_generic_stateid(stp); | ||
341 | } | ||
342 | |||
343 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
344 | { | ||
345 | struct nfs4_stateid *stp; | ||
346 | |||
347 | list_del(&sop->so_idhash); | ||
348 | list_del(&sop->so_strhash); | ||
349 | list_del(&sop->so_perstateid); | ||
350 | while (!list_empty(&sop->so_stateids)) { | ||
351 | stp = list_first_entry(&sop->so_stateids, | ||
352 | struct nfs4_stateid, st_perstateowner); | ||
353 | release_lock_stateid(stp); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
358 | { | ||
359 | unhash_lockowner(sop); | ||
360 | nfs4_put_stateowner(sop); | ||
361 | } | ||
362 | |||
363 | static void | ||
364 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
365 | { | ||
366 | struct nfs4_stateowner *lock_sop; | ||
367 | |||
368 | while (!list_empty(&open_stp->st_lockowners)) { | ||
369 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
370 | struct nfs4_stateowner, so_perstateid); | ||
371 | /* list_del(&open_stp->st_lockowners); */ | ||
372 | BUG_ON(lock_sop->so_is_open_owner); | ||
373 | release_lockowner(lock_sop); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* | 320 | /* |
378 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 321 | * We store the NONE, READ, WRITE, and BOTH bits separately in the |
379 | * st_{access,deny}_bmap field of the stateid, in order to track not | 322 | * st_{access,deny}_bmap field of the stateid, in order to track not |
@@ -446,13 +389,74 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | |||
446 | return nfs4_access_to_omode(access); | 389 | return nfs4_access_to_omode(access); |
447 | } | 390 | } |
448 | 391 | ||
449 | static void release_open_stateid(struct nfs4_stateid *stp) | 392 | static void unhash_generic_stateid(struct nfs4_stateid *stp) |
450 | { | 393 | { |
451 | int oflag = nfs4_access_bmap_to_omode(stp); | 394 | list_del(&stp->st_hash); |
395 | list_del(&stp->st_perfile); | ||
396 | list_del(&stp->st_perstateowner); | ||
397 | } | ||
452 | 398 | ||
399 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
400 | { | ||
401 | int oflag; | ||
402 | |||
403 | if (stp->st_access_bmap) { | ||
404 | oflag = nfs4_access_bmap_to_omode(stp); | ||
405 | nfs4_file_put_access(stp->st_file, oflag); | ||
406 | } | ||
407 | put_nfs4_file(stp->st_file); | ||
408 | kmem_cache_free(stateid_slab, stp); | ||
409 | } | ||
410 | |||
411 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
412 | { | ||
413 | struct file *file; | ||
414 | |||
415 | unhash_generic_stateid(stp); | ||
416 | file = find_any_file(stp->st_file); | ||
417 | if (file) | ||
418 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
419 | free_generic_stateid(stp); | ||
420 | } | ||
421 | |||
422 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
423 | { | ||
424 | struct nfs4_stateid *stp; | ||
425 | |||
426 | list_del(&sop->so_idhash); | ||
427 | list_del(&sop->so_strhash); | ||
428 | list_del(&sop->so_perstateid); | ||
429 | while (!list_empty(&sop->so_stateids)) { | ||
430 | stp = list_first_entry(&sop->so_stateids, | ||
431 | struct nfs4_stateid, st_perstateowner); | ||
432 | release_lock_stateid(stp); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
437 | { | ||
438 | unhash_lockowner(sop); | ||
439 | nfs4_put_stateowner(sop); | ||
440 | } | ||
441 | |||
442 | static void | ||
443 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
444 | { | ||
445 | struct nfs4_stateowner *lock_sop; | ||
446 | |||
447 | while (!list_empty(&open_stp->st_lockowners)) { | ||
448 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
449 | struct nfs4_stateowner, so_perstateid); | ||
450 | /* list_del(&open_stp->st_lockowners); */ | ||
451 | BUG_ON(lock_sop->so_is_open_owner); | ||
452 | release_lockowner(lock_sop); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static void release_open_stateid(struct nfs4_stateid *stp) | ||
457 | { | ||
453 | unhash_generic_stateid(stp); | 458 | unhash_generic_stateid(stp); |
454 | release_stateid_lockowners(stp); | 459 | release_stateid_lockowners(stp); |
455 | nfs4_file_put_access(stp->st_file, oflag); | ||
456 | free_generic_stateid(stp); | 460 | free_generic_stateid(stp); |
457 | } | 461 | } |
458 | 462 | ||
@@ -608,7 +612,8 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4 | |||
608 | u32 maxrpc = nfsd_serv->sv_max_mesg; | 612 | u32 maxrpc = nfsd_serv->sv_max_mesg; |
609 | 613 | ||
610 | new->maxreqs = numslots; | 614 | new->maxreqs = numslots; |
611 | new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ; | 615 | new->maxresp_cached = min_t(u32, req->maxresp_cached, |
616 | slotsize + NFSD_MIN_HDR_SEQ_SZ); | ||
612 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); | 617 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); |
613 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); | 618 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); |
614 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); | 619 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); |
@@ -3054,7 +3059,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | |||
3054 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) | 3059 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) |
3055 | return nfs_ok; | 3060 | return nfs_ok; |
3056 | else if (locks_in_grace()) { | 3061 | else if (locks_in_grace()) { |
3057 | /* Answer in remaining cases depends on existance of | 3062 | /* Answer in remaining cases depends on existence of |
3058 | * conflicting state; so we must wait out the grace period. */ | 3063 | * conflicting state; so we must wait out the grace period. */ |
3059 | return nfserr_grace; | 3064 | return nfserr_grace; |
3060 | } else if (flags & WR_STATE) | 3065 | } else if (flags & WR_STATE) |
@@ -3674,7 +3679,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, | |||
3674 | /* | 3679 | /* |
3675 | * Alloc a lock owner structure. | 3680 | * Alloc a lock owner structure. |
3676 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has | 3681 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has |
3677 | * occured. | 3682 | * occurred. |
3678 | * | 3683 | * |
3679 | * strhashval = lock_ownerstr_hashval | 3684 | * strhashval = lock_ownerstr_hashval |
3680 | */ | 3685 | */ |
@@ -3735,6 +3740,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3735 | stp->st_stateid.si_stateownerid = sop->so_id; | 3740 | stp->st_stateid.si_stateownerid = sop->so_id; |
3736 | stp->st_stateid.si_fileid = fp->fi_id; | 3741 | stp->st_stateid.si_fileid = fp->fi_id; |
3737 | stp->st_stateid.si_generation = 0; | 3742 | stp->st_stateid.si_generation = 0; |
3743 | stp->st_access_bmap = 0; | ||
3738 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3744 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3739 | stp->st_openstp = open_stp; | 3745 | stp->st_openstp = open_stp; |
3740 | 3746 | ||
@@ -3749,6 +3755,17 @@ check_lock_length(u64 offset, u64 length) | |||
3749 | LOFF_OVERFLOW(offset, length))); | 3755 | LOFF_OVERFLOW(offset, length))); |
3750 | } | 3756 | } |
3751 | 3757 | ||
3758 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) | ||
3759 | { | ||
3760 | struct nfs4_file *fp = lock_stp->st_file; | ||
3761 | int oflag = nfs4_access_to_omode(access); | ||
3762 | |||
3763 | if (test_bit(access, &lock_stp->st_access_bmap)) | ||
3764 | return; | ||
3765 | nfs4_file_get_access(fp, oflag); | ||
3766 | __set_bit(access, &lock_stp->st_access_bmap); | ||
3767 | } | ||
3768 | |||
3752 | /* | 3769 | /* |
3753 | * LOCK operation | 3770 | * LOCK operation |
3754 | */ | 3771 | */ |
@@ -3765,7 +3782,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3765 | struct file_lock conflock; | 3782 | struct file_lock conflock; |
3766 | __be32 status = 0; | 3783 | __be32 status = 0; |
3767 | unsigned int strhashval; | 3784 | unsigned int strhashval; |
3768 | unsigned int cmd; | ||
3769 | int err; | 3785 | int err; |
3770 | 3786 | ||
3771 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 3787 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -3847,22 +3863,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3847 | switch (lock->lk_type) { | 3863 | switch (lock->lk_type) { |
3848 | case NFS4_READ_LT: | 3864 | case NFS4_READ_LT: |
3849 | case NFS4_READW_LT: | 3865 | case NFS4_READW_LT: |
3850 | if (find_readable_file(lock_stp->st_file)) { | 3866 | filp = find_readable_file(lock_stp->st_file); |
3851 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); | 3867 | if (filp) |
3852 | filp = find_readable_file(lock_stp->st_file); | 3868 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
3853 | } | ||
3854 | file_lock.fl_type = F_RDLCK; | 3869 | file_lock.fl_type = F_RDLCK; |
3855 | cmd = F_SETLK; | 3870 | break; |
3856 | break; | ||
3857 | case NFS4_WRITE_LT: | 3871 | case NFS4_WRITE_LT: |
3858 | case NFS4_WRITEW_LT: | 3872 | case NFS4_WRITEW_LT: |
3859 | if (find_writeable_file(lock_stp->st_file)) { | 3873 | filp = find_writeable_file(lock_stp->st_file); |
3860 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); | 3874 | if (filp) |
3861 | filp = find_writeable_file(lock_stp->st_file); | 3875 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
3862 | } | ||
3863 | file_lock.fl_type = F_WRLCK; | 3876 | file_lock.fl_type = F_WRLCK; |
3864 | cmd = F_SETLK; | 3877 | break; |
3865 | break; | ||
3866 | default: | 3878 | default: |
3867 | status = nfserr_inval; | 3879 | status = nfserr_inval; |
3868 | goto out; | 3880 | goto out; |
@@ -3886,7 +3898,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3886 | * Note: locks.c uses the BKL to protect the inode's lock list. | 3898 | * Note: locks.c uses the BKL to protect the inode's lock list. |
3887 | */ | 3899 | */ |
3888 | 3900 | ||
3889 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); | 3901 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); |
3890 | switch (-err) { | 3902 | switch (-err) { |
3891 | case 0: /* success! */ | 3903 | case 0: /* success! */ |
3892 | update_stateid(&lock_stp->st_stateid); | 3904 | update_stateid(&lock_stp->st_stateid); |