@@ -3991,10 +3991,115 @@ static int do_check_fs_roots(struct cache_tree *root_cache)
return ret;
}
+/*
+ * Define the minimal size for a buffer to describe the data backref.
+ * It needs to support something like:
+ * root <U64_MAX> owner <U64_MAX> offset <U64_MAX>
+ * Or
+ * parent <U64_MAX>
+ *
+ * Obviously the first pattern needs longer buffer size.
+ * The minimal size (including the tailing NUL) would be:
+ * 5 + 20 + 7 + 20 + 8 + 20 = 80.
+ *
+ * Just round it to 128 to provide extra wiggle room.
+ */
+#define DATA_EXTENT_DESC_BUF_LEN (128)
+static void describe_data_extent_backref(char *buf,
+ struct data_backref *dback)
+{
+ if (dback->node.full_backref)
+ sprintf(buf, "parent %llu", dback->parent);
+ else
+ sprintf(buf, "root %llu owner %llu offset %llu",
+ dback->root, dback->owner, dback->offset);
+}
+
+static void print_data_backref_error(struct extent_record *rec,
+ struct data_backref *dback)
+{
+ struct extent_backref *back = &dback->node;
+ char desc[DATA_EXTENT_DESC_BUF_LEN] = { 0 };
+ u32 found_refs;
+ u32 expected_refs;
+
+ if (!back->found_extent_tree) {
+ /*
+ * No backref item in extent tree.
+ * Thus expected refs should be 0.
+ */
+ expected_refs = 0;
+ found_refs = dback->found_ref;
+ } else {
+ expected_refs = dback->num_refs;
+ found_refs = dback->found_ref;
+ }
+
+ /* Extent item bytenr mismatch with found file extent item. */
+ if (dback->disk_bytenr != rec->start)
+ fprintf(stderr,
+"data extent[%llu, %llu] bytenr mimsmatch, extent item bytenr %llu file item bytenr %llu\n",
+ rec->start, rec->max_size, rec->start,
+ dback->disk_bytenr);
+
+ /* Extent item size mismatch with found file item. */
+ if (dback->bytes != rec->nr)
+ fprintf(stderr,
+"data extent[%llu, %llu] size mimsmatch, extent item size %llu file item size %llu\n",
+ rec->start, rec->max_size, rec->nr, dback->bytes);
+
+ if (expected_refs != found_refs) {
+ describe_data_extent_backref(desc, dback);
+ fprintf(stderr,
+"data extent[%llu, %llu] referencer count mismatch (%s) wanted %u have %u\n",
+ rec->start, rec->max_size, desc, expected_refs,
+ found_refs);
+ }
+}
+
+static void print_tree_backref_error(struct extent_record *rec,
+ struct tree_backref *tback)
+{
+ struct extent_backref *back = &tback->node;
+
+ /*
+ * For tree blocks, we only handle two cases here:
+ * - No backref item in extent tree
+ * - No tree block found (but with backref item)
+ *
+ * The refs count check is done by the global backref check at
+ * all_backpointers_checked().
+ */
+ if (!back->found_extent_tree) {
+ fprintf(stderr,
+"tree extent[%llu, %llu] %s %llu has no backref item in extent tree\n",
+ rec->start, rec->max_size,
+ back->full_backref ? "parent" : "root",
+ back->full_backref ? tback->parent : tback->root);
+ return;
+ }
+ if (!back->found_ref) {
+ fprintf(stderr,
+"tree extent[%llu, %llu] %s %llu has no tree block found\n",
+ rec->start, rec->max_size,
+ back->full_backref ? "parent" : "root",
+ back->full_backref ? tback->parent : tback->root);
+ return;
+ }
+}
+
+static void print_backref_error(struct extent_record *rec,
+ struct extent_backref *back)
+{
+ if (back->is_data)
+ print_data_backref_error(rec, to_data_backref(back));
+ else
+ print_tree_backref_error(rec, to_tree_backref(back));
+}
+
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
{
struct extent_backref *back, *tmp;
- struct tree_backref *tback;
struct data_backref *dback;
u64 found = 0;
int err = 0;
@@ -4005,42 +4110,11 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
err = 1;
if (!print_errs)
goto out;
- if (back->is_data) {
- dback = to_data_backref(back);
- fprintf(stderr,
-"data backref %llu %s %llu owner %llu offset %llu num_refs %lu not found in extent tree\n",
- (unsigned long long)rec->start,
- back->full_backref ?
- "parent" : "root",
- back->full_backref ?
- (unsigned long long)dback->parent :
- (unsigned long long)dback->root,
- (unsigned long long)dback->owner,
- (unsigned long long)dback->offset,
- (unsigned long)dback->num_refs);
- } else {
- tback = to_tree_backref(back);
- fprintf(stderr,
-"tree backref %llu %s %llu not found in extent tree\n",
- (unsigned long long)rec->start,
- back->full_backref ? "parent" : "root",
- back->full_backref ?
- (unsigned long long)tback->parent :
- (unsigned long long)tback->root);
- }
}
- if (!back->is_data && !back->found_ref) {
+ if (!back->found_ref) {
err = 1;
if (!print_errs)
goto out;
- tback = to_tree_backref(back);
- fprintf(stderr,
- "backref %llu %s %llu not referenced back %p\n",
- (unsigned long long)rec->start,
- back->full_backref ? "parent" : "root",
- back->full_backref ?
- (unsigned long long)tback->parent :
- (unsigned long long)tback->root, back);
}
if (back->is_data) {
dback = to_data_backref(back);
@@ -4048,38 +4122,17 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
err = 1;
if (!print_errs)
goto out;
- fprintf(stderr,
-"incorrect local backref count on %llu %s %llu owner %llu offset %llu found %u wanted %u back %p\n",
- (unsigned long long)rec->start,
- back->full_backref ?
- "parent" : "root",
- back->full_backref ?
- (unsigned long long)dback->parent :
- (unsigned long long)dback->root,
- (unsigned long long)dback->owner,
- (unsigned long long)dback->offset,
- dback->found_ref, dback->num_refs,
- back);
}
if (dback->disk_bytenr != rec->start) {
err = 1;
if (!print_errs)
goto out;
- fprintf(stderr,
-"backref disk bytenr does not match extent record, bytenr=%llu, ref bytenr=%llu\n",
- (unsigned long long)rec->start,
- (unsigned long long)dback->disk_bytenr);
}
if (dback->bytes != rec->nr) {
err = 1;
if (!print_errs)
goto out;
- fprintf(stderr,
-"backref bytes do not match extent backref, bytenr=%llu, ref bytes=%llu, backref bytes=%llu\n",
- (unsigned long long)rec->start,
- (unsigned long long)rec->nr,
- (unsigned long long)dback->bytes);
}
}
if (!back->is_data) {
@@ -4088,6 +4141,8 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
dback = to_data_backref(back);
found += dback->found_ref;
}
+ if (err)
+ print_backref_error(rec, back);
}
if (found != rec->refs) {
err = 1;
[PROBLEM] Btrfs check original mode output is not that reader friendly already, it even includes pointer output: backref 15353727729664 parent 1140559929556992 not referenced back 0xc9133d70 tree backref 15353727729664 parent 14660022714368 not found in extent tree incorrect global backref count on 15353727729664 found 3 wanted 2 backpointer mismatch on [15353727729664 16384] In above case, the "0xc9133d70" is completely useless, as it's a pointer for the tree_backref structure. And the term "backref" is quite abused in above case. [ENHANCEMENT] To enhance the situation, let's use some output format from lowmem mode instead. Now above example will be changed to: tree extent[15353727729664, 16384] parent 1140559929556992 has no tree block found tree extent[15353727729664, 16384] parent 14660022714368 has no backref item in extent tree incorrect global backref count on 15353727729664 found 3 wanted 2 backpointer mismatch on [15353727729664 16384] And some example for data backrefs: data extent[12845056, 1048576] bytenr mimsmatch, extent item bytenr 12845056 file item bytenr 0 data extent[12845056, 1048576] referencer count mismatch (root 5 owner 257 offset 0) wanted 1 have 0 data extent[14233600, 12288] referencer count mismatch (parent 42139648) wanted 0 have 1 data extent[14233600, 12288] referencer count mismatch (root 5 owner 307 offset 0) wanted 0 have 1 data extent[14233600, 12288] referencer count mismatch (parent 30507008) wanted 0 have 1 Furthermore, the original function print_tree_backref_error() is a mess already, here we clean it up by exacting all the error output into a dedicated helper, print_backref_error(), so the function itself only need to find out errors. Signed-off-by: Qu Wenruo <wqu@suse.com> --- check/main.c | 163 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 54 deletions(-)