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