{
u16 num_stripes = btrfs_chunk_num_stripes(eb, chunk);
int i;
- u32 chunk_item_size = btrfs_chunk_item_size(num_stripes);
+ u32 chunk_item_size;
char chunk_flags_str[32] = {0};
+ /* The chunk must contain at least one stripe */
+ if (num_stripes < 1) {
+ printf("invalid num_stripes: %u\n", num_stripes);
+ return;
+ }
+
+ chunk_item_size = btrfs_chunk_item_size(num_stripes);
+
if ((unsigned long)chunk + chunk_item_size > eb->len) {
printf("\t\tchunk item invalid\n");
return;
case BTRFS_COMPRESS_LZO:
strcpy(ret, "lzo");
break;
+ case BTRFS_COMPRESS_ZSTD:
+ strcpy(ret, "zstd");
+ break;
default:
sprintf(ret, "UNKNOWN.%d", compress_type);
}
strcat(ret, "none");
}
+static void print_timespec(struct extent_buffer *eb,
+ struct btrfs_timespec *timespec, const char *prefix,
+ const char *suffix)
+{
+ struct tm tm;
+ u64 tmp_u64;
+ u32 tmp_u32;
+ time_t tmp_time;
+ char timestamp[256];
+
+ tmp_u64 = btrfs_timespec_sec(eb, timespec);
+ tmp_u32 = btrfs_timespec_nsec(eb, timespec);
+ tmp_time = tmp_u64;
+ localtime_r(&tmp_time, &tm);
+ strftime(timestamp, sizeof(timestamp),
+ "%Y-%m-%d %H:%M:%S", &tm);
+ printf("%s%llu.%u (%s)%s", prefix, (unsigned long long)tmp_u64, tmp_u32,
+ timestamp, suffix);
+}
+
static void print_root_item(struct extent_buffer *leaf, int slot)
{
struct btrfs_root_item *ri;
btrfs_root_stransid(&root_item),
btrfs_root_rtransid(&root_item));
}
+ if (btrfs_timespec_sec(leaf, btrfs_root_ctime(ri)))
+ print_timespec(leaf, btrfs_root_ctime(ri),
+ "\t\tctime ", "\n");
+ if (btrfs_timespec_sec(leaf, btrfs_root_otime(ri)))
+ print_timespec(leaf, btrfs_root_otime(ri),
+ "\t\totime ", "\n");
+ if (btrfs_timespec_sec(leaf, btrfs_root_stime(ri)))
+ print_timespec(leaf, btrfs_root_stime(ri),
+ "\t\tstime ", "\n");
+ if (btrfs_timespec_sec(leaf, btrfs_root_rtime(ri)))
+ print_timespec(leaf, btrfs_root_rtime(ri),
+ "\t\trtime ", "\n");
}
btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress);
case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
printf(" 0x%016llx)", (unsigned long long)offset);
break;
+
+ /*
+ * Key offsets of ROOT_ITEM point to tree root, print them in human
+ * readable format. Especially useful for trees like data/tree reloc
+ * tree, whose tree id can be negative.
+ */
+ case BTRFS_ROOT_ITEM_KEY:
+ printf(" ");
+ /*
+ * Normally offset of ROOT_ITEM should present the generation
+ * of creation time of the root.
+ * However if this is reloc tree, offset is the subvolume
+ * id of its source. Here we do extra check on this.
+ */
+ if (objectid == BTRFS_TREE_RELOC_OBJECTID)
+ print_objectid(stdout, offset, type);
+ else
+ printf("%lld", offset);
+ printf(")");
+ break;
default:
if (offset == (u64)-1)
printf(" -1)");
strcat(ret, "none");
}
-static void print_timespec(struct extent_buffer *eb,
- struct btrfs_timespec *timespec, const char *prefix,
- const char *suffix)
-{
- struct tm tm;
- u64 tmp_u64;
- u32 tmp_u32;
- time_t tmp_time;
- char timestamp[256];
-
- tmp_u64 = btrfs_timespec_sec(eb, timespec);
- tmp_u32 = btrfs_timespec_nsec(eb, timespec);
- tmp_time = tmp_u64;
- localtime_r(&tmp_time, &tm);
- strftime(timestamp, sizeof(timestamp),
- "%Y-%m-%d %H:%M:%S", &tm);
- printf("%s%llu.%u (%s)%s", prefix, (unsigned long long)tmp_u64, tmp_u32,
- timestamp, suffix);
-}
-
static void print_inode_item(struct extent_buffer *eb,
struct btrfs_inode_item *ii)
{
btrfs_inode_uid(eb, ii),
btrfs_inode_gid(eb, ii),
(unsigned long long)btrfs_inode_rdev(eb,ii),
- (unsigned long long)btrfs_inode_flags(eb,ii),
(unsigned long long)btrfs_inode_sequence(eb, ii),
+ (unsigned long long)btrfs_inode_flags(eb,ii),
flags_str);
print_timespec(eb, btrfs_inode_atime(ii), "\t\tatime ", "\n");
print_timespec(eb, btrfs_inode_ctime(ii), "\t\tctime ", "\n");
(long long)btrfs_qgroup_limit_rsv_exclusive(eb, qg_limit));
}
+static void print_persistent_item(struct extent_buffer *eb, void *ptr,
+ u32 item_size, u64 objectid, u64 offset)
+{
+ printf("\t\tpersistent item objectid ");
+ print_objectid(stdout, objectid, BTRFS_PERSISTENT_ITEM_KEY);
+ printf(" offset %llu\n", (unsigned long long)offset);
+ switch (objectid) {
+ case BTRFS_DEV_STATS_OBJECTID:
+ print_dev_stats(eb, ptr, item_size);
+ break;
+ default:
+ printf("\t\tunknown persistent item objectid %llu\n", objectid);
+ }
+}
+
+static void print_temporary_item(struct extent_buffer *eb, void *ptr,
+ u64 objectid, u64 offset)
+{
+ printf("\t\ttemporary item objectid ");
+ print_objectid(stdout, objectid, BTRFS_TEMPORARY_ITEM_KEY);
+ printf(" offset %llu\n", (unsigned long long)offset);
+ switch (objectid) {
+ case BTRFS_BALANCE_OBJECTID:
+ print_balance_item(eb, ptr);
+ break;
+ default:
+ printf("\t\tunknown temporary item objectid %llu\n", objectid);
+ }
+}
+
+static void print_extent_csum(struct extent_buffer *eb,
+ struct btrfs_fs_info *fs_info, u32 item_size, u64 start)
+{
+ u32 size;
+
+ size = (item_size / btrfs_super_csum_size(fs_info->super_copy)) *
+ fs_info->sectorsize;
+ printf("\t\trange start %llu end %llu length %u\n",
+ (unsigned long long)start,
+ (unsigned long long)start + size, size);
+}
+
/* Caller must ensure sizeof(*ret) >= 14 "WRITTEN|RELOC" */
static void header_flags_to_str(u64 flags, char *ret)
{
}
}
-void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *eb)
+void btrfs_print_leaf(struct extent_buffer *eb)
{
+ struct btrfs_fs_info *fs_info = eb->fs_info;
struct btrfs_item *item;
struct btrfs_disk_key disk_key;
char flags_str[128];
header_flags_to_str(flags, flags_str);
nr = btrfs_header_nritems(eb);
- printf("leaf %llu items %d free space %d generation %llu owner %llu\n",
+ printf("leaf %llu items %d free space %d generation %llu owner ",
(unsigned long long)btrfs_header_bytenr(eb), nr,
- btrfs_leaf_free_space(root, eb),
- (unsigned long long)btrfs_header_generation(eb),
- (unsigned long long)btrfs_header_owner(eb));
+ btrfs_leaf_free_space(fs_info, eb),
+ (unsigned long long)btrfs_header_generation(eb));
+ print_objectid(stdout, btrfs_header_owner(eb), 0);
+ printf("\n");
printf("leaf %llu flags 0x%llx(%s) backref revision %d\n",
btrfs_header_bytenr(eb), flags, flags_str, backref_rev);
print_uuids(eb);
printf("\t\tcsum item\n");
break;
case BTRFS_EXTENT_CSUM_KEY:
- printf("\t\textent csum item\n");
+ print_extent_csum(eb, fs_info, item_size,
+ offset);
break;
case BTRFS_EXTENT_DATA_KEY:
print_file_extent_item(eb, item, i, ptr);
break;
}
case BTRFS_PERSISTENT_ITEM_KEY:
- printf("\t\tpersistent item objectid ");
- print_objectid(stdout, objectid, BTRFS_PERSISTENT_ITEM_KEY);
- printf(" offset %llu\n", (unsigned long long)offset);
- switch (objectid) {
- case BTRFS_DEV_STATS_OBJECTID:
- print_dev_stats(eb, ptr, item_size);
- break;
- default:
- printf("\t\tunknown persistent item objectid %llu\n",
- objectid);
- }
+ print_persistent_item(eb, ptr, item_size, objectid,
+ offset);
break;
case BTRFS_TEMPORARY_ITEM_KEY:
- printf("\t\ttemporary item objectid ");
- print_objectid(stdout, objectid, BTRFS_TEMPORARY_ITEM_KEY);
- printf(" offset %llu\n", (unsigned long long)offset);
- switch (objectid) {
- case BTRFS_BALANCE_OBJECTID:
- print_balance_item(eb, ptr);
- break;
- default:
- printf("\t\tunknown temporary item objectid %llu\n",
- objectid);
- }
+ print_temporary_item(eb, ptr, objectid, offset);
break;
};
fflush(stdout);
}
}
-void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow)
+void btrfs_print_tree(struct extent_buffer *eb, int follow)
{
u32 i;
u32 nr;
+ struct btrfs_fs_info *fs_info = eb->fs_info;
struct btrfs_disk_key disk_key;
struct btrfs_key key;
struct extent_buffer *next;
return;
nr = btrfs_header_nritems(eb);
if (btrfs_is_leaf(eb)) {
- btrfs_print_leaf(root, eb);
+ btrfs_print_leaf(eb);
return;
}
- printf("node %llu level %d items %d free %u generation %llu owner %llu\n",
+ printf("node %llu level %d items %d free %u generation %llu owner ",
(unsigned long long)eb->start,
btrfs_header_level(eb), nr,
- (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
- (unsigned long long)btrfs_header_generation(eb),
- (unsigned long long)btrfs_header_owner(eb));
+ (u32)BTRFS_NODEPTRS_PER_BLOCK(fs_info) - nr,
+ (unsigned long long)btrfs_header_generation(eb));
+ print_objectid(stdout, btrfs_header_owner(eb), 0);
+ printf("\n");
print_uuids(eb);
fflush(stdout);
for (i = 0; i < nr; i++) {
btrfs_print_key(&disk_key);
printf(" block %llu (%llu) gen %llu\n",
(unsigned long long)blocknr,
- (unsigned long long)blocknr / root->fs_info->nodesize,
+ (unsigned long long)blocknr / fs_info->nodesize,
(unsigned long long)btrfs_node_ptr_generation(eb, i));
fflush(stdout);
}
return;
for (i = 0; i < nr; i++) {
- next = read_tree_block(root->fs_info,
+ next = read_tree_block(fs_info,
btrfs_node_blockptr(eb, i),
btrfs_node_ptr_generation(eb, i));
if (!extent_buffer_uptodate(next)) {
(unsigned long long)btrfs_header_owner(eb));
continue;
}
- if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
- warning(
- "eb corrupted: item %d eb level %d next level %d, skipping the rest",
- i, btrfs_header_level(next),
- btrfs_header_level(eb));
- goto out;
- }
if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) {
warning(
- "eb corrupted: item %d eb level %d next level %d, skipping the rest",
- i, btrfs_header_level(next),
- btrfs_header_level(eb));
- goto out;
+"eb corrupted: parent bytenr %llu slot %d level %d child bytenr %llu level has %d expect %d, skipping the slot",
+ btrfs_header_bytenr(eb), i,
+ btrfs_header_level(eb),
+ btrfs_header_bytenr(next),
+ btrfs_header_level(next),
+ btrfs_header_level(eb) - 1);
+ free_extent_buffer(next);
+ continue;
}
- btrfs_print_tree(root, next, 1);
+ btrfs_print_tree(next, 1);
free_extent_buffer(next);
}
return;
-out:
free_extent_buffer(next);
}