| From f71ffed544b7a962554e1b809ed63b1527deb695 Mon Sep 17 00:00:00 2001 |
| From: Mike Kravetz <mike.kravetz@oracle.com> |
| Date: Sat, 30 Nov 2019 17:56:34 -0800 |
| Subject: [PATCH] mm/hugetlbfs: fix error handling when setting up mounts |
| |
| commit 8fc312b32b25c6b0a8b46fab4df8c68df5af1223 upstream. |
| |
| It is assumed that the hugetlbfs_vfsmount[] array will contain either a |
| valid vfsmount pointer or NULL for each hstate after initialization. |
| Changes made while converting to use fs_context broke this assumption. |
| |
| While fixing the hugetlbfs_vfsmount issue, it was discovered that |
| init_hugetlbfs_fs never did correctly clean up when encountering a vfs |
| mount error. |
| |
| It was found during code inspection. A small memory allocation failure |
| would be the most likely cause of taking a error path with the bug. |
| This is unlikely to happen as this is early init code. |
| |
| Link: http://lkml.kernel.org/r/94b6244d-2c24-e269-b12c-e3ba694b242d@oracle.com |
| Reported-by: Chengguang Xu <cgxu519@mykernel.net> |
| Fixes: 32021982a324 ("hugetlbfs: Convert to fs_context") |
| Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> |
| Cc: David Howells <dhowells@redhat.com> |
| Cc: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c |
| index 1dcc57189382..c4f9b9a1def1 100644 |
| --- a/fs/hugetlbfs/inode.c |
| +++ b/fs/hugetlbfs/inode.c |
| @@ -1461,28 +1461,41 @@ static int __init init_hugetlbfs_fs(void) |
| sizeof(struct hugetlbfs_inode_info), |
| 0, SLAB_ACCOUNT, init_once); |
| if (hugetlbfs_inode_cachep == NULL) |
| - goto out2; |
| + goto out; |
| |
| error = register_filesystem(&hugetlbfs_fs_type); |
| if (error) |
| - goto out; |
| + goto out_free; |
| |
| + /* default hstate mount is required */ |
| + mnt = mount_one_hugetlbfs(&hstates[default_hstate_idx]); |
| + if (IS_ERR(mnt)) { |
| + error = PTR_ERR(mnt); |
| + goto out_unreg; |
| + } |
| + hugetlbfs_vfsmount[default_hstate_idx] = mnt; |
| + |
| + /* other hstates are optional */ |
| i = 0; |
| for_each_hstate(h) { |
| + if (i == default_hstate_idx) |
| + continue; |
| + |
| mnt = mount_one_hugetlbfs(h); |
| - if (IS_ERR(mnt) && i == 0) { |
| - error = PTR_ERR(mnt); |
| - goto out; |
| - } |
| - hugetlbfs_vfsmount[i] = mnt; |
| + if (IS_ERR(mnt)) |
| + hugetlbfs_vfsmount[i] = NULL; |
| + else |
| + hugetlbfs_vfsmount[i] = mnt; |
| i++; |
| } |
| |
| return 0; |
| |
| - out: |
| + out_unreg: |
| + (void)unregister_filesystem(&hugetlbfs_fs_type); |
| + out_free: |
| kmem_cache_destroy(hugetlbfs_inode_cachep); |
| - out2: |
| + out: |
| return error; |
| } |
| fs_initcall(init_hugetlbfs_fs) |
| -- |
| 2.7.4 |
| |