Skip to content

Commit 76f0670

Browse files
adam900710kdave
authored andcommitted
btrfs-progs: tune: do not allow multiple incompatible features to be set
[PROBLEM] Btrfstune allows multiple different options to be executed in one go, some options are completely fine, like no-holes along with extref, but with more and more options, we need more exclusive checks. In fact a lot of new options are already not following the old success/total checks. [ENHANCEMENT] There is really no need to allow multiple features to be set in one go. So this patch introduces an array which groups all the compatible options into following categories: - Extent tree This includes converting to/from extent and block group tree. - Space cache This includes converting to v2 space cache. - Metadata UUID This includes changing metadata uuid. - FSID change This includes the slower full fs fsid rewrites. - Csum change This includes the csum rewrites. - Seed devices This includes changing the device seed flag. - Legacy options This includes no-holes/extref/skinny-metadata features, which are already default mkfs features. Now we only allow options inside the same group to be specified. E.g. "btrfstune -r -S 1" would fail as it includes both legacy and seed groups. Meanwhile "btrfstune -r -n" would still be allowed. Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 776edd3 commit 76f0670

File tree

1 file changed

+83
-38
lines changed

1 file changed

+83
-38
lines changed

tune/main.c

+83-38
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,49 @@ static const char * const tune_usage[] = {
126126
NULL
127127
};
128128

129+
enum btrfstune_group_enum {
130+
/* Extent/block group tree feature. */
131+
EXTENT_TREE,
132+
133+
/* V1/v2 free space cache. */
134+
SPACE_CACHE,
135+
136+
/* Metadata UUID. */
137+
METADATA_UUID,
138+
139+
/* FSID change. */
140+
FSID_CHANGE,
141+
142+
/* Seed device. */
143+
SEED,
144+
145+
/* Csum conversion */
146+
CSUM_CHANGE,
147+
148+
/*
149+
* Legacy features (which later become default), including:
150+
* - no-holes
151+
* - extref
152+
* - skinny-metadata
153+
*/
154+
LEGACY,
155+
156+
BTRFSTUNE_NR_GROUPS,
157+
};
158+
159+
static bool btrfstune_cmd_groups[BTRFSTUNE_NR_GROUPS] = { 0 };
160+
161+
static unsigned int btrfstune_count_set_groups()
162+
{
163+
int ret = 0;
164+
165+
for (int i = 0; i < BTRFSTUNE_NR_GROUPS; i++) {
166+
if (btrfstune_cmd_groups[i])
167+
ret++;
168+
}
169+
return ret;
170+
}
171+
129172
static const struct cmd_struct tune_cmd = {
130173
.usagestr = tune_usage
131174
};
@@ -135,8 +178,6 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
135178
struct btrfs_root *root;
136179
struct btrfs_fs_info *fs_info;
137180
unsigned ctree_flags = OPEN_CTREE_WRITES;
138-
int success = 0;
139-
int total = 0;
140181
int seeding_flag = 0;
141182
u64 seeding_value = 0;
142183
int random_fsid = 0;
@@ -178,51 +219,63 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
178219
case 'S':
179220
seeding_flag = 1;
180221
seeding_value = arg_strtou64(optarg);
222+
btrfstune_cmd_groups[SEED] = true;
181223
break;
182224
case 'r':
183225
super_flags |= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF;
226+
btrfstune_cmd_groups[LEGACY] = true;
184227
break;
185228
case 'x':
186229
super_flags |= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA;
230+
btrfstune_cmd_groups[LEGACY] = true;
187231
break;
188232
case 'n':
189233
super_flags |= BTRFS_FEATURE_INCOMPAT_NO_HOLES;
234+
btrfstune_cmd_groups[LEGACY] = true;
190235
break;
191236
case 'f':
192237
force = 1;
193238
break;
194239
case 'U':
195240
ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
196241
new_fsid_str = optarg;
242+
btrfstune_cmd_groups[FSID_CHANGE] = true;
197243
break;
198244
case 'u':
199245
ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
200246
random_fsid = 1;
247+
btrfstune_cmd_groups[FSID_CHANGE] = true;
201248
break;
202249
case 'M':
203250
ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
204251
change_metadata_uuid = 1;
205252
new_fsid_str = optarg;
253+
btrfstune_cmd_groups[METADATA_UUID] = true;
206254
break;
207255
case 'm':
208256
ctree_flags |= OPEN_CTREE_IGNORE_FSID_MISMATCH;
209257
change_metadata_uuid = 1;
258+
btrfstune_cmd_groups[METADATA_UUID] = true;
210259
break;
211260
case GETOPT_VAL_ENABLE_BLOCK_GROUP_TREE:
212261
to_bg_tree = true;
262+
btrfstune_cmd_groups[EXTENT_TREE] = true;
213263
break;
214264
case GETOPT_VAL_DISABLE_BLOCK_GROUP_TREE:
215265
to_extent_tree = true;
266+
btrfstune_cmd_groups[EXTENT_TREE] = true;
216267
break;
217268
case GETOPT_VAL_ENABLE_FREE_SPACE_TREE:
218269
to_fst = true;
270+
btrfstune_cmd_groups[SPACE_CACHE] = true;
219271
break;
220272
#if EXPERIMENTAL
221273
case GETOPT_VAL_CSUM:
222274
btrfs_warn_experimental(
223275
"Switching checksums is experimental, do not use for valuable data!");
224276
ctree_flags |= OPEN_CTREE_SKIP_CSUM_CHECK;
225277
csum_type = parse_csum_type(optarg);
278+
btrfstune_cmd_groups[CSUM_CHANGE] = true;
226279
break;
227280
#endif
228281
case GETOPT_VAL_HELP:
@@ -238,20 +291,23 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
238291
goto free_out;
239292
}
240293

