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