Skip to content

Commit 6baa1a7

Browse files
pdzhuadam900710
authored andcommitted
btrfs-progs: check: add option to skip qgroup accounting verification
Qgroup accounting verification can be expensive because it walks extents and backrefs to recompute referenced/exclusive numbers. Add --skip-qgroup-accounting so btrfs check can still load qgroup status/info/relation items from the quota tree without verifying the accounting numbers. Reject the option with --repair and --qgroup-report, as both depend on full accounting verification results. Signed-off-by: Dongjiang Zhu <zhudongjiang@fnnas.com> Reviewed-by: Qu Wenruo <wqu@suse.com>
1 parent 2bd9c1b commit 6baa1a7

5 files changed

Lines changed: 58 additions & 18 deletions

File tree

Documentation/btrfs-check.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ SAFE OR ADVISORY OPTIONS
5858
This expects that the filesystem is otherwise OK, and is basically an offline
5959
*scrub* that does not repair data from spare copies.
6060

61+
--skip-qgroup-accounting
62+
skip verification of qgroup referenced/exclusive accounting.
63+
64+
Qgroup status, info and relation items are still loaded from the quota
65+
tree. This option cannot be used with *--repair* or *--qgroup-report*.
66+
67+
This can significantly reduce runtime on filesystems with many snapshots
68+
or reflinked files, as full qgroup accounting verification can require
69+
extensive backref walks.
70+
6171
--chunk-root <bytenr>
6272
use the given offset *bytenr* for the chunk tree root
6373

check/main.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ bool no_holes = false;
8686
bool is_free_space_tree = false;
8787
bool init_extent_tree = false;
8888
bool check_data_csum = false;
89+
static bool check_qgroup_accounting = true;
8990
static bool found_free_ino_cache = false;
9091
static bool found_unknown_key = false;
9192
struct cache_tree *roots_info_cache = NULL;
@@ -217,7 +218,9 @@ static void print_status_check_line(void *p)
217218
"[5/7] checking csums against data " :
218219
"[5/7] checking csums (without verifying data) ",
219220
"[6/7] checking root refs ",
220-
"[7/7] checking quota groups ",
221+
check_qgroup_accounting ?
222+
"[7/7] checking quota groups " :
223+
"[7/7] checking qgroups (no accounting verify) ",
221224
};
222225
time_t elapsed;
223226
int hours;
@@ -10597,6 +10600,7 @@ static const char * const cmd_check_usage[] = {
1059710600
"",
1059810601
"Check and reporting options:",
1059910602
OPTLINE("--check-data-csum", "verify checksums of data blocks"),
10603+
OPTLINE("--skip-qgroup-accounting", "skip quota group accounting verification"),
1060010604
OPTLINE("-Q, --qgroup-report", "print a report on qgroup consistency"),
1060110605
OPTLINE("-E, --subvol-extents SUBVOLID", "print subvolume extents and sharing state"),
1060210606
OPTLINE("-p, --progress", "indicate progress"),
@@ -10636,7 +10640,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1063610640
GETOPT_VAL_INIT_EXTENT, GETOPT_VAL_CHECK_CSUM,
1063710641
GETOPT_VAL_READONLY, GETOPT_VAL_CHUNK_TREE,
1063810642
GETOPT_VAL_MODE, GETOPT_VAL_CLEAR_SPACE_CACHE,
10639-
GETOPT_VAL_FORCE };
10643+
GETOPT_VAL_FORCE, GETOPT_VAL_SKIP_QGROUP_ACCOUNTING };
1064010644
static const struct option long_options[] = {
1064110645
{ "super", required_argument, NULL, 's' },
1064210646
{ "repair", no_argument, NULL, GETOPT_VAL_REPAIR },
@@ -10647,6 +10651,8 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1064710651
GETOPT_VAL_INIT_EXTENT },
1064810652
{ "check-data-csum", no_argument, NULL,
1064910653
GETOPT_VAL_CHECK_CSUM },
10654+
{ "skip-qgroup-accounting", no_argument, NULL,
10655+
GETOPT_VAL_SKIP_QGROUP_ACCOUNTING },
1065010656
{ "backup", no_argument, NULL, 'b' },
1065110657
{ "subvol-extents", required_argument, NULL, 'E' },
1065210658
{ "qgroup-report", no_argument, NULL, 'Q' },
@@ -10719,6 +10725,9 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1071910725
case GETOPT_VAL_CHECK_CSUM:
1072010726
check_data_csum = true;
1072110727
break;
10728+
case GETOPT_VAL_SKIP_QGROUP_ACCOUNTING:
10729+
check_qgroup_accounting = false;
10730+
break;
1072210731
case GETOPT_VAL_MODE:
1072310732
check_mode = parse_check_mode(optarg);
1072410733
if (check_mode == CHECK_MODE_UNKNOWN) {
@@ -10762,6 +10771,15 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1076210771
exit(1);
1076310772
}
1076410773

