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
179179 fsparam_flag_no ("copyfrom", Opt_copyfrom),
180180 fsparam_flag_no ("dcache", Opt_dcache),
181181 fsparam_flag_no ("dirstat", Opt_dirstat),
182− __fsparam (fs_param_is_string, "fsc", Opt_fscache,
183− fs_param_neg_with_no | fs_param_v_optional, NULL),
182+ fsparam_flag_no ("fsc", Opt_fscache), // fsc|nofsc
183+ fsparam_string ("fsc", Opt_fscache), // fsc=...
184184 fsparam_flag_no ("ino32", Opt_ino32),
185185 fsparam_string ("mds_namespace", Opt_mds_namespace),
186186 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
4646 }
4747 EXPORT_SYMBOL(lookup_constant);
4848
49+static inline bool is_flag(const struct fs_parameter_spec *p)
50+{
51+ return p->type == fs_param_is_flag;
52+}
53+
4954 static const struct fs_parameter_spec *fs_lookup_key(
5055 const struct fs_parameter_spec *desc,
51− const char *name)
56+ struct fs_parameter *param, bool *negated)
5257 {
53− const struct fs_parameter_spec *p;
54− if (!desc)
55− return NULL;
56−
57− for (p = desc; p->name; p++)
58− if (strcmp(p->name, name) == 0)
58+ const struct fs_parameter_spec *p, *other = NULL;
59+ const char *name = param->key;
60+ bool want_flag = param->type == fs_value_is_flag;
61+
62+ *negated = false;
63+ for (p = desc; p->name; p++) {
64+ if (strcmp(p->name, name) != 0)
65+ continue;
66+ if (likely(is_flag(p) == want_flag))
5967 return p;
60−
61− return NULL;
68+ other = p;
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;
6283 }
6384
6485 /*
@@ -88,123 +109,77 @@ int __fs_parse(struct p_log *log, · 23 unmodified lines
88109 const struct constant_table *e;
89110 int ret = -ENOPARAM, b;
90111
91− result->negated = false;
92112 result->uint_64 = 0;
93113
94− p = fs_lookup_key(desc, param->key);
95− if (!p) {
96− /* If we didn't find something that looks like "noxxx", see if
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− }
114+ p = fs_lookup_key(desc, param, &result->negated);
115+ if (!p)
116+ return -ENOPARAM;
113117
114118 if (p->flags & fs_param_deprecated)
115119 warn_plog(log, "Deprecated parameter '%s'", param->key);
116120
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−
147121 /* Try to turn the type we were given into the type desired by the
148122 * parameter and give an error if we can't.
149123 */
150124 switch (p->type) {
125+ case __fs_param_wasnt_defined:
126+ return -EINVAL;
151127 case fs_param_is_flag:
152128 if (param->type != fs_value_is_flag)
153129 return inval_plog(log, "Unexpected value for '%s'",
154130 param->key);
155− result->boolean = true;
131+ result->boolean = !result->negated;
156132 goto okay;
157−
158133 case fs_param_is_bool:
159− switch (param->type) {
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:
134+ if (param->type != fs_value_is_string)
174135 goto bad_value;
175− }
176−
136+ b = lookup_constant(bool_names, param->string, -1);
137+ if (b == -1)
138+ goto bad_value;
139+ result->boolean = b;
140+ goto okay;
177141 case fs_param_is_u32:
142+ if (param->type != fs_value_is_string)
143+ goto bad_value;
178144 ret = kstrtouint(param->string, 0, &result->uint_32);
179145 goto maybe_okay;
180146 case fs_param_is_u32_octal:
147+ if (param->type != fs_value_is_string)
148+ goto bad_value;
181149 ret = kstrtouint(param->string, 8, &result->uint_32);
182150 goto maybe_okay;
183151 case fs_param_is_u32_hex:
152+ if (param->type != fs_value_is_string)
153+ goto bad_value;
184154 ret = kstrtouint(param->string, 16, &result->uint_32);
185155 goto maybe_okay;
186156 case fs_param_is_s32:
157+ if (param->type != fs_value_is_string)
158+ goto bad_value;
187159 ret = kstrtoint(param->string, 0, &result->int_32);
188160 goto maybe_okay;
189161 case fs_param_is_u64:
162+ if (param->type != fs_value_is_string)
163+ goto bad_value;
190164 ret = kstrtoull(param->string, 0, &result->uint_64);
191165 goto maybe_okay;
192−
193166 case fs_param_is_enum:
167+ if (param->type != fs_value_is_string)
168+ goto bad_value;
194169 e = __lookup_constant(p->data, param->string);
195170 if (e) {
196171 result->uint_32 = e->value;
197172 goto okay;
198173 }
199174 goto bad_value;
200−
201175 case fs_param_is_string:
176+ if (param->type != fs_value_is_string || !*param->string)
177+ goto bad_value;
202178 goto okay;
203179 case fs_param_is_blob:
204180 if (param->type != fs_value_is_blob)
205181 goto bad_value;
206182 goto okay;
207−
208183 case fs_param_is_fd: {
209184 switch (param->type) {
210185 case fs_value_is_string:
@@ -221,7 +196,6 @@ int __fs_parse(struct p_log *log, · 10 unmodified lines
221196 goto bad_value;
222197 goto maybe_okay;
223198 }
224−
225199 case fs_param_is_blockdev:
226200 case fs_param_is_path:
227201 goto okay;
@@ -237,8 +211,6 @@ okay: · 9 unmodified lines
237211
238212 bad_value:
239213 return inval_plog(log, "Bad value for '%s'", param->key);
240−unknown_parameter:
241− return -ENOPARAM;
242214 }
243215 EXPORT_SYMBOL(__fs_parse);
244216
@@ -382,6 +354,8 @@ bool fs_validate_description(const char *name, · 137 unmodified lines
382354 /* Check for duplicate parameter names */
383355 for (p2 = desc; p2 < param; p2++) {
384356 if (strcmp(param->name, p2->name) == 0) {
357+ if (is_flag(param) != is_flag(p2))
358+ continue;
385359 pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n",
386360 name, param->name);
387361 good = false;
fs/gfs2/ops_fstype.c+10−28
@@ -1250,6 +1250,7 @@ enum gfs2_param { · 1249 unmodified lines
12501250 Opt_upgrade,
12511251 Opt_acl,
12521252 Opt_quota,
1253+ Opt_quota_flag,
12531254 Opt_suiddir,
12541255 Opt_data,
12551256 Opt_meta,
@@ -1264,26 +1265,13 @@ enum gfs2_param { · 8 unmodified lines
12641265 Opt_loccookie,
12651266 };
12661267
1267−enum opt_quota {
1268− Opt_quota_unset = 0,
1269− Opt_quota_off,
1270− Opt_quota_account,
1271− Opt_quota_on,
1272−};
1273−
12741268 static const struct constant_table gfs2_param_quota[] = {
1275− {"off", Opt_quota_off },
1276− {"account", Opt_quota_account },
1277− {"on", Opt_quota_on },
1269+ {"off", GFS2_QUOTA_OFF},
1270+ {"account", GFS2_QUOTA_ACCOUNT},
1271+ {"on", GFS2_QUOTA_ON},
12781272 {}
12791273 };
12801274
1281−static 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−
12871275 enum opt_data {
12881276 Opt_data_writeback = GFS2_DATA_WRITEBACK,
12891277 Opt_data_ordered = GFS2_DATA_ORDERED,
@@ -1331,8 +1319,8 @@ static const struct fs_parameter_spec gfs2_fs_parameters[] = { · 41 unmodified lines
13311319 fsparam_flag_no("rgrplvb", Opt_rgrplvb),
13321320 fsparam_flag_no("loccookie", Opt_loccookie),
13331321 /* quota can be a flag or an enum so it gets special treatment */
1334− __fsparam(fs_param_is_enum, "quota", Opt_quota,
1335− fs_param_neg_with_no|fs_param_v_optional, gfs2_param_quota),
1322+ fsparam_flag_no("quota", Opt_quota_flag),
1323+ fsparam_enum("quota", Opt_quota, gfs2_param_quota),
13361324 {}
13371325 };
13381326
@@ -1380,17 +1368,11 @@ static int gfs2_parse_param(struct fs_context *fc, struct fs_parameter *param) · 41 unmodified lines
13801368 case Opt_acl:
13811369 args->ar_posix_acl = result.boolean;
13821370 break;
1371+ case Opt_quota_flag:
1372+ args->ar_quota = result.negated ? GFS2_QUOTA_OFF : GFS2_QUOTA_ON;
1373+ break;
13831374 case Opt_quota:
1384− /* The quota option can be a flag or an enum. A non-zero 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;
1375+ args->ar_quota = result.int_32;
13941376 break;
13951377 case Opt_suiddir:
13961378 args->ar_suiddir = result.boolean;
fs/nfs/fs_context.c+12−6
@@ -45,6 +45,7 @@ enum nfs_param { · 44 unmodified lines
4545 Opt_cto,
4646 Opt_fg,
4747 Opt_fscache,
48+ Opt_fscache_flag,
4849 Opt_hard,
4950 Opt_intr,
5051 Opt_local_lock,
@@ -125,8 +126,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = { · 74 unmodified lines
125126 fsparam_string("clientaddr", Opt_clientaddr),
126127 fsparam_flag_no("cto", Opt_cto),
127128 fsparam_flag ("fg", Opt_fg),
128− __fsparam(fs_param_is_string, "fsc", Opt_fscache,
129− fs_param_neg_with_no|fs_param_v_optional, NULL),
129+ fsparam_flag_no("fsc", Opt_fscache_flag),
130+ fsparam_string("fsc", Opt_fscache),
130131 fsparam_flag ("hard", Opt_hard),
131132 __fsparam(fs_param_is_flag, "intr", Opt_intr,
132133 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
537538 else
538539 ctx->flags &= ~NFS_MOUNT_NORESVPORT;
539540 break;
540− case Opt_fscache:
541− kfree(ctx->fscache_uniq);
542− ctx->fscache_uniq = param->string;
543− param->string = NULL;
541+ case Opt_fscache_flag:
544542 if (result.negated)
545543 ctx->options &= ~NFS_OPTION_FSCACHE;
546544 else
547545 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;
548554 break;
549555 case Opt_migration:
550556 if (result.negated)
include/linux/fs_parser.h+0−1
@@ -49,7 +49,6 @@ struct fs_parameter_spec { · 48 unmodified lines
4949 u8 opt; /* Option number (returned by fs_parse()) */
5050 enum fs_parameter_type type:8; /* The desired parameter type */
5151 unsigned short flags;
52−#define fs_param_v_optional 0x0001 /* The value is optional */
5352 #define fs_param_neg_with_no 0x0002 /* "noxxx" is negative param */
5453 #define fs_param_neg_with_empty 0x0004 /* "xxx=" is negative param */
5554 #define fs_param_deprecated 0x0008 /* The param is deprecated */