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