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