10774+
if (!check_qgroup_accounting && opt_check_repair) {
10775+
error("--skip-qgroup-accounting is not compatible with --repair");
10776+
exit(1);
10777+
}
10778+
if (!check_qgroup_accounting && qgroup_report) {
10779+
error("--skip-qgroup-accounting is not compatible with --qgroup-report");
10780+
exit(1);
10781+
}
10782+
1076510783
if (opt_check_repair && !force) {
1076610784
int delay = 10;
1076710785

@@ -10882,7 +10900,7 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1088210900

1088310901
if (qgroup_report) {
1088410902
printf("Print quota groups report for %s\nUUID: %s\n", argv[optind], uuidbuf);
10885-
ret = qgroup_verify_all(gfs_info);
10903+
ret = qgroup_verify(gfs_info, true);
1088610904
err |= !!ret;
1088710905
if (ret >= 0)
1088810906
report_qgroups(1);
@@ -11143,26 +11161,32 @@ static int cmd_check(const struct cmd_struct *cmd, int argc, char **argv)
1114311161

1114411162
if (gfs_info->quota_enabled) {
1114511163
if (!g_task_ctx.progress_enabled) {
11146-
fprintf(stderr, "[8/8] checking quota groups\n");
11164+
if (check_qgroup_accounting)
11165+
fprintf(stderr, "[8/8] checking quota groups\n");
11166+
else
11167+
fprintf(stderr,
11168+
"[8/8] checking quota groups (without verifying accounting)\n");
1114711169
} else {
1114811170
g_task_ctx.tp = TASK_QGROUPS;
1114911171
task_start(g_task_ctx.info, &g_task_ctx.start_time, &g_task_ctx.item_count);
1115011172
}
11151-
qgroup_verify_ret = qgroup_verify_all(gfs_info);
11173+
qgroup_verify_ret = qgroup_verify(gfs_info, check_qgroup_accounting);
1115211174
task_stop(g_task_ctx.info);
1115311175
if (qgroup_verify_ret < 0) {
1115411176
error("failed to check quota groups");
1115511177
err |= !!qgroup_verify_ret;
1115611178
goto out;
1115711179
}
11158-
report_qgroups(0);
11159-
ret = repair_qgroups(gfs_info, &qgroups_repaired, false);
11160-
if (ret) {
11161-
error("failed to repair quota groups");
11162-
goto out;
11180+
if (check_qgroup_accounting) {
11181+
report_qgroups(0);
11182+
ret = repair_qgroups(gfs_info, &qgroups_repaired, false);
11183+
if (ret) {
11184+
error("failed to repair quota groups");
11185+
goto out;
11186+
}
11187+
if (qgroup_verify_ret && (!qgroups_repaired || ret))
11188+
err |= !!qgroup_verify_ret;
1116311189
}
11164-
if (qgroup_verify_ret && (!qgroups_repaired || ret))
11165-
err |= !!qgroup_verify_ret;
1116611190
ret = 0;
1116711191
} else {
1116811192
fprintf(stderr,

check/qgroup-verify.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,13 +1451,16 @@ static bool is_bad_qgroup(struct qgroup_count *count)
14511451
}
14521452

14531453
/*
1454-
* Verify all qgroup numbers.
1454+
* Load qgroup items and optionally verify qgroup numbers.
1455+
*
1456+
* @check_accounting true: verify referenced/exclusive accounting.
1457+
* @check_accounting false: only load qgroup status/info/relation items.
14551458
*
14561459
* Return <0 for fatal errors (e.g. ENOMEM or failed to read quota tree)
1457-
* Return 0 if all qgroup numbers are correct or no need to check (under rescan)
1458-
* Return >0 if qgroup numbers are inconsistent.
1460+
* Return 0 if requested checks pass or accounting mismatches are ignored.
1461+
* Return >0 if qgroup numbers are inconsistent and not ignored.
14591462
*/
1460-
int qgroup_verify_all(struct btrfs_fs_info *info)
1463+
int qgroup_verify(struct btrfs_fs_info *info, bool check_accounting)
14611464
{
14621465
struct rb_node *n;
14631466
int ret;
@@ -1486,6 +1489,9 @@ int qgroup_verify_all(struct btrfs_fs_info *info)
14861489
counts.rescan_running == 0)
14871490
skip_err = true;
14881491

1492+
if (!check_accounting)
1493+
goto out;
1494+
14891495
/*
14901496
* Put all extent refs into our rbtree
14911497
*/

check/qgroup-verify.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
struct btrfs_fs_info;
2626

27-
int qgroup_verify_all(struct btrfs_fs_info *info);
27+
int qgroup_verify(struct btrfs_fs_info *info, bool check_accounting);
2828
void report_qgroups(int all);
2929
int repair_qgroups(struct btrfs_fs_info *info, int *repaired, bool silent);
3030

mkfs/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ static int setup_quota_root(struct btrfs_fs_info *fs_info)
10461046
* Qgroup is setup but with wrong info, use qgroup-verify
10471047
* infrastructure to repair them. (Just acts as offline rescan)
10481048
*/
1049-
ret = qgroup_verify_all(fs_info);
1049+
ret = qgroup_verify(fs_info, true);
10501050
if (ret < 0) {
10511051
errno = -ret;
10521052
error("qgroup rescan failed: %m");

0 commit comments

Comments
 (0)