diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-03-02 18:01:35 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2011-03-08 19:38:27 -0500 |
commit | 0997b173609b9229ece28941c118a2a9b278796e (patch) | |
tree | 30d8c6f3846371b78a9339c5798dd59c60fa4a4c | |
parent | 529d7b2a7fa31e9f7d08bc790d232c3cbe64fa24 (diff) |
nfsd4: fix struct file leak
Make sure we properly reference count the struct files that a lock
depends on, and release them when the lock stateid is released.
This fixes a major leak of struct files when using locking over nfsv4.
Cc: stable@kernel.org
Reported-by: Rick Koshi <nfs-bug-report@more-right-rudder.com>
Tested-by: Ivo Přikryl <prikryl@eurosat.cz>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/nfs4state.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 84d2dd327b2d..c26dc31fb943 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -397,6 +397,9 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp) | |||
397 | 397 | ||
398 | static void free_generic_stateid(struct nfs4_stateid *stp) | 398 | static void free_generic_stateid(struct nfs4_stateid *stp) |
399 | { | 399 | { |
400 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
401 | |||
402 | nfs4_file_put_access(stp->st_file, oflag); | ||
400 | put_nfs4_file(stp->st_file); | 403 | put_nfs4_file(stp->st_file); |
401 | kmem_cache_free(stateid_slab, stp); | 404 | kmem_cache_free(stateid_slab, stp); |
402 | } | 405 | } |
@@ -448,11 +451,8 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
448 | 451 | ||
449 | static void release_open_stateid(struct nfs4_stateid *stp) | 452 | static void release_open_stateid(struct nfs4_stateid *stp) |
450 | { | 453 | { |
451 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
452 | |||
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 | ||
@@ -3734,6 +3734,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3734 | stp->st_stateid.si_stateownerid = sop->so_id; | 3734 | stp->st_stateid.si_stateownerid = sop->so_id; |
3735 | stp->st_stateid.si_fileid = fp->fi_id; | 3735 | stp->st_stateid.si_fileid = fp->fi_id; |
3736 | stp->st_stateid.si_generation = 0; | 3736 | stp->st_stateid.si_generation = 0; |
3737 | stp->st_access_bmap = 0; | ||
3737 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3738 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3738 | stp->st_openstp = open_stp; | 3739 | stp->st_openstp = open_stp; |
3739 | 3740 | ||
@@ -3748,6 +3749,17 @@ check_lock_length(u64 offset, u64 length) | |||
3748 | LOFF_OVERFLOW(offset, length))); | 3749 | LOFF_OVERFLOW(offset, length))); |
3749 | } | 3750 | } |
3750 | 3751 | ||
3752 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) | ||
3753 | { | ||
3754 | struct nfs4_file *fp = lock_stp->st_file; | ||
3755 | int oflag = nfs4_access_to_omode(access); | ||
3756 | |||
3757 | if (test_bit(access, &lock_stp->st_access_bmap)) | ||
3758 | return; | ||
3759 | nfs4_file_get_access(fp, oflag); | ||
3760 | __set_bit(access, &lock_stp->st_access_bmap); | ||
3761 | } | ||
3762 | |||
3751 | /* | 3763 | /* |
3752 | * LOCK operation | 3764 | * LOCK operation |
3753 | */ | 3765 | */ |
@@ -3845,18 +3857,16 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3845 | switch (lock->lk_type) { | 3857 | switch (lock->lk_type) { |
3846 | case NFS4_READ_LT: | 3858 | case NFS4_READ_LT: |
3847 | case NFS4_READW_LT: | 3859 | case NFS4_READW_LT: |
3848 | if (find_readable_file(lock_stp->st_file)) { | 3860 | filp = find_readable_file(lock_stp->st_file); |
3849 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); | 3861 | if (filp) |
3850 | filp = find_readable_file(lock_stp->st_file); | 3862 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
3851 | } | ||
3852 | file_lock.fl_type = F_RDLCK; | 3863 | file_lock.fl_type = F_RDLCK; |
3853 | break; | 3864 | break; |
3854 | case NFS4_WRITE_LT: | 3865 | case NFS4_WRITE_LT: |
3855 | case NFS4_WRITEW_LT: | 3866 | case NFS4_WRITEW_LT: |
3856 | if (find_writeable_file(lock_stp->st_file)) { | 3867 | filp = find_writeable_file(lock_stp->st_file); |
3857 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); | 3868 | if (filp) |
3858 | filp = find_writeable_file(lock_stp->st_file); | 3869 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
3859 | } | ||
3860 | file_lock.fl_type = F_WRLCK; | 3870 | file_lock.fl_type = F_WRLCK; |
3861 | break; | 3871 | break; |
3862 | default: | 3872 | default: |