~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/bcachefs/opts.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
382                 if (ret == -BCH_ERR_option_needs_open_fs)
383                         return ret;
384 
385                 if (ret < 0) {
386                         if (err)
387                                 prt_printf(err, "%s: parse error",
388                                            opt->attr.name);
389                         return ret;
390                 }
391         }
392 
393         return bch2_opt_validate(opt, *res, err);
394 }
395 
396 void bch2_opt_to_text(struct printbuf *out,
397                       struct bch_fs *c, struct bch_sb *sb,
398                       const struct bch_option *opt, u64 v,
399                       unsigned flags)
400 {
401         if (flags & OPT_SHOW_MOUNT_STYLE) {
402                 if (opt->type == BCH_OPT_BOOL) {
403                         prt_printf(out, "%s%s",
404                                v ? "" : "no",
405                                opt->attr.name);
406                         return;
407                 }
408 
409                 prt_printf(out, "%s=", opt->attr.name);
410         }
411 
412         switch (opt->type) {
413         case BCH_OPT_BOOL:
414         case BCH_OPT_UINT:
415                 if (opt->flags & OPT_HUMAN_READABLE)
416                         prt_human_readable_u64(out, v);
417                 else
418                         prt_printf(out, "%lli", v);
419                 break;
420         case BCH_OPT_STR:
421                 if (flags & OPT_SHOW_FULL_LIST)
422                         prt_string_option(out, opt->choices, v);
423                 else
424                         prt_str(out, opt->choices[v]);
425                 break;
426         case BCH_OPT_FN:
427                 opt->fn.to_text(out, c, sb, v);
428                 break;
429         default:
430                 BUG();
431         }
432 }
433 
434 int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)
435 {
436         int ret = 0;
437 
438         switch (id) {
439         case Opt_compression:
440         case Opt_background_compression:
441                 ret = bch2_check_set_has_compressed_data(c, v);
442                 break;
443         case Opt_erasure_code:
444                 if (v)
445                         bch2_check_set_feature(c, BCH_FEATURE_ec);
446                 break;
447         }
448 
449         return ret;
450 }
451 
452 int bch2_opts_check_may_set(struct bch_fs *c)
453 {
454         unsigned i;
455         int ret;
456 
457         for (i = 0; i < bch2_opts_nr; i++) {
458                 ret = bch2_opt_check_may_set(c, i,
459                                 bch2_opt_get_by_id(&c->opts, i));
460                 if (ret)
461                         return ret;
462         }
463 
464         return 0;
465 }
466 
467 int bch2_parse_one_mount_opt(struct bch_fs *c, struct bch_opts *opts,
468                              struct printbuf *parse_later,
469                              const char *name, const char *val)
470 {
471         struct printbuf err = PRINTBUF;
472         u64 v;
473         int ret, id;
474 
475         id = bch2_mount_opt_lookup(name);
476 
477         /* Check for the form "noopt", negation of a boolean opt: */
478         if (id < 0 &&
479             !val &&
480             !strncmp("no", name, 2)) {
481                 id = bch2_mount_opt_lookup(name + 2);
482                 val = "";
483         }
484 
485         /* Unknown options are ignored: */
486         if (id < 0)
487                 return 0;
488 
489         if (!(bch2_opt_table[id].flags & OPT_MOUNT))
490                 goto bad_opt;
491 
492         if (id == Opt_acl &&
493             !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
494                 goto bad_opt;
495 
496         if ((id == Opt_usrquota ||
497              id == Opt_grpquota) &&
498             !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
499                 goto bad_opt;
500 
501         ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
502         if (ret == -BCH_ERR_option_needs_open_fs && parse_later) {
503                 prt_printf(parse_later, "%s=%s,", name, val);
504                 if (parse_later->allocation_failure) {
505                         ret = -ENOMEM;
506                         goto out;
507                 }
508 
509                 ret = 0;
510                 goto out;
511         }
512 
513         if (ret < 0)
514                 goto bad_val;
515 
516         if (opts)
517                 bch2_opt_set_by_id(opts, id, v);
518 
519         ret = 0;
520         goto out;
521 
522 bad_opt:
523         pr_err("Bad mount option %s", name);
524         ret = -BCH_ERR_option_name;
525         goto out;
526 
527 bad_val:
528         pr_err("Invalid mount option %s", err.buf);
529         ret = -BCH_ERR_option_value;
530 
531 out:
532         printbuf_exit(&err);
533         return ret;
534 }
535 
536 int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
537                           struct printbuf *parse_later, char *options)
538 {
539         char *copied_opts, *copied_opts_start;
540         char *opt, *name, *val;
541         int ret;
542 
543         if (!options)
544                 return 0;
545 
546         /*
547          * sys_fsconfig() is now occasionally providing us with option lists
548          * starting with a comma - weird.
549          */
550         if (*options == ',')
551                 options++;
552 
553         copied_opts = kstrdup(options, GFP_KERNEL);
554         if (!copied_opts)
555                 return -ENOMEM;
556         copied_opts_start = copied_opts;
557 
558         while ((opt = strsep(&copied_opts, ",")) != NULL) {
559                 name    = strsep(&opt, "=");
560                 val     = opt;
561 
562                 ret = bch2_parse_one_mount_opt(c, opts, parse_later, name, val);
563                 if (ret < 0)
564                         goto out;
565         }
566 
567         ret = 0;
568         goto out;
569 
570 out:
571         kfree(copied_opts_start);
572         return ret;
573 }
574 
575 u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
576 {
577         const struct bch_option *opt = bch2_opt_table + id;
578         u64 v;
579 
580         v = opt->get_sb(sb);
581 
582         if (opt->flags & OPT_SB_FIELD_ILOG2)
583                 v = 1ULL << v;
584 
585         if (opt->flags & OPT_SB_FIELD_SECTORS)
586                 v <<= 9;
587 
588         return v;
589 }
590 
591 /*
592  * Initial options from superblock - here we don't want any options undefined,
593  * any options the superblock doesn't specify are set to 0:
594  */
595 int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
596 {
597         unsigned id;
598 
599         for (id = 0; id < bch2_opts_nr; id++) {
600                 const struct bch_option *opt = bch2_opt_table + id;
601 
602                 if (opt->get_sb == BCH2_NO_SB_OPT)
603                         continue;
604 
605                 bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id));
606         }
607 
608         return 0;
609 }
610 
611 void __bch2_opt_set_sb(struct bch_sb *sb, const struct bch_option *opt, u64 v)
612 {
613         if (opt->set_sb == SET_BCH2_NO_SB_OPT)
614                 return;
615 
616         if (opt->flags & OPT_SB_FIELD_SECTORS)
617                 v >>= 9;
618 
619         if (opt->flags & OPT_SB_FIELD_ILOG2)
620                 v = ilog2(v);
621 
622         opt->set_sb(sb, v);
623 }
624 
625 void bch2_opt_set_sb(struct bch_fs *c, const struct bch_option *opt, u64 v)
626 {
627         if (opt->set_sb == SET_BCH2_NO_SB_OPT)
628                 return;
629 
630         mutex_lock(&c->sb_lock);
631         __bch2_opt_set_sb(c->disk_sb.sb, opt, v);
632         bch2_write_super(c);
633         mutex_unlock(&c->sb_lock);
634 }
635 
636 /* io opts: */
637 
638 struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
639 {
640         return (struct bch_io_opts) {
641 #define x(_name, _bits) ._name = src._name,
642         BCH_INODE_OPTS()
643 #undef x
644         };
645 }
646 
647 bool bch2_opt_is_inode_opt(enum bch_opt_id id)
648 {
649         static const enum bch_opt_id inode_opt_list[] = {
650 #define x(_name, _bits) Opt_##_name,
651         BCH_INODE_OPTS()
652 #undef x
653         };
654         unsigned i;
655 
656         for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)
657                 if (inode_opt_list[i] == id)
658                         return true;
659 
660         return false;
661 }
662 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php