mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 05:44:11 +00:00
hugetlbfs: fix memory leak for resv_map
[ Upstream commit 58b6e5e8f1
]
When mknod is used to create a block special file in hugetlbfs, it will
allocate an inode and kmalloc a 'struct resv_map' via resv_map_alloc().
inode->i_mapping->private_data will point the newly allocated resv_map.
However, when the device special file is opened bd_acquire() will set
inode->i_mapping to bd_inode->i_mapping. Thus the pointer to the
allocated resv_map is lost and the structure is leaked.
Programs to reproduce:
mount -t hugetlbfs nodev hugetlbfs
mknod hugetlbfs/dev b 0 0
exec 30<> hugetlbfs/dev
umount hugetlbfs/
resv_map structures are only needed for inodes which can have associated
page allocations. To fix the leak, only allocate resv_map for those
inodes which could possibly be associated with page allocations.
Link: http://lkml.kernel.org/r/20190401213101.16476-1-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Reported-by: Yufen Yu <yuyufen@huawei.com>
Suggested-by: Yufen Yu <yuyufen@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
6a62bbe823
commit
b51fdcbe45
1 changed files with 14 additions and 6 deletions
|
@ -741,11 +741,17 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
|
|||
umode_t mode, dev_t dev)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct resv_map *resv_map;
|
||||
struct resv_map *resv_map = NULL;
|
||||
|
||||
resv_map = resv_map_alloc();
|
||||
if (!resv_map)
|
||||
return NULL;
|
||||
/*
|
||||
* Reserve maps are only needed for inodes that can have associated
|
||||
* page allocations.
|
||||
*/
|
||||
if (S_ISREG(mode) || S_ISLNK(mode)) {
|
||||
resv_map = resv_map_alloc();
|
||||
if (!resv_map)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inode = new_inode(sb);
|
||||
if (inode) {
|
||||
|
@ -780,8 +786,10 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
|
|||
break;
|
||||
}
|
||||
lockdep_annotate_inode_mutex_key(inode);
|
||||
} else
|
||||
kref_put(&resv_map->refs, resv_map_release);
|
||||
} else {
|
||||
if (resv_map)
|
||||
kref_put(&resv_map->refs, resv_map_release);
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue