aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-03-02 18:01:35 -0500
committerJ. Bruce Fields <bfields@redhat.com>2011-03-08 19:38:27 -0500
commit0997b173609b9229ece28941c118a2a9b278796e (patch)
tree30d8c6f3846371b78a9339c5798dd59c60fa4a4c
parent529d7b2a7fa31e9f7d08bc790d232c3cbe64fa24 (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.c32
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
398static void free_generic_stateid(struct nfs4_stateid *stp) 398static 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
449static void release_open_stateid(struct nfs4_stateid *stp) 452static 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
3752static 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: