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