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