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