Skip to content

Commit 48ce73b

Browse files
author
Al Viro
committed
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. Signed-off-by: Al Viro <[email protected]>
1 parent d7167b1 commit 48ce73b

File tree

5 files changed

+82
-121
lines changed

5 files changed

+82
-121
lines changed

fs/ceph/super.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
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

Lines changed: 58 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,40 @@ int lookup_constant(const struct constant_table *tbl, const char *name, int not_
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,
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,
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 @@ int __fs_parse(struct p_log *log,
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,
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

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,7 @@ enum gfs2_param {
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 {
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[] = {
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)
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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum nfs_param {
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[] = {
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,
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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ struct fs_parameter_spec {
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 */

0 commit comments

Comments
 (0)