diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:08:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:08:19 -0400 |
commit | 7b47a9e7c8f672b6fb0b77fca11a63a8a77f5a91 (patch) | |
tree | cf05645120ba2323c36acefdea6e62addf320f8c /fs/hugetlbfs | |
parent | dbc2fba3fc46084f502aec53183995a632998dcd (diff) | |
parent | c99c2171fc61476afac0dfb59fb2c447a01fb1e0 (diff) |
Merge branch 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs mount infrastructure updates from Al Viro:
"The rest of core infrastructure; no new syscalls in that pile, but the
old parts are switched to new infrastructure. At that point
conversions of individual filesystems can happen independently; some
are done here (afs, cgroup, procfs, etc.), there's also a large series
outside of that pile dealing with NFS (quite a bit of option-parsing
stuff is getting used there - it's one of the most convoluted
filesystems in terms of mount-related logics), but NFS bits are the
next cycle fodder.
It got seriously simplified since the last cycle; documentation is
probably the weakest bit at the moment - I considered dropping the
commit introducing Documentation/filesystems/mount_api.txt (cutting
the size increase by quarter ;-), but decided that it would be better
to fix it up after -rc1 instead.
That pile allows to do followup work in independent branches, which
should make life much easier for the next cycle. fs/super.c size
increase is unpleasant; there's a followup series that allows to
shrink it considerably, but I decided to leave that until the next
cycle"
* 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (41 commits)
afs: Use fs_context to pass parameters over automount
afs: Add fs_context support
vfs: Add some logging to the core users of the fs_context log
vfs: Implement logging through fs_context
vfs: Provide documentation for new mount API
vfs: Remove kern_mount_data()
hugetlbfs: Convert to fs_context
cpuset: Use fs_context
kernfs, sysfs, cgroup, intel_rdt: Support fs_context
cgroup: store a reference to cgroup_ns into cgroup_fs_context
cgroup1_get_tree(): separate "get cgroup_root to use" into a separate helper
cgroup_do_mount(): massage calling conventions
cgroup: stash cgroup_root reference into cgroup_fs_context
cgroup2: switch to option-by-option parsing
cgroup1: switch to option-by-option parsing
cgroup: take options parsing into ->parse_monolithic()
cgroup: fold cgroup1_mount() into cgroup1_get_tree()
cgroup: start switching to fs_context
ipc: Convert mqueue fs to fs_context
proc: Add fs_context support to procfs
...
Diffstat (limited to 'fs/hugetlbfs')
-rw-r--r-- | fs/hugetlbfs/inode.c | 358 |
1 files changed, 200 insertions, 158 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b0eef008de67..ec32fece5e1e 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/backing-dev.h> | 27 | #include <linux/backing-dev.h> |
28 | #include <linux/hugetlb.h> | 28 | #include <linux/hugetlb.h> |
29 | #include <linux/pagevec.h> | 29 | #include <linux/pagevec.h> |
30 | #include <linux/parser.h> | 30 | #include <linux/fs_parser.h> |
31 | #include <linux/mman.h> | 31 | #include <linux/mman.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/dnotify.h> | 33 | #include <linux/dnotify.h> |
@@ -45,11 +45,17 @@ const struct file_operations hugetlbfs_file_operations; | |||
45 | static const struct inode_operations hugetlbfs_dir_inode_operations; | 45 | static const struct inode_operations hugetlbfs_dir_inode_operations; |
46 | static const struct inode_operations hugetlbfs_inode_operations; | 46 | static const struct inode_operations hugetlbfs_inode_operations; |
47 | 47 | ||
48 | struct hugetlbfs_config { | 48 | enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT }; |
49 | |||
50 | struct hugetlbfs_fs_context { | ||
49 | struct hstate *hstate; | 51 | struct hstate *hstate; |
52 | unsigned long long max_size_opt; | ||
53 | unsigned long long min_size_opt; | ||
50 | long max_hpages; | 54 | long max_hpages; |
51 | long nr_inodes; | 55 | long nr_inodes; |
52 | long min_hpages; | 56 | long min_hpages; |
57 | enum hugetlbfs_size_type max_val_type; | ||
58 | enum hugetlbfs_size_type min_val_type; | ||
53 | kuid_t uid; | 59 | kuid_t uid; |
54 | kgid_t gid; | 60 | kgid_t gid; |
55 | umode_t mode; | 61 | umode_t mode; |
@@ -57,22 +63,30 @@ struct hugetlbfs_config { | |||
57 | 63 | ||
58 | int sysctl_hugetlb_shm_group; | 64 | int sysctl_hugetlb_shm_group; |
59 | 65 | ||
60 | enum { | 66 | enum hugetlb_param { |
61 | Opt_size, Opt_nr_inodes, | 67 | Opt_gid, |
62 | Opt_mode, Opt_uid, Opt_gid, | 68 | Opt_min_size, |
63 | Opt_pagesize, Opt_min_size, | 69 | Opt_mode, |
64 | Opt_err, | 70 | Opt_nr_inodes, |
71 | Opt_pagesize, | ||
72 | Opt_size, | ||
73 | Opt_uid, | ||
65 | }; | 74 | }; |
66 | 75 | ||
67 | static const match_table_t tokens = { | 76 | static const struct fs_parameter_spec hugetlb_param_specs[] = { |
68 | {Opt_size, "size=%s"}, | 77 | fsparam_u32 ("gid", Opt_gid), |
69 | {Opt_nr_inodes, "nr_inodes=%s"}, | 78 | fsparam_string("min_size", Opt_min_size), |
70 | {Opt_mode, "mode=%o"}, | 79 | fsparam_u32 ("mode", Opt_mode), |
71 | {Opt_uid, "uid=%u"}, | 80 | fsparam_string("nr_inodes", Opt_nr_inodes), |
72 | {Opt_gid, "gid=%u"}, | 81 | fsparam_string("pagesize", Opt_pagesize), |
73 | {Opt_pagesize, "pagesize=%s"}, | 82 | fsparam_string("size", Opt_size), |
74 | {Opt_min_size, "min_size=%s"}, | 83 | fsparam_u32 ("uid", Opt_uid), |
75 | {Opt_err, NULL}, | 84 | {} |
85 | }; | ||
86 | |||
87 | static const struct fs_parameter_description hugetlb_fs_parameters = { | ||
88 | .name = "hugetlbfs", | ||
89 | .specs = hugetlb_param_specs, | ||
76 | }; | 90 | }; |
77 | 91 | ||
78 | #ifdef CONFIG_NUMA | 92 | #ifdef CONFIG_NUMA |
@@ -708,16 +722,16 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
708 | } | 722 | } |
709 | 723 | ||
710 | static struct inode *hugetlbfs_get_root(struct super_block *sb, | 724 | static struct inode *hugetlbfs_get_root(struct super_block *sb, |
711 | struct hugetlbfs_config *config) | 725 | struct hugetlbfs_fs_context *ctx) |
712 | { | 726 | { |
713 | struct inode *inode; | 727 | struct inode *inode; |
714 | 728 | ||
715 | inode = new_inode(sb); | 729 | inode = new_inode(sb); |
716 | if (inode) { | 730 | if (inode) { |
717 | inode->i_ino = get_next_ino(); | 731 | inode->i_ino = get_next_ino(); |
718 | inode->i_mode = S_IFDIR | config->mode; | 732 | inode->i_mode = S_IFDIR | ctx->mode; |
719 | inode->i_uid = config->uid; | 733 | inode->i_uid = ctx->uid; |
720 | inode->i_gid = config->gid; | 734 | inode->i_gid = ctx->gid; |
721 | inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); | 735 | inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); |
722 | inode->i_op = &hugetlbfs_dir_inode_operations; | 736 | inode->i_op = &hugetlbfs_dir_inode_operations; |
723 | inode->i_fop = &simple_dir_operations; | 737 | inode->i_fop = &simple_dir_operations; |
@@ -1093,8 +1107,6 @@ static const struct super_operations hugetlbfs_ops = { | |||
1093 | .show_options = hugetlbfs_show_options, | 1107 | .show_options = hugetlbfs_show_options, |
1094 | }; | 1108 | }; |
1095 | 1109 | ||
1096 | enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT }; | ||
1097 | |||
1098 | /* | 1110 | /* |
1099 | * Convert size option passed from command line to number of huge pages | 1111 | * Convert size option passed from command line to number of huge pages |
1100 | * in the pool specified by hstate. Size option could be in bytes | 1112 | * in the pool specified by hstate. Size option could be in bytes |
@@ -1117,170 +1129,151 @@ hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt, | |||
1117 | return size_opt; | 1129 | return size_opt; |
1118 | } | 1130 | } |
1119 | 1131 | ||
1120 | static int | 1132 | /* |
1121 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | 1133 | * Parse one mount parameter. |
1134 | */ | ||
1135 | static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *param) | ||
1122 | { | 1136 | { |
1123 | char *p, *rest; | 1137 | struct hugetlbfs_fs_context *ctx = fc->fs_private; |
1124 | substring_t args[MAX_OPT_ARGS]; | 1138 | struct fs_parse_result result; |
1125 | int option; | 1139 | char *rest; |
1126 | unsigned long long max_size_opt = 0, min_size_opt = 0; | 1140 | unsigned long ps; |
1127 | enum hugetlbfs_size_type max_val_type = NO_SIZE, min_val_type = NO_SIZE; | 1141 | int opt; |
1128 | 1142 | ||
1129 | if (!options) | 1143 | opt = fs_parse(fc, &hugetlb_fs_parameters, param, &result); |
1144 | if (opt < 0) | ||
1145 | return opt; | ||
1146 | |||
1147 | switch (opt) { | ||
1148 | case Opt_uid: | ||
1149 | ctx->uid = make_kuid(current_user_ns(), result.uint_32); | ||
1150 | if (!uid_valid(ctx->uid)) | ||
1151 | goto bad_val; | ||
1130 | return 0; | 1152 | return 0; |
1131 | 1153 | ||
1132 | while ((p = strsep(&options, ",")) != NULL) { | 1154 | case Opt_gid: |
1133 | int token; | 1155 | ctx->gid = make_kgid(current_user_ns(), result.uint_32); |
1134 | if (!*p) | 1156 | if (!gid_valid(ctx->gid)) |
1135 | continue; | 1157 | goto bad_val; |
1158 | return 0; | ||
1136 | 1159 | ||
1137 | token = match_token(p, tokens, args); | 1160 | case Opt_mode: |
1138 | switch (token) { | 1161 | ctx->mode = result.uint_32 & 01777U; |
1139 | case Opt_uid: | 1162 | return 0; |
1140 | if (match_int(&args[0], &option)) | ||
1141 | goto bad_val; | ||
1142 | pconfig->uid = make_kuid(current_user_ns(), option); | ||
1143 | if (!uid_valid(pconfig->uid)) | ||
1144 | goto bad_val; | ||
1145 | break; | ||
1146 | 1163 | ||
1147 | case Opt_gid: | 1164 | case Opt_size: |
1148 | if (match_int(&args[0], &option)) | 1165 | /* memparse() will accept a K/M/G without a digit */ |
1149 | goto bad_val; | 1166 | if (!isdigit(param->string[0])) |
1150 | pconfig->gid = make_kgid(current_user_ns(), option); | 1167 | goto bad_val; |
1151 | if (!gid_valid(pconfig->gid)) | 1168 | ctx->max_size_opt = memparse(param->string, &rest); |
1152 | goto bad_val; | 1169 | ctx->max_val_type = SIZE_STD; |
1153 | break; | 1170 | if (*rest == '%') |
1171 | ctx->max_val_type = SIZE_PERCENT; | ||
1172 | return 0; | ||
1154 | 1173 | ||
1155 | case Opt_mode: | 1174 | case Opt_nr_inodes: |
1156 | if (match_octal(&args[0], &option)) | 1175 | /* memparse() will accept a K/M/G without a digit */ |
1157 | goto bad_val; | 1176 | if (!isdigit(param->string[0])) |
1158 | pconfig->mode = option & 01777U; | 1177 | goto bad_val; |
1159 | break; | 1178 | ctx->nr_inodes = memparse(param->string, &rest); |
1179 | return 0; | ||
1160 | 1180 | ||
1161 | case Opt_size: { | 1181 | case Opt_pagesize: |
1162 | /* memparse() will accept a K/M/G without a digit */ | 1182 | ps = memparse(param->string, &rest); |
1163 | if (!isdigit(*args[0].from)) | 1183 | ctx->hstate = size_to_hstate(ps); |
1164 | goto bad_val; | 1184 | if (!ctx->hstate) { |
1165 | max_size_opt = memparse(args[0].from, &rest); | 1185 | pr_err("Unsupported page size %lu MB\n", ps >> 20); |
1166 | max_val_type = SIZE_STD; | 1186 | return -EINVAL; |
1167 | if (*rest == '%') | ||
1168 | max_val_type = SIZE_PERCENT; | ||
1169 | break; | ||
1170 | } | 1187 | } |
1188 | return 0; | ||
1171 | 1189 | ||
1172 | case Opt_nr_inodes: | 1190 | case Opt_min_size: |
1173 | /* memparse() will accept a K/M/G without a digit */ | 1191 | /* memparse() will accept a K/M/G without a digit */ |
1174 | if (!isdigit(*args[0].from)) | 1192 | if (!isdigit(param->string[0])) |
1175 | goto bad_val; | 1193 | goto bad_val; |
1176 | pconfig->nr_inodes = memparse(args[0].from, &rest); | 1194 | ctx->min_size_opt = memparse(param->string, &rest); |
1177 | break; | 1195 | ctx->min_val_type = SIZE_STD; |
1196 | if (*rest == '%') | ||
1197 | ctx->min_val_type = SIZE_PERCENT; | ||
1198 | return 0; | ||
1178 | 1199 | ||
1179 | case Opt_pagesize: { | 1200 | default: |
1180 | unsigned long ps; | 1201 | return -EINVAL; |
1181 | ps = memparse(args[0].from, &rest); | 1202 | } |
1182 | pconfig->hstate = size_to_hstate(ps); | ||
1183 | if (!pconfig->hstate) { | ||
1184 | pr_err("Unsupported page size %lu MB\n", | ||
1185 | ps >> 20); | ||
1186 | return -EINVAL; | ||
1187 | } | ||
1188 | break; | ||
1189 | } | ||
1190 | 1203 | ||
1191 | case Opt_min_size: { | 1204 | bad_val: |
1192 | /* memparse() will accept a K/M/G without a digit */ | 1205 | return invalf(fc, "hugetlbfs: Bad value '%s' for mount option '%s'\n", |
1193 | if (!isdigit(*args[0].from)) | 1206 | param->string, param->key); |
1194 | goto bad_val; | 1207 | } |
1195 | min_size_opt = memparse(args[0].from, &rest); | ||
1196 | min_val_type = SIZE_STD; | ||
1197 | if (*rest == '%') | ||
1198 | min_val_type = SIZE_PERCENT; | ||
1199 | break; | ||
1200 | } | ||
1201 | 1208 | ||
1202 | default: | 1209 | /* |
1203 | pr_err("Bad mount option: \"%s\"\n", p); | 1210 | * Validate the parsed options. |
1204 | return -EINVAL; | 1211 | */ |
1205 | break; | 1212 | static int hugetlbfs_validate(struct fs_context *fc) |
1206 | } | 1213 | { |
1207 | } | 1214 | struct hugetlbfs_fs_context *ctx = fc->fs_private; |
1208 | 1215 | ||
1209 | /* | 1216 | /* |
1210 | * Use huge page pool size (in hstate) to convert the size | 1217 | * Use huge page pool size (in hstate) to convert the size |
1211 | * options to number of huge pages. If NO_SIZE, -1 is returned. | 1218 | * options to number of huge pages. If NO_SIZE, -1 is returned. |
1212 | */ | 1219 | */ |
1213 | pconfig->max_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, | 1220 | ctx->max_hpages = hugetlbfs_size_to_hpages(ctx->hstate, |
1214 | max_size_opt, max_val_type); | 1221 | ctx->max_size_opt, |
1215 | pconfig->min_hpages = hugetlbfs_size_to_hpages(pconfig->hstate, | 1222 | ctx->max_val_type); |
1216 | min_size_opt, min_val_type); | 1223 | ctx->min_hpages = hugetlbfs_size_to_hpages(ctx->hstate, |
1224 | ctx->min_size_opt, | ||
1225 | ctx->min_val_type); | ||
1217 | 1226 | ||
1218 | /* | 1227 | /* |
1219 | * If max_size was specified, then min_size must be smaller | 1228 | * If max_size was specified, then min_size must be smaller |
1220 | */ | 1229 | */ |
1221 | if (max_val_type > NO_SIZE && | 1230 | if (ctx->max_val_type > NO_SIZE && |
1222 | pconfig->min_hpages > pconfig->max_hpages) { | 1231 | ctx->min_hpages > ctx->max_hpages) { |
1223 | pr_err("minimum size can not be greater than maximum size\n"); | 1232 | pr_err("Minimum size can not be greater than maximum size\n"); |
1224 | return -EINVAL; | 1233 | return -EINVAL; |
1225 | } | 1234 | } |
1226 | 1235 | ||
1227 | return 0; | 1236 | return 0; |
1228 | |||
1229 | bad_val: | ||
1230 | pr_err("Bad value '%s' for mount option '%s'\n", args[0].from, p); | ||
1231 | return -EINVAL; | ||
1232 | } | 1237 | } |
1233 | 1238 | ||
1234 | static int | 1239 | static int |
1235 | hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) | 1240 | hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc) |
1236 | { | 1241 | { |
1237 | int ret; | 1242 | struct hugetlbfs_fs_context *ctx = fc->fs_private; |
1238 | struct hugetlbfs_config config; | ||
1239 | struct hugetlbfs_sb_info *sbinfo; | 1243 | struct hugetlbfs_sb_info *sbinfo; |
1240 | 1244 | ||
1241 | config.max_hpages = -1; /* No limit on size by default */ | ||
1242 | config.nr_inodes = -1; /* No limit on number of inodes by default */ | ||
1243 | config.uid = current_fsuid(); | ||
1244 | config.gid = current_fsgid(); | ||
1245 | config.mode = 0755; | ||
1246 | config.hstate = &default_hstate; | ||
1247 | config.min_hpages = -1; /* No default minimum size */ | ||
1248 | ret = hugetlbfs_parse_options(data, &config); | ||
1249 | if (ret) | ||
1250 | return ret; | ||
1251 | |||
1252 | sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); | 1245 | sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); |
1253 | if (!sbinfo) | 1246 | if (!sbinfo) |
1254 | return -ENOMEM; | 1247 | return -ENOMEM; |
1255 | sb->s_fs_info = sbinfo; | 1248 | sb->s_fs_info = sbinfo; |
1256 | sbinfo->hstate = config.hstate; | ||
1257 | spin_lock_init(&sbinfo->stat_lock); | 1249 | spin_lock_init(&sbinfo->stat_lock); |
1258 | sbinfo->max_inodes = config.nr_inodes; | 1250 | sbinfo->hstate = ctx->hstate; |
1259 | sbinfo->free_inodes = config.nr_inodes; | 1251 | sbinfo->max_inodes = ctx->nr_inodes; |
1260 | sbinfo->spool = NULL; | 1252 | sbinfo->free_inodes = ctx->nr_inodes; |
1261 | sbinfo->uid = config.uid; | 1253 | sbinfo->spool = NULL; |
1262 | sbinfo->gid = config.gid; | 1254 | sbinfo->uid = ctx->uid; |
1263 | sbinfo->mode = config.mode; | 1255 | sbinfo->gid = ctx->gid; |
1256 | sbinfo->mode = ctx->mode; | ||
1264 | 1257 | ||
1265 | /* | 1258 | /* |
1266 | * Allocate and initialize subpool if maximum or minimum size is | 1259 | * Allocate and initialize subpool if maximum or minimum size is |
1267 | * specified. Any needed reservations (for minimim size) are taken | 1260 | * specified. Any needed reservations (for minimim size) are taken |
1268 | * taken when the subpool is created. | 1261 | * taken when the subpool is created. |
1269 | */ | 1262 | */ |
1270 | if (config.max_hpages != -1 || config.min_hpages != -1) { | 1263 | if (ctx->max_hpages != -1 || ctx->min_hpages != -1) { |
1271 | sbinfo->spool = hugepage_new_subpool(config.hstate, | 1264 | sbinfo->spool = hugepage_new_subpool(ctx->hstate, |
1272 | config.max_hpages, | 1265 | ctx->max_hpages, |
1273 | config.min_hpages); | 1266 | ctx->min_hpages); |
1274 | if (!sbinfo->spool) | 1267 | if (!sbinfo->spool) |
1275 | goto out_free; | 1268 | goto out_free; |
1276 | } | 1269 | } |
1277 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1270 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
1278 | sb->s_blocksize = huge_page_size(config.hstate); | 1271 | sb->s_blocksize = huge_page_size(ctx->hstate); |
1279 | sb->s_blocksize_bits = huge_page_shift(config.hstate); | 1272 | sb->s_blocksize_bits = huge_page_shift(ctx->hstate); |
1280 | sb->s_magic = HUGETLBFS_MAGIC; | 1273 | sb->s_magic = HUGETLBFS_MAGIC; |
1281 | sb->s_op = &hugetlbfs_ops; | 1274 | sb->s_op = &hugetlbfs_ops; |
1282 | sb->s_time_gran = 1; | 1275 | sb->s_time_gran = 1; |
1283 | sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config)); | 1276 | sb->s_root = d_make_root(hugetlbfs_get_root(sb, ctx)); |
1284 | if (!sb->s_root) | 1277 | if (!sb->s_root) |
1285 | goto out_free; | 1278 | goto out_free; |
1286 | return 0; | 1279 | return 0; |
@@ -1290,16 +1283,52 @@ out_free: | |||
1290 | return -ENOMEM; | 1283 | return -ENOMEM; |
1291 | } | 1284 | } |
1292 | 1285 | ||
1293 | static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type, | 1286 | static int hugetlbfs_get_tree(struct fs_context *fc) |
1294 | int flags, const char *dev_name, void *data) | 1287 | { |
1288 | int err = hugetlbfs_validate(fc); | ||
1289 | if (err) | ||
1290 | return err; | ||
1291 | return vfs_get_super(fc, vfs_get_independent_super, hugetlbfs_fill_super); | ||
1292 | } | ||
1293 | |||
1294 | static void hugetlbfs_fs_context_free(struct fs_context *fc) | ||
1295 | { | ||
1296 | kfree(fc->fs_private); | ||
1297 | } | ||
1298 | |||
1299 | static const struct fs_context_operations hugetlbfs_fs_context_ops = { | ||
1300 | .free = hugetlbfs_fs_context_free, | ||
1301 | .parse_param = hugetlbfs_parse_param, | ||
1302 | .get_tree = hugetlbfs_get_tree, | ||
1303 | }; | ||
1304 | |||
1305 | static int hugetlbfs_init_fs_context(struct fs_context *fc) | ||
1295 | { | 1306 | { |
1296 | return mount_nodev(fs_type, flags, data, hugetlbfs_fill_super); | 1307 | struct hugetlbfs_fs_context *ctx; |
1308 | |||
1309 | ctx = kzalloc(sizeof(struct hugetlbfs_fs_context), GFP_KERNEL); | ||
1310 | if (!ctx) | ||
1311 | return -ENOMEM; | ||
1312 | |||
1313 | ctx->max_hpages = -1; /* No limit on size by default */ | ||
1314 | ctx->nr_inodes = -1; /* No limit on number of inodes by default */ | ||
1315 | ctx->uid = current_fsuid(); | ||
1316 | ctx->gid = current_fsgid(); | ||
1317 | ctx->mode = 0755; | ||
1318 | ctx->hstate = &default_hstate; | ||
1319 | ctx->min_hpages = -1; /* No default minimum size */ | ||
1320 | ctx->max_val_type = NO_SIZE; | ||
1321 | ctx->min_val_type = NO_SIZE; | ||
1322 | fc->fs_private = ctx; | ||
1323 | fc->ops = &hugetlbfs_fs_context_ops; | ||
1324 | return 0; | ||
1297 | } | 1325 | } |
1298 | 1326 | ||
1299 | static struct file_system_type hugetlbfs_fs_type = { | 1327 | static struct file_system_type hugetlbfs_fs_type = { |
1300 | .name = "hugetlbfs", | 1328 | .name = "hugetlbfs", |
1301 | .mount = hugetlbfs_mount, | 1329 | .init_fs_context = hugetlbfs_init_fs_context, |
1302 | .kill_sb = kill_litter_super, | 1330 | .parameters = &hugetlb_fs_parameters, |
1331 | .kill_sb = kill_litter_super, | ||
1303 | }; | 1332 | }; |
1304 | 1333 | ||
1305 | static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE]; | 1334 | static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE]; |
@@ -1384,8 +1413,29 @@ out: | |||
1384 | return file; | 1413 | return file; |
1385 | } | 1414 | } |
1386 | 1415 | ||
1416 | static struct vfsmount *__init mount_one_hugetlbfs(struct hstate *h) | ||
1417 | { | ||
1418 | struct fs_context *fc; | ||
1419 | struct vfsmount *mnt; | ||
1420 | |||
1421 | fc = fs_context_for_mount(&hugetlbfs_fs_type, SB_KERNMOUNT); | ||
1422 | if (IS_ERR(fc)) { | ||
1423 | mnt = ERR_CAST(fc); | ||
1424 | } else { | ||
1425 | struct hugetlbfs_fs_context *ctx = fc->fs_private; | ||
1426 | ctx->hstate = h; | ||
1427 | mnt = fc_mount(fc); | ||
1428 | put_fs_context(fc); | ||
1429 | } | ||
1430 | if (IS_ERR(mnt)) | ||
1431 | pr_err("Cannot mount internal hugetlbfs for page size %uK", | ||
1432 | 1U << (h->order + PAGE_SHIFT - 10)); | ||
1433 | return mnt; | ||
1434 | } | ||
1435 | |||
1387 | static int __init init_hugetlbfs_fs(void) | 1436 | static int __init init_hugetlbfs_fs(void) |
1388 | { | 1437 | { |
1438 | struct vfsmount *mnt; | ||
1389 | struct hstate *h; | 1439 | struct hstate *h; |
1390 | int error; | 1440 | int error; |
1391 | int i; | 1441 | int i; |
@@ -1408,24 +1458,16 @@ static int __init init_hugetlbfs_fs(void) | |||
1408 | 1458 | ||
1409 | i = 0; | 1459 | i = 0; |
1410 | for_each_hstate(h) { | 1460 | for_each_hstate(h) { |
1411 | char buf[50]; | 1461 | mnt = mount_one_hugetlbfs(h); |
1412 | unsigned ps_kb = 1U << (h->order + PAGE_SHIFT - 10); | 1462 | if (IS_ERR(mnt) && i == 0) { |
1413 | 1463 | error = PTR_ERR(mnt); | |
1414 | snprintf(buf, sizeof(buf), "pagesize=%uK", ps_kb); | 1464 | goto out; |
1415 | hugetlbfs_vfsmount[i] = kern_mount_data(&hugetlbfs_fs_type, | ||
1416 | buf); | ||
1417 | |||
1418 | if (IS_ERR(hugetlbfs_vfsmount[i])) { | ||
1419 | pr_err("Cannot mount internal hugetlbfs for " | ||
1420 | "page size %uK", ps_kb); | ||
1421 | error = PTR_ERR(hugetlbfs_vfsmount[i]); | ||
1422 | hugetlbfs_vfsmount[i] = NULL; | ||
1423 | } | 1465 | } |
1466 | hugetlbfs_vfsmount[i] = mnt; | ||
1424 | i++; | 1467 | i++; |
1425 | } | 1468 | } |
1426 | /* Non default hstates are optional */ | 1469 | |
1427 | if (!IS_ERR_OR_NULL(hugetlbfs_vfsmount[default_hstate_idx])) | 1470 | return 0; |
1428 | return 0; | ||
1429 | 1471 | ||
1430 | out: | 1472 | out: |
1431 | kmem_cache_destroy(hugetlbfs_inode_cachep); | 1473 | kmem_cache_destroy(hugetlbfs_inode_cachep); |