diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 160 |
1 files changed, 84 insertions, 76 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7b566ec14e1..fbde6f79922 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) |
@@ -316,64 +316,6 @@ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | |||
316 | static struct list_head client_lru; | 316 | static struct list_head client_lru; |
317 | static struct list_head close_lru; | 317 | static struct list_head close_lru; |
318 | 318 | ||
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 | /* | 319 | /* |
378 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 320 | * 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 | 321 | * st_{access,deny}_bmap field of the stateid, in order to track not |
@@ -446,13 +388,71 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | |||
446 | return nfs4_access_to_omode(access); | 388 | return nfs4_access_to_omode(access); |
447 | } | 389 | } |
448 | 390 | ||
449 | static void release_open_stateid(struct nfs4_stateid *stp) | 391 | static void unhash_generic_stateid(struct nfs4_stateid *stp) |
392 | { | ||
393 | list_del(&stp->st_hash); | ||
394 | list_del(&stp->st_perfile); | ||
395 | list_del(&stp->st_perstateowner); | ||
396 | } | ||
397 | |||
398 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
450 | { | 399 | { |
451 | int oflag = nfs4_access_bmap_to_omode(stp); | 400 | int oflag = nfs4_access_bmap_to_omode(stp); |
452 | 401 | ||
402 | nfs4_file_put_access(stp->st_file, oflag); | ||
403 | put_nfs4_file(stp->st_file); | ||
404 | kmem_cache_free(stateid_slab, stp); | ||
405 | } | ||
406 | |||
407 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
408 | { | ||
409 | struct file *file; | ||
410 | |||
411 | unhash_generic_stateid(stp); | ||
412 | file = find_any_file(stp->st_file); | ||
413 | if (file) | ||
414 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
415 | free_generic_stateid(stp); | ||
416 | } | ||
417 | |||
418 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
419 | { | ||
420 | struct nfs4_stateid *stp; | ||
421 | |||
422 | list_del(&sop->so_idhash); | ||
423 | list_del(&sop->so_strhash); | ||
424 | list_del(&sop->so_perstateid); | ||
425 | while (!list_empty(&sop->so_stateids)) { | ||
426 | stp = list_first_entry(&sop->so_stateids, | ||
427 | struct nfs4_stateid, st_perstateowner); | ||
428 | release_lock_stateid(stp); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
433 | { | ||
434 | unhash_lockowner(sop); | ||
435 | nfs4_put_stateowner(sop); | ||
436 | } | ||
437 | |||
438 | static void | ||
439 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
440 | { | ||
441 | struct nfs4_stateowner *lock_sop; | ||
442 | |||
443 | while (!list_empty(&open_stp->st_lockowners)) { | ||
444 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
445 | struct nfs4_stateowner, so_perstateid); | ||
446 | /* list_del(&open_stp->st_lockowners); */ | ||
447 | BUG_ON(lock_sop->so_is_open_owner); | ||
448 | release_lockowner(lock_sop); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static void release_open_stateid(struct nfs4_stateid *stp) | ||
453 | { | ||
453 | unhash_generic_stateid(stp); | 454 | unhash_generic_stateid(stp); |
454 | release_stateid_lockowners(stp); | 455 | release_stateid_lockowners(stp); |
455 | nfs4_file_put_access(stp->st_file, oflag); | ||
456 | free_generic_stateid(stp); | 456 | free_generic_stateid(stp); |
457 | } | 457 | } |
458 | 458 | ||
@@ -608,7 +608,8 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4 | |||
608 | u32 maxrpc = nfsd_serv->sv_max_mesg; | 608 | u32 maxrpc = nfsd_serv->sv_max_mesg; |
609 | 609 | ||
610 | new->maxreqs = numslots; | 610 | new->maxreqs = numslots; |
611 | new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ; | 611 | new->maxresp_cached = min_t(u32, req->maxresp_cached, |
612 | slotsize + NFSD_MIN_HDR_SEQ_SZ); | ||
612 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); | 613 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); |
613 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); | 614 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); |
614 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); | 615 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); |
@@ -3735,6 +3736,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3735 | stp->st_stateid.si_stateownerid = sop->so_id; | 3736 | stp->st_stateid.si_stateownerid = sop->so_id; |
3736 | stp->st_stateid.si_fileid = fp->fi_id; | 3737 | stp->st_stateid.si_fileid = fp->fi_id; |
3737 | stp->st_stateid.si_generation = 0; | 3738 | stp->st_stateid.si_generation = 0; |
3739 | stp->st_access_bmap = 0; | ||
3738 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3740 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3739 | stp->st_openstp = open_stp; | 3741 | stp->st_openstp = open_stp; |
3740 | 3742 | ||
@@ -3749,6 +3751,17 @@ check_lock_length(u64 offset, u64 length) | |||
3749 | LOFF_OVERFLOW(offset, length))); | 3751 | LOFF_OVERFLOW(offset, length))); |
3750 | } | 3752 | } |
3751 | 3753 | ||
3754 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) | ||
3755 | { | ||
3756 | struct nfs4_file *fp = lock_stp->st_file; | ||
3757 | int oflag = nfs4_access_to_omode(access); | ||
3758 | |||
3759 | if (test_bit(access, &lock_stp->st_access_bmap)) | ||
3760 | return; | ||
3761 | nfs4_file_get_access(fp, oflag); | ||
3762 | __set_bit(access, &lock_stp->st_access_bmap); | ||
3763 | } | ||
3764 | |||
3752 | /* | 3765 | /* |
3753 | * LOCK operation | 3766 | * LOCK operation |
3754 | */ | 3767 | */ |
@@ -3765,7 +3778,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3765 | struct file_lock conflock; | 3778 | struct file_lock conflock; |
3766 | __be32 status = 0; | 3779 | __be32 status = 0; |
3767 | unsigned int strhashval; | 3780 | unsigned int strhashval; |
3768 | unsigned int cmd; | ||
3769 | int err; | 3781 | int err; |
3770 | 3782 | ||
3771 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 3783 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -3847,22 +3859,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3847 | switch (lock->lk_type) { | 3859 | switch (lock->lk_type) { |
3848 | case NFS4_READ_LT: | 3860 | case NFS4_READ_LT: |
3849 | case NFS4_READW_LT: | 3861 | case NFS4_READW_LT: |
3850 | if (find_readable_file(lock_stp->st_file)) { | 3862 | filp = find_readable_file(lock_stp->st_file); |
3851 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); | 3863 | if (filp) |
3852 | filp = find_readable_file(lock_stp->st_file); | 3864 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
3853 | } | ||
3854 | file_lock.fl_type = F_RDLCK; | 3865 | file_lock.fl_type = F_RDLCK; |
3855 | cmd = F_SETLK; | 3866 | break; |
3856 | break; | ||
3857 | case NFS4_WRITE_LT: | 3867 | case NFS4_WRITE_LT: |
3858 | case NFS4_WRITEW_LT: | 3868 | case NFS4_WRITEW_LT: |
3859 | if (find_writeable_file(lock_stp->st_file)) { | 3869 | filp = find_writeable_file(lock_stp->st_file); |
3860 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); | 3870 | if (filp) |
3861 | filp = find_writeable_file(lock_stp->st_file); | 3871 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
3862 | } | ||
3863 | file_lock.fl_type = F_WRLCK; | 3872 | file_lock.fl_type = F_WRLCK; |
3864 | cmd = F_SETLK; | 3873 | break; |
3865 | break; | ||
3866 | default: | 3874 | default: |
3867 | status = nfserr_inval; | 3875 | status = nfserr_inval; |
3868 | goto out; | 3876 | goto out; |
@@ -3886,7 +3894,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. | 3894 | * Note: locks.c uses the BKL to protect the inode's lock list. |
3887 | */ | 3895 | */ |
3888 | 3896 | ||
3889 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); | 3897 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); |
3890 | switch (-err) { | 3898 | switch (-err) { |
3891 | case 0: /* success! */ | 3899 | case 0: /* success! */ |
3892 | update_stateid(&lock_stp->st_stateid); | 3900 | update_stateid(&lock_stp->st_stateid); |