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);
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.
* 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;
rr->rr_col[0].rc_devidx = rr->rr_col[1].rc_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;
(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;
if (next_offset != file_offset) {
(void) printf("skip hole\t-\t%llx\n",
(u_longlong_t)((file_offset - next_offset) >>
vd->vdev_ashift));
(void) printf("skip hole\t-\t\t%lld\n",
(u_longlong_t)((file_offset - next_offset) / 512));
}
next_offset = file_offset + BP_GET_LSIZE(bp);
uint64_t tmp_offset = file_offset;
for (int c = 0; c < rr->rr_cols; c++) {
boolean_t pcol = c < rr->rr_firstdatacol;
raidz_col_t *rc = &rr->rr_col[c];
char *path = vd->vdev_child[rc->rc_devidx]->vdev_path;
// c < rr->rr_firstdatacol
if (rc->rc_size == 0)
continue;
(void) printf("%s\t%llu\t%d\n",
(void) printf("%s\t\t%llu\t%d",
zfs_basename(path),
(u_longlong_t)(rc->rc_offset +
VDEV_LABEL_START_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
*/
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 {
char diskhdr[16];
@@ -10519,6 +10550,7 @@ main(int argc, char **argv)
}
if (dump_opt['f'] && os != NULL) {
dump_opt['v'] = verbose;
dump_file_data_layout(os);
} else if (dump_opt['B']) {
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.
.It Fl f , -file-layout
Display the file layout of an object for the disks of a raidz vdev.
Numeric values in the disply are hexadecimal.
With
.Fl H ,
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.
.It Fl h , -history
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_block_size_histogram', 'zdb_checksum', 'zdb_decompress',
'zdb_display_block', 'zdb_encrypted', 'zdb_encrypted_raw',
'zdb_label_checksum', 'zdb_object_range_neg', 'zdb_object_range_pos',
'zdb_objset_id', 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2',
'zdb_backup', 'zdb_tunables']
'zdb_file_layout_001', 'zdb_file_layout_002', 'zdb_file_layout_003',
'zdb_file_layout_neg', 'zdb_label_checksum', 'zdb_object_range_neg',
'zdb_object_range_pos', 'zdb_objset_id', 'zdb_decompress_zstd',
'zdb_recover', 'zdb_recover_2', 'zdb_backup', 'zdb_tunables']
pre =
post =
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_raw.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_pos.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."