diff options
| -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 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; | |||
| 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; |
| @@ -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 | ||
| 1084 | enum 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 | ||
| 1108 | static int | 1120 | /* |
| 1109 | hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) | 1121 | * Parse one mount parameter. |
| 1122 | */ | ||
| 1123 | static 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 | |||
