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: | 
