]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/opts.c
a05c389830dc066e53038d23061b660075146ead
[bcachefs-tools-debian] / libbcachefs / opts.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/kernel.h>
4
5 #include "bcachefs.h"
6 #include "compress.h"
7 #include "disk_groups.h"
8 #include "opts.h"
9 #include "super-io.h"
10 #include "util.h"
11
12 #define x(t, n) [n] = #t,
13
14 const char * const bch2_error_actions[] = {
15         BCH_ERROR_ACTIONS()
16         NULL
17 };
18
19 const char * const bch2_sb_features[] = {
20         BCH_SB_FEATURES()
21         NULL
22 };
23
24 const char * const bch2_sb_compat[] = {
25         BCH_SB_COMPAT()
26         NULL
27 };
28
29 const char * const bch2_btree_ids[] = {
30         BCH_BTREE_IDS()
31         "interior btree node",
32         NULL
33 };
34
35 const char * const bch2_csum_types[] = {
36         BCH_CSUM_TYPES()
37         NULL
38 };
39
40 const char * const bch2_csum_opts[] = {
41         BCH_CSUM_OPTS()
42         NULL
43 };
44
45 const char * const bch2_compression_types[] = {
46         BCH_COMPRESSION_TYPES()
47         NULL
48 };
49
50 const char * const bch2_compression_opts[] = {
51         BCH_COMPRESSION_OPTS()
52         NULL
53 };
54
55 const char * const bch2_str_hash_types[] = {
56         BCH_STR_HASH_TYPES()
57         NULL
58 };
59
60 const char * const bch2_str_hash_opts[] = {
61         BCH_STR_HASH_OPTS()
62         NULL
63 };
64
65 const char * const bch2_data_types[] = {
66         BCH_DATA_TYPES()
67         NULL
68 };
69
70 const char * const bch2_member_states[] = {
71         BCH_MEMBER_STATES()
72         NULL
73 };
74
75 const char * const bch2_jset_entry_types[] = {
76         BCH_JSET_ENTRY_TYPES()
77         NULL
78 };
79
80 const char * const bch2_fs_usage_types[] = {
81         BCH_FS_USAGE_TYPES()
82         NULL
83 };
84
85 #undef x
86
87 const char * const bch2_d_types[BCH_DT_MAX] = {
88         [DT_UNKNOWN]    = "unknown",
89         [DT_FIFO]       = "fifo",
90         [DT_CHR]        = "chr",
91         [DT_DIR]        = "dir",
92         [DT_BLK]        = "blk",
93         [DT_REG]        = "reg",
94         [DT_LNK]        = "lnk",
95         [DT_SOCK]       = "sock",
96         [DT_WHT]        = "whiteout",
97         [DT_SUBVOL]     = "subvol",
98 };
99
100 u64 BCH2_NO_SB_OPT(const struct bch_sb *sb)
101 {
102         BUG();
103 }
104
105 void SET_BCH2_NO_SB_OPT(struct bch_sb *sb, u64 v)
106 {
107         BUG();
108 }
109
110 void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
111 {
112 #define x(_name, ...)                                           \
113         if (opt_defined(src, _name))                                    \
114                 opt_set(*dst, _name, src._name);
115
116         BCH_OPTS()
117 #undef x
118 }
119
120 bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)
121 {
122         switch (id) {
123 #define x(_name, ...)                                           \
124         case Opt_##_name:                                               \
125                 return opt_defined(*opts, _name);
126         BCH_OPTS()
127 #undef x
128         default:
129                 BUG();
130         }
131 }
132
133 u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
134 {
135         switch (id) {
136 #define x(_name, ...)                                           \
137         case Opt_##_name:                                               \
138                 return opts->_name;
139         BCH_OPTS()
140 #undef x
141         default:
142                 BUG();
143         }
144 }
145
146 void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
147 {
148         switch (id) {
149 #define x(_name, ...)                                           \
150         case Opt_##_name:                                               \
151                 opt_set(*opts, _name, v);                               \
152                 break;
153         BCH_OPTS()
154 #undef x
155         default:
156                 BUG();
157         }
158 }
159
160 const struct bch_option bch2_opt_table[] = {
161 #define OPT_BOOL()              .type = BCH_OPT_BOOL, .min = 0, .max = 2
162 #define OPT_UINT(_min, _max)    .type = BCH_OPT_UINT,                   \
163                                 .min = _min, .max = _max
164 #define OPT_STR(_choices)       .type = BCH_OPT_STR,                    \
165                                 .min = 0, .max = ARRAY_SIZE(_choices),\
166                                 .choices = _choices
167 #define OPT_FN(_fn)             .type = BCH_OPT_FN,                     \
168                                 .parse = _fn##_parse,                   \
169                                 .to_text = _fn##_to_text
170
171 #define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help) \
172         [Opt_##_name] = {                                               \
173                 .attr   = {                                             \
174                         .name   = #_name,                               \
175                         .mode = (_flags) & OPT_RUNTIME ? 0644 : 0444,   \
176                 },                                                      \
177                 .flags  = _flags,                                       \
178                 .hint   = _hint,                                        \
179                 .help   = _help,                                        \
180                 .get_sb = _sb_opt,                                      \
181                 .set_sb = SET_##_sb_opt,                                \
182                 _type                                                   \
183         },
184
185         BCH_OPTS()
186 #undef x
187 };
188
189 int bch2_opt_lookup(const char *name)
190 {
191         const struct bch_option *i;
192
193         for (i = bch2_opt_table;
194              i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
195              i++)
196                 if (!strcmp(name, i->attr.name))
197                         return i - bch2_opt_table;
198
199         return -1;
200 }
201
202 struct synonym {
203         const char      *s1, *s2;
204 };
205
206 static const struct synonym bch_opt_synonyms[] = {
207         { "quota",      "usrquota" },
208 };
209
210 static int bch2_mount_opt_lookup(const char *name)
211 {
212         const struct synonym *i;
213
214         for (i = bch_opt_synonyms;
215              i < bch_opt_synonyms + ARRAY_SIZE(bch_opt_synonyms);
216              i++)
217                 if (!strcmp(name, i->s1))
218                         name = i->s2;
219
220         return bch2_opt_lookup(name);
221 }
222
223 int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err)
224 {
225         if (v < opt->min) {
226                 if (err)
227                         prt_printf(err, "%s: too small (min %llu)",
228                                opt->attr.name, opt->min);
229                 return -ERANGE;
230         }
231
232         if (opt->max && v >= opt->max) {
233                 if (err)
234                         prt_printf(err, "%s: too big (max %llu)",
235                                opt->attr.name, opt->max);
236                 return -ERANGE;
237         }
238
239         if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) {
240                 if (err)
241                         prt_printf(err, "%s: not a multiple of 512",
242                                opt->attr.name);
243                 return -EINVAL;
244         }
245
246         if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) {
247                 if (err)
248                         prt_printf(err, "%s: must be a power of two",
249                                opt->attr.name);
250                 return -EINVAL;
251         }
252
253         return 0;
254 }
255
256 int bch2_opt_parse(struct bch_fs *c,
257                    const struct bch_option *opt,
258                    const char *val, u64 *res,
259                    struct printbuf *err)
260 {
261         ssize_t ret;
262
263         switch (opt->type) {
264         case BCH_OPT_BOOL:
265                 ret = kstrtou64(val, 10, res);
266                 if (ret < 0 || (*res != 0 && *res != 1)) {
267                         if (err)
268                                 prt_printf(err, "%s: must be bool",
269                                            opt->attr.name);
270                         return ret;
271                 }
272                 break;
273         case BCH_OPT_UINT:
274                 ret = opt->flags & OPT_HUMAN_READABLE
275                         ? bch2_strtou64_h(val, res)
276                         : kstrtou64(val, 10, res);
277                 if (ret < 0) {
278                         if (err)
279                                 prt_printf(err, "%s: must be a number",
280                                            opt->attr.name);
281                         return ret;
282                 }
283                 break;
284         case BCH_OPT_STR:
285                 ret = match_string(opt->choices, -1, val);
286                 if (ret < 0) {
287                         if (err)
288                                 prt_printf(err, "%s: invalid selection",
289                                            opt->attr.name);
290                         return ret;
291                 }
292
293                 *res = ret;
294                 break;
295         case BCH_OPT_FN:
296                 if (!c)
297                         return 0;
298
299                 ret = opt->parse(c, val, res);
300                 if (ret < 0) {
301                         if (err)
302                                 prt_printf(err, "%s: parse error",
303                                            opt->attr.name);
304                         return ret;
305                 }
306         }
307
308         return bch2_opt_validate(opt, *res, err);
309 }
310
311 void bch2_opt_to_text(struct printbuf *out,
312                       struct bch_fs *c, struct bch_sb *sb,
313                       const struct bch_option *opt, u64 v,
314                       unsigned flags)
315 {
316         if (flags & OPT_SHOW_MOUNT_STYLE) {
317                 if (opt->type == BCH_OPT_BOOL) {
318                         prt_printf(out, "%s%s",
319                                v ? "" : "no",
320                                opt->attr.name);
321                         return;
322                 }
323
324                 prt_printf(out, "%s=", opt->attr.name);
325         }
326
327         switch (opt->type) {
328         case BCH_OPT_BOOL:
329         case BCH_OPT_UINT:
330                 if (opt->flags & OPT_HUMAN_READABLE)
331                         prt_human_readable_u64(out, v);
332                 else
333                         prt_printf(out, "%lli", v);
334                 break;
335         case BCH_OPT_STR:
336                 if (flags & OPT_SHOW_FULL_LIST)
337                         prt_string_option(out, opt->choices, v);
338                 else
339                         prt_printf(out, "%s", opt->choices[v]);
340                 break;
341         case BCH_OPT_FN:
342                 opt->to_text(out, c, sb, v);
343                 break;
344         default:
345                 BUG();
346         }
347 }
348
349 int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)
350 {
351         int ret = 0;
352
353         switch (id) {
354         case Opt_compression:
355         case Opt_background_compression:
356                 ret = bch2_check_set_has_compressed_data(c, v);
357                 break;
358         case Opt_erasure_code:
359                 if (v)
360                         bch2_check_set_feature(c, BCH_FEATURE_ec);
361                 break;
362         }
363
364         return ret;
365 }
366
367 int bch2_opts_check_may_set(struct bch_fs *c)
368 {
369         unsigned i;
370         int ret;
371
372         for (i = 0; i < bch2_opts_nr; i++) {
373                 ret = bch2_opt_check_may_set(c, i,
374                                 bch2_opt_get_by_id(&c->opts, i));
375                 if (ret)
376                         return ret;
377         }
378
379         return 0;
380 }
381
382 int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
383                           char *options)
384 {
385         char *copied_opts, *copied_opts_start;
386         char *opt, *name, *val;
387         int ret, id;
388         struct printbuf err = PRINTBUF;
389         u64 v;
390
391         if (!options)
392                 return 0;
393
394         copied_opts = kstrdup(options, GFP_KERNEL);
395         if (!copied_opts)
396                 return -1;
397         copied_opts_start = copied_opts;
398
399         while ((opt = strsep(&copied_opts, ",")) != NULL) {
400                 name    = strsep(&opt, "=");
401                 val     = opt;
402
403                 if (val) {
404                         id = bch2_mount_opt_lookup(name);
405                         if (id < 0)
406                                 goto bad_opt;
407
408                         ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
409                         if (ret < 0)
410                                 goto bad_val;
411                 } else {
412                         id = bch2_mount_opt_lookup(name);
413                         v = 1;
414
415                         if (id < 0 &&
416                             !strncmp("no", name, 2)) {
417                                 id = bch2_mount_opt_lookup(name + 2);
418                                 v = 0;
419                         }
420
421                         if (id < 0)
422                                 goto bad_opt;
423
424                         if (bch2_opt_table[id].type != BCH_OPT_BOOL)
425                                 goto no_val;
426                 }
427
428                 if (!(bch2_opt_table[id].flags & OPT_MOUNT))
429                         goto bad_opt;
430
431                 if (id == Opt_acl &&
432                     !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
433                         goto bad_opt;
434
435                 if ((id == Opt_usrquota ||
436                      id == Opt_grpquota) &&
437                     !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
438                         goto bad_opt;
439
440                 bch2_opt_set_by_id(opts, id, v);
441         }
442
443         ret = 0;
444         goto out;
445
446 bad_opt:
447         pr_err("Bad mount option %s", name);
448         ret = -1;
449         goto out;
450 bad_val:
451         pr_err("Invalid mount option %s", err.buf);
452         ret = -1;
453         goto out;
454 no_val:
455         pr_err("Mount option %s requires a value", name);
456         ret = -1;
457         goto out;
458 out:
459         kfree(copied_opts_start);
460         printbuf_exit(&err);
461         return ret;
462 }
463
464 u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
465 {
466         const struct bch_option *opt = bch2_opt_table + id;
467         u64 v;
468
469         v = opt->get_sb(sb);
470
471         if (opt->flags & OPT_SB_FIELD_ILOG2)
472                 v = 1ULL << v;
473
474         if (opt->flags & OPT_SB_FIELD_SECTORS)
475                 v <<= 9;
476
477         return v;
478 }
479
480 /*
481  * Initial options from superblock - here we don't want any options undefined,
482  * any options the superblock doesn't specify are set to 0:
483  */
484 int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
485 {
486         unsigned id;
487
488         for (id = 0; id < bch2_opts_nr; id++) {
489                 const struct bch_option *opt = bch2_opt_table + id;
490
491                 if (opt->get_sb == BCH2_NO_SB_OPT)
492                         continue;
493
494                 bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id));
495         }
496
497         return 0;
498 }
499
500 void __bch2_opt_set_sb(struct bch_sb *sb, const struct bch_option *opt, u64 v)
501 {
502         if (opt->set_sb == SET_BCH2_NO_SB_OPT)
503                 return;
504
505         if (opt->flags & OPT_SB_FIELD_SECTORS)
506                 v >>= 9;
507
508         if (opt->flags & OPT_SB_FIELD_ILOG2)
509                 v = ilog2(v);
510
511         opt->set_sb(sb, v);
512 }
513
514 void bch2_opt_set_sb(struct bch_fs *c, const struct bch_option *opt, u64 v)
515 {
516         if (opt->set_sb == SET_BCH2_NO_SB_OPT)
517                 return;
518
519         mutex_lock(&c->sb_lock);
520         __bch2_opt_set_sb(c->disk_sb.sb, opt, v);
521         bch2_write_super(c);
522         mutex_unlock(&c->sb_lock);
523 }
524
525 /* io opts: */
526
527 struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
528 {
529         return (struct bch_io_opts) {
530 #define x(_name, _bits) ._name = src._name,
531         BCH_INODE_OPTS()
532 #undef x
533         };
534 }
535
536 bool bch2_opt_is_inode_opt(enum bch_opt_id id)
537 {
538         static const enum bch_opt_id inode_opt_list[] = {
539 #define x(_name, _bits) Opt_##_name,
540         BCH_INODE_OPTS()
541 #undef x
542         };
543         unsigned i;
544
545         for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)
546                 if (inode_opt_list[i] == id)
547                         return true;
548
549         return false;
550 }