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