aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/hugetlbfs/inode.c358
1 files changed, 200 insertions, 158 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 32920a10100e..239c7ca09b74 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;
45static const struct inode_operations hugetlbfs_dir_inode_operations; 45static const struct inode_operations hugetlbfs_dir_inode_operations;
46static const struct inode_operations hugetlbfs_inode_operations; 46static const struct inode_operations hugetlbfs_inode_operations;
47 47
48struct hugetlbfs_config { 48enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT };
49
50struct 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
58int sysctl_hugetlb_shm_group; 64int sysctl_hugetlb_shm_group;
59 65
60enum { 66enum 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
67static const match_table_t tokens = { 76static 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
87static 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
710static struct inode *hugetlbfs_get_root(struct super_block *sb, 724static 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;
@@ -1081,8 +1095,6 @@ static const struct super_operations hugetlbfs_ops = {
1081 .show_options = hugetlbfs_show_options, 1095 .show_options = hugetlbfs_show_options,
1082}; 1096};
1083 1097
1084enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT };
1085
1086/* 1098/*
1087 * Convert size option passed from command line to number of huge pages 1099 * Convert size option passed from command line to number of huge pages
1088 * in the pool specified by hstate. Size option could be in bytes 1100 * in the pool specified by hstate. Size option could be in bytes
@@ -1105,170 +1117,151 @@ hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt,
1105 return size_opt; 1117 return size_opt;
1106} 1118}
1107 1119
1108static int 1120/*
1109hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) 1121 * Parse one mount parameter.
1122 */
1123static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
1110{ 1124{
1111 char *p, *rest; 1125 struct hugetlbfs_fs_context *ctx = fc->fs_private;
1112 substring_t args[MAX_OPT_ARGS]; 1126 struct fs_parse_result result;
1113 int option; 1127 char *rest;
1114 unsigned long long max_size_opt = 0, min_size_opt = 0; 1128 unsigned long ps;
1115 enum hugetlbfs_size_type max_val_type = NO_SIZE, min_val_type = NO_SIZE; 1129 int opt;
1116 1130
1117 if (!options) 1131 opt = fs_parse(fc, &hugetlb_fs_parameters, param, &result);
1132 if (opt < 0)
1133 return opt;
1134
1135 switch (opt) {
1136 case Opt_uid:
1137 ctx->uid = make_kuid(current_user_ns(), result.uint_32);
1138 if (!uid_valid(ctx->uid))
1139 goto bad_val;
1118 return 0; 1140 return 0;
1119 1141
1120 while ((p = strsep(&options, ",")) != NULL) { 1142 case Opt_gid:
1121 int token; 1143 ctx->gid = make_kgid(current_user_ns(), result.uint_32);
1122 if (!*p) 1144 if (!gid_valid(ctx->gid))
1123 continue; 1145 goto bad_val;
1146 return 0;
1124 1147
1125 token = match_token(p, tokens, args); 1148 case Opt_mode:
1126 switch (token) { 1149 ctx->mode = result.uint_32 & 01777U;
1127 case Opt_uid: 1150 return 0;
1128 if (match_int(&args[0], &option))
1129 goto bad_val;
1130 pconfig->uid = make_kuid(current_user_ns(), option);
1131 if (!uid_valid(pconfig->uid))
1132 goto bad_val;
1133 break;
1134 1151
1135 case Opt_gid: 1152 case Opt_size:
1136 if (match_int(&args[0], &option)) 1153 /* memparse() will accept a K/M/G without a digit */
1137 goto bad_val; 1154 if (!isdigit(param->string[0]))
1138 pconfig->gid = make_kgid(current_user_ns(), option); 1155 goto bad_val;
1139 if (!gid_valid(pconfig->gid)) 1156 ctx->max_size_opt = memparse(param->string, &rest);
1140 goto bad_val; 1157 ctx->max_val_type = SIZE_STD;
1141 break; 1158 if (*rest == '%')
1159 ctx->max_val_type = SIZE_PERCENT;
1160 return 0;
1142 1161
1143 case Opt_mode: 1162 case Opt_nr_inodes:
1144 if (match_octal(&args[0], &option)) 1163 /* memparse() will accept a K/M/G without a digit */
1145 goto bad_val; 1164 if (!isdigit(param->string[0]))
1146 pconfig->mode = option & 01777U; 1165 goto bad_val;
1147 break; 1166 ctx->nr_inodes = memparse(param->string, &rest);
1167 return 0;
1148 1168
1149 case Opt_size: { 1169 case Opt_pagesize:
1150 /* memparse() will accept a K/M/G without a digit */ 1170 ps = memparse(param->string, &rest);
1151 if (!isdigit(*args[0].from)) 1171 ctx->hstate = size_to_hstate(ps);
1152 goto bad_val; 1172 if (!ctx->hstate) {
1153 max_size_opt = memparse(args[0].from, &rest); 1173 pr_err("Unsupported page size %lu MB\n", ps >> 20);
1154 max_val_type = SIZE_STD; 1174 return -EINVAL;
1155 if (*rest == '%')
1156 max_val_type = SIZE_PERCENT;
1157 break;
1158 } 1175 }
1176 return 0;
1159 1177
1160 case Opt_nr_inodes: 1178 case Opt_min_size:
1161 /* memparse() will accept a K/M/G without a digit */ 1179 /* memparse() will accept a K/M/G without a digit */
116