241-
if (random_fsid && new_fsid_str) {
242-
error("random fsid can't be used with specified fsid");
294+
if (btrfstune_count_set_groups() == 0) {
295+
error("at least one option should be specified");
296+
usage(&tune_cmd, 1);
243297
ret = 1;
244298
goto free_out;
245299
}
246-
if (!super_flags && !seeding_flag && !(random_fsid || new_fsid_str) &&
247-
!change_metadata_uuid && csum_type == -1 && !to_bg_tree &&
248-
!to_extent_tree && !to_fst) {
249-
error("at least one option should be specified");
300+
if (btrfstune_count_set_groups() > 1) {
301+
error("too many conflicting options specified");
250302
usage(&tune_cmd, 1);
251303
ret = 1;
252304
goto free_out;
253305
}
254-
306+
if (random_fsid && new_fsid_str) {
307+
error("random fsid can't be used with specified fsid");
308+
ret = 1;
309+
goto free_out;
310+
}
255311
if (new_fsid_str) {
256312
uuid_t tmp;
257313

@@ -321,17 +377,17 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
321377
if (to_bg_tree) {
322378
if (to_extent_tree) {
323379
error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree");
324-
ret = 1;
380+
ret = -EINVAL;
325381
goto out;
326382
}
327383
if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) {
328384
error("the filesystem already has block group tree feature");
329-
ret = 1;
385+
ret = -EINVAL;
330386
goto out;
331387
}
332388
if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
333389
error("the filesystem doesn't have space cache v2, needs to be mounted with \"-o space_cache=v2\" first");
334-
ret = 1;
390+
ret = -EINVAL;
335391
goto out;
336392
}
337393
ret = convert_to_bg_tree(fs_info);
@@ -344,7 +400,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
344400
if (to_fst) {
345401
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
346402
error("filesystem already has free-space-tree feature");
347-
ret = 1;
403+
ret = -EINVAL;
348404
goto out;
349405
}
350406
ret = convert_to_fst(fs_info);
@@ -355,12 +411,12 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
355411
if (to_extent_tree) {
356412
if (to_bg_tree) {
357413
error("option --convert-to-block-group-tree conflicts with --convert-from-block-group-tree");
358-
ret = 1;
414+
ret = -EINVAL;
359415
goto out;
360416
}
361417
if (!btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) {
362418
error("filesystem doesn't have block-group-tree feature");
363-
ret = 1;
419+
ret = -EINVAL;
364420
goto out;
365421
}
366422
ret = convert_to_extent_tree(fs_info);
@@ -373,7 +429,7 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
373429
if (seeding_flag) {
374430
if (btrfs_fs_incompat(fs_info, METADATA_UUID)) {
375431
error("SEED flag cannot be changed on a metadata-uuid changed fs");
376-
ret = 1;
432+
ret = -EINVAL;
377433
goto out;
378434
}
379435

@@ -383,34 +439,30 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
383439
ret = ask_user("We are going to clear the seeding flag, are you sure?");
384440
if (!ret) {
385441
error("clear seeding flag canceled");
386-
ret = 1;
442+
ret = -EINVAL;
387443
goto out;
388444
}
389445
}
390446

391447
ret = update_seeding_flag(root, device, seeding_value, force);
392-
if (!ret)
393-
success++;
394-
total++;
448+
goto out;
395449
}
396450

397451
if (super_flags) {
398452
ret = set_super_incompat_flags(root, super_flags);
399-
if (!ret)
400-
success++;
401-
total++;
453+
goto out;
402454
}
403455

404456
if (csum_type != -1) {
405-
/* TODO: check conflicting flags */
406457
pr_verbose(LOG_DEFAULT, "Proceed to switch checksums\n");
407458
ret = btrfs_change_csum_type(fs_info, csum_type);
459+
goto out;
408460
}
409461

410462
if (change_metadata_uuid) {
411463
if (seeding_flag) {
412464
error("not allowed to set both seeding flag and uuid metadata");
413-
ret = 1;
465+
ret = -EINVAL;
414466
goto out;
415467
}
416468

@@ -419,18 +471,16 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
419471
else
420472
ret = set_metadata_uuid(root, NULL);
421473

422-
if (!ret)
423-
success++;
424-
total++;
425474
btrfs_register_all_devices();
475+
goto out;
426476
}
427477

428478
if (random_fsid || (new_fsid_str && !change_metadata_uuid)) {
429479
if (fs_info->fs_devices->active_metadata_uuid) {
430480
error(
431481
"Cannot rewrite fsid while METADATA_UUID flag is active. \n"
432482
"Ensure fsid and metadata_uuid match before retrying.");
433-
ret = 1;
483+
ret = -EINVAL;
434484
goto out;
435485
}
436486

@@ -442,24 +492,19 @@ int BOX_MAIN(btrfstune)(int argc, char *argv[])
442492
ret = ask_user("We are going to change UUID, are your sure?");
443493
if (!ret) {
444494
error("UUID change canceled");
445-
ret = 1;
495+
ret = -EINVAL;
446496
goto out;
447497
}
448498
}
449499
ret = change_uuid(fs_info, new_fsid_str);
450-
if (!ret)
451-
success++;
452-
total++;
500+
goto out;
453501
}
454-
455-
if (success == total) {
456-
ret = 0;
457-
} else {
502+
out:
503+
if (ret < 0) {
458504
fs_info->readonly = 1;
459505
ret = 1;
460506
error("btrfstune failed");
461507
}
462-
out:
463508
close_ctree(root);
464509
btrfs_close_all_devices();
465510

0 commit comments

Comments
 (0)