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