1 From dde1a87702117a783e5157251893a18997544113 Mon Sep 17 00:00:00 2001
2 From: Mike Kravetz <mike.kravetz@oracle.com>
3 Date: Fri, 5 Apr 2019 18:39:06 -0700
4 Subject: hugetlbfs: fix memory leak for resv_map
6 [ Upstream commit 58b6e5e8f1addd44583d61b0a03c0f5519527e35 ]
8 When mknod is used to create a block special file in hugetlbfs, it will
9 allocate an inode and kmalloc a 'struct resv_map' via resv_map_alloc().
10 inode->i_mapping->private_data will point the newly allocated resv_map.
11 However, when the device special file is opened bd_acquire() will set
12 inode->i_mapping to bd_inode->i_mapping. Thus the pointer to the
13 allocated resv_map is lost and the structure is leaked.
15 Programs to reproduce:
16 mount -t hugetlbfs nodev hugetlbfs
17 mknod hugetlbfs/dev b 0 0
18 exec 30<> hugetlbfs/dev
21 resv_map structures are only needed for inodes which can have associated
22 page allocations. To fix the leak, only allocate resv_map for those
23 inodes which could possibly be associated with page allocations.
25 Link: http://lkml.kernel.org/r/20190401213101.16476-1-mike.kravetz@oracle.com
26 Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
27 Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
28 Reported-by: Yufen Yu <yuyufen@huawei.com>
29 Suggested-by: Yufen Yu <yuyufen@huawei.com>
30 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
31 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
32 Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
34 fs/hugetlbfs/inode.c | 20 ++++++++++++++------
35 1 file changed, 14 insertions(+), 6 deletions(-)
37 diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
38 index a7fa037b876b..a3a3d256fb0e 100644
39 --- a/fs/hugetlbfs/inode.c
40 +++ b/fs/hugetlbfs/inode.c
41 @@ -741,11 +741,17 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
42 umode_t mode, dev_t dev)
45 - struct resv_map *resv_map;
46 + struct resv_map *resv_map = NULL;
48 - resv_map = resv_map_alloc();
52 + * Reserve maps are only needed for inodes that can have associated
55 + if (S_ISREG(mode) || S_ISLNK(mode)) {
56 + resv_map = resv_map_alloc();
61 inode = new_inode(sb);
63 @@ -780,8 +786,10 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
66 lockdep_annotate_inode_mutex_key(inode);
68 - kref_put(&resv_map->refs, resv_map_release);
71 + kref_put(&resv_map->refs, resv_map_release);