Add some more file layout output, triggered by -v

With one -v, the block type (parity or data) is printed (matching
the ASCII-art version); with two -v, the offset into the file is
also printed.

This also updates the man page, and adds some simple
test scripts.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Sean Fagan <sean.fagan@klarasystems.com>
Signed-off-by: Sean Fagan <sean.fagan@klarasystems.com>
Closes #18470
This commit is contained in:
Sean Eric Fagan
2026-05-07 21:22:38 +01:00
committed by GitHub
parent 439b802e77
commit a2d053329c
8 changed files with 353 additions and 20 deletions
+42 -10
View File
@@ -2802,18 +2802,18 @@ print_file_layout_raidz(vdev_t *vd, blkptr_t *bp, uint64_t file_offset,
vd->vdev_children, vdrz->vd_nparity); vd->vdev_children, vdrz->vd_nparity);
raidz_row_t *rr = rm->rm_row[0]; raidz_row_t *rr = rm->rm_row[0];
if (!dump_opt['H']) {
int last_disk = vd->vdev_children - 1;
/* /*
* Account for out of order disks in raidz1. * Account for out of order disks in raidz1.
* For now just reverse them back and adjust for it later. * For now just reverse them back and adjust for it later.
*/ */
if (rr->rr_firstdatacol == 1 && (zio.io_offset & (1ULL << 20))) { if (rr->rr_firstdatacol == 1 &&
(zio.io_offset & (1ULL << 20))) {
uint64_t devidx = rr->rr_col[0].rc_devidx; uint64_t devidx = rr->rr_col[0].rc_devidx;
rr->rr_col[0].rc_devidx = rr->rr_col[1].rc_devidx; rr->rr_col[0].rc_devidx = rr->rr_col[1].rc_devidx;
rr->rr_col[1].rc_devidx = devidx; rr->rr_col[1].rc_devidx = devidx;
} }
if (!dump_opt['H']) {
int last_disk = vd->vdev_children - 1;
int first_disk = rr->rr_col[0].rc_devidx; int first_disk = rr->rr_col[0].rc_devidx;
(void) printf("%12llx", (u_longlong_t)file_offset); (void) printf("%12llx", (u_longlong_t)file_offset);
@@ -2843,23 +2843,49 @@ print_file_layout_raidz(vdev_t *vd, blkptr_t *bp, uint64_t file_offset,
static uint64_t next_offset = 0; static uint64_t next_offset = 0;
if (next_offset != file_offset) { if (next_offset != file_offset) {
(void) printf("skip hole\t-\t%llx\n", (void) printf("skip hole\t-\t\t%lld\n",
(u_longlong_t)((file_offset - next_offset) >> (u_longlong_t)((file_offset - next_offset) / 512));
vd->vdev_ashift));
} }
next_offset = file_offset + BP_GET_LSIZE(bp); next_offset = file_offset + BP_GET_LSIZE(bp);
uint64_t tmp_offset = file_offset;
for (int c = 0; c < rr->rr_cols; c++) { for (int c = 0; c < rr->rr_cols; c++) {
boolean_t pcol = c < rr->rr_firstdatacol;
raidz_col_t *rc = &rr->rr_col[c]; raidz_col_t *rc = &rr->rr_col[c];
char *path = vd->vdev_child[rc->rc_devidx]->vdev_path; char *path = vd->vdev_child[rc->rc_devidx]->vdev_path;
// c < rr->rr_firstdatacol
if (rc->rc_size == 0) if (rc->rc_size == 0)
continue; continue;
(void) printf("%s\t%llu\t%d\n", (void) printf("%s\t\t%llu\t%d",
zfs_basename(path), zfs_basename(path),
(u_longlong_t)(rc->rc_offset + (u_longlong_t)(rc->rc_offset +
VDEV_LABEL_START_SIZE)/512, VDEV_LABEL_START_SIZE)/512,
(int)rc->rc_size/512); (int)rc->rc_size/512);
if (dump_opt['v']) {
char label = pcol ? 'P' : 'D';
int num;
if (c < 2) {
num = 0;
} else {
num = pcol ? c :
(c - rr->rr_firstdatacol);
}
printf("\t%c%d", label, num);
if (dump_opt['v'] > 1) {
unsigned long long off;
if (pcol)
off = file_offset;
else
off = tmp_offset;
off = off / 512ULL;
printf("\t%llu", off);
}
}
if (!pcol)
tmp_offset += rc->rc_size;
printf("\n");
} }
} }
} }
@@ -2989,7 +3015,12 @@ dump_indirect_layout(dnode_t *dn)
* Start layout with a header * Start layout with a header
*/ */
if (dump_opt['H']) { if (dump_opt['H']) {
(void) printf("DISK\t\tLBA\t\tCOUNT\n"); (void) printf("DISK\t\t\tLBA\tCOUNT");
if (dump_opt['v'])
(void) printf("\tTYPE");
if (dump_opt['v'] > 1)
(void) printf("\tOFFSET");
printf("\n");
} else { } else {
char diskhdr[16]; char diskhdr[16];
@@ -10519,6 +10550,7 @@ main(int argc, char **argv)
} }
if (dump_opt['f'] && os != NULL) { if (dump_opt['f'] && os != NULL) {
dump_opt['v'] = verbose;
dump_file_data_layout(os); dump_file_data_layout(os);
} else if (dump_opt['B']) { } else if (dump_opt['B']) {
dump_backup(target, objset_id, dump_backup(target, objset_id,
+6 -1
View File
@@ -284,10 +284,15 @@ Decode and display block from an embedded block pointer specified by the
arguments. arguments.
.It Fl f , -file-layout .It Fl f , -file-layout
Display the file layout of an object for the disks of a raidz vdev. Display the file layout of an object for the disks of a raidz vdev.
Numeric values in the disply are hexadecimal.
With With
.Fl H , .Fl H ,
the output is in scripted mode for easy parsing, with all values the output is in scripted mode for easy parsing, with all values
being presented as 512 byte blocks. being presented as 512 byte blocks in decimal; with
.Fl v ,
the block type (parity or data) is displayed; with
.Fl vv ,
the offset into the file for each block is also printed.
Only a single top-level raidz vdev is supported. Only a single top-level raidz vdev is supported.
.It Fl h , -history .It Fl h , -history
Display pool history similar to Display pool history similar to
+4 -3
View File
@@ -173,9 +173,10 @@ tests = ['zdb_002_pos', 'zdb_003_pos', 'zdb_004_pos', 'zdb_005_pos',
'zdb_006_pos', 'zdb_args_neg', 'zdb_args_pos', 'zdb_006_pos', 'zdb_args_neg', 'zdb_args_pos',
'zdb_block_size_histogram', 'zdb_checksum', 'zdb_decompress', 'zdb_block_size_histogram', 'zdb_checksum', 'zdb_decompress',
'zdb_display_block', 'zdb_encrypted', 'zdb_encrypted_raw', 'zdb_display_block', 'zdb_encrypted', 'zdb_encrypted_raw',
'zdb_label_checksum', 'zdb_object_range_neg', 'zdb_object_range_pos', 'zdb_file_layout_001', 'zdb_file_layout_002', 'zdb_file_layout_003',
'zdb_objset_id', 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2', 'zdb_file_layout_neg', 'zdb_label_checksum', 'zdb_object_range_neg',
'zdb_backup', 'zdb_tunables'] 'zdb_object_range_pos', 'zdb_objset_id', 'zdb_decompress_zstd',
'zdb_recover', 'zdb_recover_2', 'zdb_backup', 'zdb_tunables']
pre = pre =
post = post =
tags = ['functional', 'cli_root', 'zdb'] tags = ['functional', 'cli_root', 'zdb']
+4
View File
@@ -650,6 +650,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zdb/zdb_encrypted.ksh \ functional/cli_root/zdb/zdb_encrypted.ksh \
functional/cli_root/zdb/zdb_encrypted_raw.ksh \ functional/cli_root/zdb/zdb_encrypted_raw.ksh \
functional/cli_root/zdb/zdb_label_checksum.ksh \ functional/cli_root/zdb/zdb_label_checksum.ksh \
functional/cli_root/zdb/zdb_file_layout_001.ksh \
functional/cli_root/zdb/zdb_file_layout_002.ksh \
functional/cli_root/zdb/zdb_file_layout_003.ksh \
functional/cli_root/zdb/zdb_file_layout_neg.ksh \
functional/cli_root/zdb/zdb_object_range_neg.ksh \ functional/cli_root/zdb/zdb_object_range_neg.ksh \
functional/cli_root/zdb/zdb_object_range_pos.ksh \ functional/cli_root/zdb/zdb_object_range_pos.ksh \
functional/cli_root/zdb/zdb_objset_id.ksh \ functional/cli_root/zdb/zdb_objset_id.ksh \
@@ -0,0 +1,78 @@
#!/bin/ksh
# SPDX-License-Identifier: CDDL-1.0
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright (c) 2019 by Datto, Inc. All rights reserved.
# Copyright (c) 2026, Klara Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# Description:
# zdb -fHv <dataset> <objnum> will display block
# layouts for the object.
#
# Strategery:
# 1. Create a RAIDZ1 pool, set compression to none
# 2. Create a file filled with random data
# 3. Get the inode number of the file
# 4. Run zdb -fHv <pool>/ <inum> & extract file
# 5. Compare real file and extracted file.
DATA=/$TESTPOOL1/random.bin
BLOCKS=$(( $RANDOM % 16 ))
COMPARE=/tmp/compare.$$
function cleanup
{
destroy_pool $TESTPOOL1
rm -f $TESTDIR/file?.bin $COMPARE
}
log_assert "Verify zdb -fHv displays correct offsets"
log_onexit cleanup
# 1. Create a RAIDZ1 pool
log_must mkdir -p $TESTDIR
for file in 1 2 3 4 5
do
rm -f $TESTDIR/file${file}.bin
touch $TESTDIR/file${file}.bin
log_must truncate -s 128m $TESTDIR/file${file}.bin
done
log_must zpool create -O compression=off -O recordsize=16K $TESTPOOL1 raidz1 $TESTDIR/file[12345].bin
zfs get compression,recordsize $TESTPOOL1
# 2. Create a file with random data
log_must rm -f $DATA
log_must dd if=/dev/urandom of=${DATA} bs=16k count=${BLOCKS} > /dev/null 2>&1
log_must zpool sync $TESTPOOL1
# 3. Get the inode number of the file
INUM=$(ls -li $DATA | cut -f1 -d ' ')
# 4. Extract the contents of the file using dd
rm -f $COMPARE
log_must touch ${COMPARE}
log_must zdb -fHv $TESTPOOL1/ ${INUM} | grep 'D.$' |
while read file offset count rest
do
log_must sh -c "dd if=$TESTDIR/${file} bs=512 skip=${offset} count=${count} >> ${COMPARE}"
done
# 5. Compare files
log_must cmp ${COMPARE} ${DATA}
log_pass "'zdb -fHv' works as expected."
@@ -0,0 +1,78 @@
#!/bin/ksh
# SPDX-License-Identifier: CDDL-1.0
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright (c) 2019 by Datto, Inc. All rights reserved.
# Copyright (c) 2026, Klara Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# Description:
# zdb -fHv <dataset> <objnum> will display block
# layouts for the object.
#
# Strategery:
# 1. Create a RAIDZ2 pool, set compression to none
# 2. Create a file filled with random data
# 3. Get the inode number of the file
# 4. Run zdb -fHv <pool>/ <inum> & extract file
# 5. Compare real file and extracted file.
DATA=/$TESTPOOL1/random.bin
BLOCKS=$(( $RANDOM % 16 ))
COMPARE=/tmp/compare.$$
function cleanup
{
destroy_pool $TESTPOOL1
rm -f $TESTDIR/file?.bin $COMPARE
}
log_assert "Verify zdb -fHv displays correct offsets"
log_onexit cleanup
# 1. Create a RAIDZ1 pool
log_must mkdir -p $TESTDIR
for file in 1 2 3 4 5 6
do
rm -f $TESTDIR/file${file}.bin
touch $TESTDIR/file${file}.bin
log_must truncate -s 128m $TESTDIR/file${file}.bin
done
log_must zpool create -O compression=off -O recordsize=16K $TESTPOOL1 raidz2 $TESTDIR/file[123456].bin
zfs get compression,recordsize $TESTPOOL1
# 2. Create a file with random data
log_must rm -f $DATA
log_must dd if=/dev/urandom of=${DATA} bs=16k count=${BLOCKS} > /dev/null 2>&1
log_must zpool sync $TESTPOOL1
# 3. Get the inode number of the file
INUM=$(ls -li $DATA | cut -f1 -d ' ')
# 4. Extract the contents of the file using dd
rm -f $COMPARE
log_must touch ${COMPARE}
log_must zdb -fHv $TESTPOOL1/ ${INUM} | grep 'D.$' |
while read file offset count rest
do
log_must sh -c "dd if=$TESTDIR/${file} bs=512 skip=${offset} count=${count} >> ${COMPARE}"
done
# 5. Compare files
log_must cmp ${COMPARE} ${DATA}
log_pass "'zdb -fHv' works as expected."
@@ -0,0 +1,78 @@
#!/bin/ksh
# SPDX-License-Identifier: CDDL-1.0
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright (c) 2019 by Datto, Inc. All rights reserved.
# Copyright (c) 2026, Klara Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# Description:
# zdb -fHv <dataset> <objnum> will display block
# layouts for the object.
#
# Strategery:
# 1. Create a RAIDZ3 pool, set compression to none
# 2. Create a file filled with random data
# 3. Get the inode number of the file
# 4. Run zdb -fHv <pool>/ <inum> & extract file
# 5. Compare real file and extracted file.
DATA=/$TESTPOOL1/random.bin
BLOCKS=$(( $RANDOM % 16 ))
COMPARE=/tmp/compare.$$
function cleanup
{
destroy_pool $TESTPOOL1
rm -f $TESTDIR/file?.bin $COMPARE
}
log_assert "Verify zdb -fHv displays correct offsets"
log_onexit cleanup
# 1. Create a RAIDZ1 pool
log_must mkdir -p $TESTDIR
for file in 1 2 3 4 5 6 7
do
rm -f $TESTDIR/file${file}.bin
touch $TESTDIR/file${file}.bin
log_must truncate -s 128m $TESTDIR/file${file}.bin
done
log_must zpool create -O compression=off -O recordsize=16K $TESTPOOL1 raidz3 $TESTDIR/file[123456].bin
zfs get compression,recordsize $TESTPOOL1
# 2. Create a file with random data
log_must rm -f $DATA
log_must dd if=/dev/urandom of=${DATA} bs=16k count=${BLOCKS} > /dev/null 2>&1
log_must zpool sync $TESTPOOL1
# 3. Get the inode number of the file
INUM=$(ls -li $DATA | cut -f1 -d ' ')
# 4. Extract the contents of the file using dd
rm -f $COMPARE
log_must touch ${COMPARE}
log_must zdb -fHv $TESTPOOL1/ ${INUM} | grep 'D.$' |
while read file offset count rest
do
log_must sh -c "dd if=$TESTDIR/${file} bs=512 skip=${offset} count=${count} >> ${COMPARE}"
done
# 5. Compare files
log_must cmp ${COMPARE} ${DATA}
log_pass "'zdb -fHv' works as expected."
@@ -0,0 +1,57 @@
#!/bin/ksh
# SPDX-License-Identifier: CDDL-1.0
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
#
# Copyright (c) 2019 by Datto, Inc. All rights reserved.
# Copyright (c) 2026, Klara Inc.
#
. $STF_SUITE/include/libtest.shlib
#
# Description:
# Ensure zdb -f only works on raidz
#
# Strategery:
# 1. Create a pool with one disk
# 2. Create a file
# 3. Get the inode number of the file
# 4. Run zdb -f
# 5. Confirm failure status
function cleanup
{
destroy_pool $TESTPOOL1
rm -f $TESTDIR/file1.bin
}
log_assert "Verify zdb -f fails on non-raidz pool"
log_onexit cleanup
# 1. Create a RAIDZ1 pool
log_must mkdir -p $TESTDIR
touch $TESTDIR/file1.bin
log_must truncate -s 128m $TESTDIR/file1.bin
log_must zpool create -f $TESTPOOL1 $TESTDIR/file1.bin
# 2. Create a file
log_must touch /$TESTPOOL1/file.txt
# 3. Get the inode number of the file
INUM=$(ls -li /$TESTDIR/file1.txt | cut -f1 -d ' ')
# 4. Run zdb -f
log_mustnot zdb -f $TESTDIR/ $INUM
log_pass "'zdb -f' fails on non-raidz as expected."