History

fs_parse: handle optional arguments sanely

Don't bother with "mixed" options that would allow both the form with and without argument (i.e. both -o foo and -o foo=bar). Rather than trying to shove both into a single fs_parameter_spec, allow having with-argument and no-argument specs with the same name and teach fs_parse to handle that. There are very few options of that sort, and they are actually easier to handle that way - callers end up with less postprocessing.

Al Viro committed 6 years ago

Commit 48ce73b1 parent d7167b15 files · +82 −121Browse files

Unified · Split

5 files
  1. fs/ceph/super.c +2 −2
  2. fs/fs_parser.c +58 −84
  3. fs/gfs2/ops_fstype.c +10 −28
  4. fs/nfs/fs_context.c +12 −6
  5. include/linux/fs_parser.h +0 −1
fs/ceph/super.c+2−2
@@ -179,8 +179,8 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = { · 178 unmodified lines
179 fsparam_flag_no ("copyfrom", Opt_copyfrom),179 fsparam_flag_no ("copyfrom", Opt_copyfrom),
180 fsparam_flag_no ("dcache", Opt_dcache),180 fsparam_flag_no ("dcache", Opt_dcache),
181 fsparam_flag_no ("dirstat", Opt_dirstat),181 fsparam_flag_no ("dirstat", Opt_dirstat),
182 __fsparam (fs_param_is_string, "fsc", Opt_fscache,182 fsparam_flag_no ("fsc", Opt_fscache), // fsc|nofsc
183 fs_param_neg_with_no | fs_param_v_optional, NULL),183 fsparam_string ("fsc", Opt_fscache), // fsc=...
184 fsparam_flag_no ("ino32", Opt_ino32),184 fsparam_flag_no ("ino32", Opt_ino32),
185 fsparam_string ("mds_namespace", Opt_mds_namespace),185 fsparam_string ("mds_namespace", Opt_mds_namespace),
186 fsparam_flag_no ("poolperm", Opt_poolperm),186 fsparam_flag_no ("poolperm", Opt_poolperm),
fs/fs_parser.c+58−84
@@ -46,19 +46,40 @@ int lookup_constant(const struct constant_table *tbl, const char *name, int not_ · 45 unmodified lines
46}46}
47EXPORT_SYMBOL(lookup_constant);47EXPORT_SYMBOL(lookup_constant);
48 48
49static inline bool is_flag(const struct fs_parameter_spec *p)
50{
51 return p->type == fs_param_is_flag;
52}
53
49static const struct fs_parameter_spec *fs_lookup_key(54static const struct fs_parameter_spec *fs_lookup_key(
50 const struct fs_parameter_spec *desc,55 const struct fs_parameter_spec *desc,
51 const char *name)56 struct fs_parameter *param, bool *negated)
52{57{
53 const struct fs_parameter_spec *p;58 const struct fs_parameter_spec *p, *other = NULL;
54 if (!desc)59 const char *name = param->key;
55 return NULL;60 bool want_flag = param->type == fs_value_is_flag;
56 61
57 for (p = desc; p->name; p++)62 *negated = false;
58 if (strcmp(p->name, name) == 0)63 for (p = desc; p->name; p++) {
64 if (strcmp(p->name, name) != 0)
65 continue;
66 if (likely(is_flag(p) == want_flag))
59 return p;67 return p;
60 68 other = p;
61 return NULL;69 }
70 if (want_flag) {
71 if (name[0] == 'n' && name[1] == 'o' && name[2]) {
72 for (p = desc; p->name; p++) {
73 if (strcmp(p->name, name + 2) != 0)
74 continue;
75 if (!(p->flags & fs_param_neg_with_no))
76 continue;
77 *negated = true;
78 return p;
79 }
80 }
81 }
82 return other;
62}83}
63 84
64/*85/*
@@ -88,123 +109,77 @@ int __fs_parse(struct p_log *log, · 23 unmodified lines
88 const struct constant_table *e;109 const struct constant_table *e;
89 int ret = -ENOPARAM, b;110 int ret = -ENOPARAM, b;
90 111
91 result->negated = false;
92 result->uint_64 = 0;112 result->uint_64 = 0;
93 113
94 p = fs_lookup_key(desc, param->key);114 p = fs_lookup_key(desc, param, &result->negated);
95 if (!p) {115 if (!p)
96 /* If we didn't find something that looks like "noxxx", see if116 return -ENOPARAM;
97 * "xxx" takes the "no"-form negative - but only if there
98 * wasn't an value.
99 */
100 if (param->type != fs_value_is_flag)
101 goto unknown_parameter;
102 if (param->key[0] != 'n' || param->key[1] != 'o' || !param->key[2])
103 goto unknown_parameter;
104
105 p = fs_lookup_key(desc, param->key + 2);
106 if (!p)
107 goto unknown_parameter;
108 if (!(p->flags & fs_param_neg_with_no))
109 goto unknown_parameter;
110 result->boolean = false;
111 result->negated = true;
112 }
113 117
114 if (p->flags & fs_param_deprecated)118 if (p->flags & fs_param_deprecated)
115 warn_plog(log, "Deprecated parameter '%s'", param->key);119 warn_plog(log, "Deprecated parameter '%s'", param->key);
116 120
117 if (result->negated)
118 goto okay;
119
120 /* Certain parameter types only take a string and convert it. */
121 switch (p->type) {
122 case __fs_param_wasnt_defined:
123 return -EINVAL;
124 case fs_param_is_u32:
125 case fs_param_is_u32_octal:
126 case fs_param_is_u32_hex:
127 case fs_param_is_s32:
128 case fs_param_is_u64:
129 case fs_param_is_enum:
130 case fs_param_is_string:
131 if (param->type == fs_value_is_string) {
132 if (p->flags & fs_param_v_optional)
133 break;
134 if (!*param->string)
135 goto bad_value;
136 break;
137 }
138 if (param->type == fs_value_is_flag) {
139 if (p->flags & fs_param_v_optional)
140 goto okay;
141 }
142 goto bad_value;
143 default:
144 break;
145 }
146
147 /* Try to turn the type we were given into the type desired by the121 /* Try to turn the type we were given into the type desired by the
148 * parameter and give an error if we can't.122 * parameter and give an error if we can't.
149 */123 */
150 switch (p->type) {124 switch (p->type) {
125 case __fs_param_wasnt_defined:
126 return -EINVAL;
151 case fs_param_is_flag:127 case fs_param_is_flag:
152 if (param->type != fs_value_is_flag)128 if (param->type != fs_value_is_flag)
153 return inval_plog(log, "Unexpected value for '%s'",129 return inval_plog(log, "Unexpected value for '%s'",
154 param->key);130 param->key);
155 result->boolean = true;131 result->boolean = !result->negated;
156 goto okay;132 goto okay;
157
158 case fs_param_is_bool:133 case fs_param_is_bool:
159 switch (param->type) {134 if (param->type != fs_value_is_string)
160 case fs_value_is_flag:
161 result->boolean = true;
162 goto okay;
163 case fs_value_is_string:
164 if (param->size == 0) {
165 result->boolean = true;
166 goto okay;
167 }
168 b = lookup_constant(bool_names, param->string, -1);
169 if (b == -1)
170 goto bad_value;
171 result->boolean = b;
172 goto okay;
173 default:
174 goto bad_value;135 goto bad_value;
175 }136 b = lookup_constant(bool_names, param->string, -1);
176 137 if (b == -1)
138 goto bad_value;
139 result->boolean = b;
140 goto okay;
177 case fs_param_is_u32:141 case fs_param_is_u32:
142 if (param->type != fs_value_is_string)
143 goto bad_value;
178 ret = kstrtouint(param->string, 0, &result->uint_32);144 ret = kstrtouint(param->string, 0, &result->uint_32);
179 goto maybe_okay;145 goto maybe_okay;
180 case fs_param_is_u32_octal:146 case fs_param_is_u32_octal:
147 if (param->type != fs_value_is_string)
148 goto bad_value;
181 ret = kstrtouint(param->string, 8, &result->uint_32);149 ret = kstrtouint(param->string, 8, &result->uint_32);
182 goto maybe_okay;150 goto maybe_okay;
183 case fs_param_is_u32_hex:151 case fs_param_is_u32_hex:
152 if (param->type != fs_value_is_string)
153 goto bad_value;
184 ret = kstrtouint(param->string, 16, &result->uint_32);154 ret = kstrtouint(param->string, 16, &result->uint_32);
185 goto maybe_okay;155 goto maybe_okay;
186 case fs_param_is_s32:156 case fs_param_is_s32:
157 if (param->type != fs_value_is_string)
158 goto bad_value;
187 ret = kstrtoint(param->string, 0, &result->int_32);159 ret = kstrtoint(param->string, 0, &result->int_32);
188 goto maybe_okay;160 goto maybe_okay;
189 case fs_param_is_u64:161 case fs_param_is_u64:
162 if (param->type != fs_value_is_string)
163 goto bad_value;
190 ret = kstrtoull(param->string, 0, &result->uint_64);164 ret = kstrtoull(param->string, 0, &result->uint_64);
191 goto maybe_okay;165 goto maybe_okay;
192
193 case fs_param_is_enum:166 case fs_param_is_enum:
167 if (param->type != fs_value_is_string)
168 goto bad_value;
194 e = __lookup_constant(p->data, param->string);169 e = __lookup_constant(p->data, param->string);
195 if (e) {170 if (e) {
196 result->uint_32 = e->value;171 result->uint_32 = e->value;
197 goto okay;172 goto okay;
198 }173 }
199 goto bad_value;174 goto bad_value;
200
201 case fs_param_is_string:175 case fs_param_is_string:
176 if (param->type != fs_value_is_string || !*param->string)
177 goto bad_value;
202 goto okay;178 goto okay;
203 case fs_param_is_blob:179 case fs_param_is_blob:
204 if (param->type != fs_value_is_blob)180 if (param->type != fs_value_is_blob)
205 goto bad_value;181 goto bad_value;
206 goto okay;182 goto okay;
207
208 case fs_param_is_fd: {183 case fs_param_is_fd: {
209 switch (param->type) {184 switch (param->type) {
210 case fs_value_is_string:185 case fs_value_is_string:
@@ -221,7 +196,6 @@ int __fs_parse(struct p_log *log, · 10 unmodified lines
221 goto bad_value;196 goto bad_value;
222 goto maybe_okay;197 goto maybe_okay;
223 }198 }
224
225 case fs_param_is_blockdev:199 case fs_param_is_blockdev:
226 case fs_param_is_path:200 case fs_param_is_path:
227 goto okay;201 goto okay;
@@ -237,8 +211,6 @@ okay: · 9 unmodified lines
237 211
238bad_value:212bad_value:
239 return inval_plog(log, "Bad value for '%s'", param->key);213 return inval_plog(log, "Bad value for '%s'", param->key);
240unknown_parameter:
241 return -ENOPARAM;
242}214}
243EXPORT_SYMBOL(__fs_parse);215EXPORT_SYMBOL(__fs_parse);
244 216
@@ -382,6 +354,8 @@ bool fs_validate_description(const char *name, · 137 unmodified lines
382 /* Check for duplicate parameter names */354 /* Check for duplicate parameter names */
383 for (p2 = desc; p2 < param; p2++) {355 for (p2 = desc; p2 < param; p2++) {
384 if (strcmp(param->name, p2->name) == 0) {356 if (strcmp(param->name, p2->name) == 0) {
357 if (is_flag(param) != is_flag(p2))
358 continue;
385 pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n",359 pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n",
386 name, param->name);360 name, param->name);
387 good = false;361 good = false;
fs/gfs2/ops_fstype.c+10−28
@@ -1250,6 +1250,7 @@ enum gfs2_param { · 1249 unmodified lines
1250 Opt_upgrade,1250 Opt_upgrade,
1251 Opt_acl,1251 Opt_acl,
1252 Opt_quota,1252 Opt_quota,
1253 Opt_quota_flag,
1253 Opt_suiddir,1254 Opt_suiddir,
1254 Opt_data,1255 Opt_data,
1255 Opt_meta,1256 Opt_meta,
@@ -1264,26 +1265,13 @@ enum gfs2_param { · 8 unmodified lines
1264 Opt_loccookie,1265 Opt_loccookie,
1265};1266};
1266 1267
1267enum opt_quota {
1268 Opt_quota_unset = 0,
1269 Opt_quota_off,
1270 Opt_quota_account,
1271 Opt_quota_on,
1272};
1273
1274static const struct constant_table gfs2_param_quota[] = {1268static const struct constant_table gfs2_param_quota[] = {
1275 {"off", Opt_quota_off },1269 {"off", GFS2_QUOTA_OFF},
1276 {"account", Opt_quota_account },1270 {"account", GFS2_QUOTA_ACCOUNT},
1277 {"on", Opt_quota_on },1271 {"on", GFS2_QUOTA_ON},
1278 {}1272 {}
1279};1273};
1280 1274
1281static const unsigned int opt_quota_values[] = {
1282 [Opt_quota_off] = GFS2_QUOTA_OFF,
1283 [Opt_quota_account] = GFS2_QUOTA_ACCOUNT,
1284 [Opt_quota_on] = GFS2_QUOTA_ON,
1285};
1286
1287enum opt_data {1275enum opt_data {
1288 Opt_data_writeback = GFS2_DATA_WRITEBACK,1276 Opt_data_writeback = GFS2_DATA_WRITEBACK,
1289 Opt_data_ordered = GFS2_DATA_ORDERED,1277 Opt_data_ordered = GFS2_DATA_ORDERED,
@@ -1331,8 +1319,8 @@ static const struct fs_parameter_spec gfs2_fs_parameters[] = { · 41 unmodified lines
1331 fsparam_flag_no("rgrplvb", Opt_rgrplvb),1319 fsparam_flag_no("rgrplvb", Opt_rgrplvb),
1332 fsparam_flag_no("loccookie", Opt_loccookie),1320 fsparam_flag_no("loccookie", Opt_loccookie),
1333 /* quota can be a flag or an enum so it gets special treatment */1321 /* quota can be a flag or an enum so it gets special treatment */
1334 __fsparam(fs_param_is_enum, "quota", Opt_quota,1322 fsparam_flag_no("quota", Opt_quota_flag),
1335 fs_param_neg_with_no|fs_param_v_optional, gfs2_param_quota),1323 fsparam_enum("quota", Opt_quota, gfs2_param_quota),
1336 {}1324 {}
1337};1325};
1338 1326
@@ -1380,17 +1368,11 @@ static int gfs2_parse_param(struct fs_context *fc, struct fs_parameter *param) · 41 unmodified lines
1380 case Opt_acl:1368 case Opt_acl:
1381 args->ar_posix_acl = result.boolean;1369 args->ar_posix_acl = result.boolean;
1382 break;1370 break;
1371 case Opt_quota_flag:
1372 args->ar_quota = result.negated ? GFS2_QUOTA_OFF : GFS2_QUOTA_ON;
1373 break;
1383 case Opt_quota:1374 case Opt_quota:
1384 /* The quota option can be a flag or an enum. A non-zero int_321375 args->ar_quota = result.int_32;
1385 result means that we have an enum index. Otherwise we have
1386 to rely on the 'negated' flag to tell us whether 'quota' or
1387 'noquota' was specified. */
1388 if (result.negated)
1389 args->ar_quota = GFS2_QUOTA_OFF;
1390 else if (result.int_32 > 0)
1391 args->ar_quota = opt_quota_values[result.int_32];
1392 else
1393 args->ar_quota = GFS2_QUOTA_ON;
1394 break;1376 break;
1395 case Opt_suiddir:1377 case Opt_suiddir:
1396 args->ar_suiddir = result.boolean;1378 args->ar_suiddir = result.boolean;
fs/nfs/fs_context.c+12−6
@@ -45,6 +45,7 @@ enum nfs_param { · 44 unmodified lines
45 Opt_cto,45 Opt_cto,
46 Opt_fg,46 Opt_fg,
47 Opt_fscache,47 Opt_fscache,
48 Opt_fscache_flag,
48 Opt_hard,49 Opt_hard,
49 Opt_intr,50 Opt_intr,
50 Opt_local_lock,51 Opt_local_lock,
@@ -125,8 +126,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = { · 74 unmodified lines
125 fsparam_string("clientaddr", Opt_clientaddr),126 fsparam_string("clientaddr", Opt_clientaddr),
126 fsparam_flag_no("cto", Opt_cto),127 fsparam_flag_no("cto", Opt_cto),
127 fsparam_flag ("fg", Opt_fg),128 fsparam_flag ("fg", Opt_fg),
128 __fsparam(fs_param_is_string, "fsc", Opt_fscache,129 fsparam_flag_no("fsc", Opt_fscache_flag),
129 fs_param_neg_with_no|fs_param_v_optional, NULL),130 fsparam_string("fsc", Opt_fscache),
130 fsparam_flag ("hard", Opt_hard),131 fsparam_flag ("hard", Opt_hard),
131 __fsparam(fs_param_is_flag, "intr", Opt_intr,132 __fsparam(fs_param_is_flag, "intr", Opt_intr,
132 fs_param_neg_with_no|fs_param_deprecated, NULL),133 fs_param_neg_with_no|fs_param_deprecated, NULL),
@@ -537,14 +538,19 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, · 404 unmodified lines
537 else538 else
538 ctx->flags &= ~NFS_MOUNT_NORESVPORT;539 ctx->flags &= ~NFS_MOUNT_NORESVPORT;
539 break;540 break;
540 case Opt_fscache:541 case Opt_fscache_flag:
541 kfree(ctx->fscache_uniq);
542 ctx->fscache_uniq = param->string;
543 param->string = NULL;
544 if (result.negated)542 if (result.negated)
545 ctx->options &= ~NFS_OPTION_FSCACHE;543 ctx->options &= ~NFS_OPTION_FSCACHE;
546 else544 else
547 ctx->options |= NFS_OPTION_FSCACHE;545 ctx->options |= NFS_OPTION_FSCACHE;
546 kfree(ctx->fscache_uniq);
547 ctx->fscache_uniq = NULL;
548 break;
549 case Opt_fscache:
550 ctx->options |= NFS_OPTION_FSCACHE;
551 kfree(ctx->fscache_uniq);
552 ctx->fscache_uniq = param->string;
553 param->string = NULL;
548 break;554 break;
549 case Opt_migration:555 case Opt_migration:
550 if (result.negated)556 if (result.negated)
include/linux/fs_parser.h+0−1
@@ -49,7 +49,6 @@ struct fs_parameter_spec { · 48 unmodified lines
49 u8 opt; /* Option number (returned by fs_parse()) */49 u8 opt; /* Option number (returned by fs_parse()) */
50 enum fs_parameter_type type:8; /* The desired parameter type */50 enum fs_parameter_type type:8; /* The desired parameter type */
51 unsigned short flags;51 unsigned short flags;
52#define fs_param_v_optional 0x0001 /* The value is optional */
53#define fs_param_neg_with_no 0x0002 /* "noxxx" is negative param */52#define fs_param_neg_with_no 0x0002 /* "noxxx" is negative param */
54#define fs_param_neg_with_empty 0x0004 /* "xxx=" is negative param */53#define fs_param_neg_with_empty 0x0004 /* "xxx=" is negative param */
55#define fs_param_deprecated 0x0008 /* The param is deprecated */54#define fs_param_deprecated 0x0008 /* The param is deprecated */