mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-04-13 07:01:46 +03:00
Add the --file-layout (-f) option to zdb(8)
Displays the physical raidz block layout for a given file. This leverages the internal vdev_raidz_map_alloc() function to find the map of how the block data is laid out across the child disks. The column entry for each row looks like: +------------+ | D2 43 | | 6020da | +------------+ representing here the logical data column 2 that is 43 sectors high starting at sector 0x6020da. With -H, the output is a list of disks, LBAs, and block counts, given in 512 byte block values. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: sean.fagan@klarasystems.com Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Don Brady <don.brady@klarasystems.com> Co-authored-by: Sean Fagan <sean.fagan@klarasystems.com> Closes #18264
This commit is contained in:
parent
2b930f63f8
commit
f109c7bb98
376
cmd/zdb/zdb.c
376
cmd/zdb/zdb.c
@ -87,6 +87,8 @@
|
|||||||
#include <sys/brt.h>
|
#include <sys/brt.h>
|
||||||
#include <sys/brt_impl.h>
|
#include <sys/brt_impl.h>
|
||||||
#include <zfs_comutil.h>
|
#include <zfs_comutil.h>
|
||||||
|
#include <sys/vdev_raidz.h>
|
||||||
|
#include <sys/vdev_raidz_impl.h>
|
||||||
#include <sys/zstd/zstd.h>
|
#include <sys/zstd/zstd.h>
|
||||||
#include <sys/backtrace.h>
|
#include <sys/backtrace.h>
|
||||||
|
|
||||||
@ -743,11 +745,13 @@ usage(void)
|
|||||||
"\t%s -r [-K <key>] -O <dataset> <object-id> <destination>\n"
|
"\t%s -r [-K <key>] -O <dataset> <object-id> <destination>\n"
|
||||||
"\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
|
"\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
|
||||||
"\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
|
"\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
|
||||||
|
"\t%s -f [-H] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
|
||||||
|
"\t\t[<poolname>[/<dataset | objset id>] [<object | range> ...]]\n"
|
||||||
"\t%s -E [-A] word0:word1:...:word15\n"
|
"\t%s -E [-A] word0:word1:...:word15\n"
|
||||||
"\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
|
"\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
|
||||||
"<poolname>\n\n",
|
"<poolname>\n\n",
|
||||||
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
|
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
|
||||||
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname);
|
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname);
|
||||||
|
|
||||||
(void) fprintf(stderr, " Dataset name must include at least one "
|
(void) fprintf(stderr, " Dataset name must include at least one "
|
||||||
"separator character '/' or '@'\n");
|
"separator character '/' or '@'\n");
|
||||||
@ -786,6 +790,8 @@ usage(void)
|
|||||||
"dataset(s)\n");
|
"dataset(s)\n");
|
||||||
(void) fprintf(stderr, " -D --dedup-stats "
|
(void) fprintf(stderr, " -D --dedup-stats "
|
||||||
"dedup statistics\n");
|
"dedup statistics\n");
|
||||||
|
(void) fprintf(stderr, " -f --file-layout "
|
||||||
|
"display a file's layout across raidz disks\n");
|
||||||
(void) fprintf(stderr, " -E --embedded-block-pointer=INTEGER\n"
|
(void) fprintf(stderr, " -E --embedded-block-pointer=INTEGER\n"
|
||||||
" decode and display block "
|
" decode and display block "
|
||||||
"from an embedded block pointer\n");
|
"from an embedded block pointer\n");
|
||||||
@ -818,6 +824,7 @@ usage(void)
|
|||||||
(void) fprintf(stderr, " -y --livelist "
|
(void) fprintf(stderr, " -y --livelist "
|
||||||
"perform livelist and metaslab validation on any livelists being "
|
"perform livelist and metaslab validation on any livelists being "
|
||||||
"deleted\n\n");
|
"deleted\n\n");
|
||||||
|
|
||||||
(void) fprintf(stderr, " Below options are intended for use "
|
(void) fprintf(stderr, " Below options are intended for use "
|
||||||
"with other options:\n");
|
"with other options:\n");
|
||||||
(void) fprintf(stderr, " -A --ignore-assertions "
|
(void) fprintf(stderr, " -A --ignore-assertions "
|
||||||
@ -830,6 +837,8 @@ usage(void)
|
|||||||
"groups\n");
|
"groups\n");
|
||||||
(void) fprintf(stderr, " -G --dump-debug-msg "
|
(void) fprintf(stderr, " -G --dump-debug-msg "
|
||||||
"dump zfs_dbgmsg buffer before exiting\n");
|
"dump zfs_dbgmsg buffer before exiting\n");
|
||||||
|
(void) fprintf(stderr, " -H --scripting-mode "
|
||||||
|
"dump output in a format that is scripting friendly\n");
|
||||||
(void) fprintf(stderr, " -I --inflight=INTEGER "
|
(void) fprintf(stderr, " -I --inflight=INTEGER "
|
||||||
"specify the maximum number of checksumming I/Os "
|
"specify the maximum number of checksumming I/Os "
|
||||||
"[default is 200]\n");
|
"[default is 200]\n");
|
||||||
@ -2645,6 +2654,7 @@ snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp,
|
|||||||
if (bp_freed)
|
if (bp_freed)
|
||||||
(void) snprintf(blkbuf + strlen(blkbuf),
|
(void) snprintf(blkbuf + strlen(blkbuf),
|
||||||
buflen - strlen(blkbuf), " %s", "FREE");
|
buflen - strlen(blkbuf), " %s", "FREE");
|
||||||
|
|
||||||
(void) snprintf(blkbuf + strlen(blkbuf),
|
(void) snprintf(blkbuf + strlen(blkbuf),
|
||||||
buflen - strlen(blkbuf),
|
buflen - strlen(blkbuf),
|
||||||
" cksum=%016llx:%016llx:%016llx:%016llx",
|
" cksum=%016llx:%016llx:%016llx:%016llx",
|
||||||
@ -2655,6 +2665,74 @@ snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inverse_text(boolean_t on)
|
||||||
|
{
|
||||||
|
if (isatty(STDOUT_FILENO)) {
|
||||||
|
if (on)
|
||||||
|
fputs("\x1b[7m", stdout);
|
||||||
|
else
|
||||||
|
fputs("\x1b[m", stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_file_layout_line(int line, int first_disk, int last_disk, int ashift,
|
||||||
|
raidz_row_t *rr)
|
||||||
|
{
|
||||||
|
if (first_disk != 0) {
|
||||||
|
/* Account for empty columns */
|
||||||
|
for (int c = 0; c < first_disk; c++) {
|
||||||
|
(void) printf("%s%s", (c == 0) ? " │ " : " ",
|
||||||
|
line == 0 ? "` ` ` ` ` " : " ` ` ` ` `");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we need to account for out of order disks in raidz1.
|
||||||
|
* Here flip means the disks in first two column were exchanged.
|
||||||
|
*/
|
||||||
|
boolean_t flip = rr->rr_firstdatacol == 1 &&
|
||||||
|
(rr->rr_offset & (1ULL << 20));
|
||||||
|
|
||||||
|
for (int c = 0; c < rr->rr_cols; c++) {
|
||||||
|
raidz_col_t *rc = &rr->rr_col[c];
|
||||||
|
char colname[8];
|
||||||
|
boolean_t pcol = flip ? (c == 1) : (c < rr->rr_firstdatacol);
|
||||||
|
|
||||||
|
if (rc->rc_devidx > last_disk)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(void) snprintf(colname, sizeof (colname), "%c%d",
|
||||||
|
pcol ? 'P' : 'D', (flip && c < 2) ? 0 :
|
||||||
|
pcol ? c : c - rr->rr_firstdatacol);
|
||||||
|
|
||||||
|
(void) printf("%s", (rc->rc_devidx == 0) ? " │ " : " ");
|
||||||
|
if (pcol)
|
||||||
|
inverse_text(B_TRUE);
|
||||||
|
if (line == 0) {
|
||||||
|
(void) printf("%3s %5d", colname,
|
||||||
|
(int)(rc->rc_size >> ashift));
|
||||||
|
} else {
|
||||||
|
(void) printf("%10llx",
|
||||||
|
(u_longlong_t)((rc->rc_offset +
|
||||||
|
VDEV_LABEL_START_SIZE) >> ashift));
|
||||||
|
}
|
||||||
|
if (pcol)
|
||||||
|
inverse_text(B_FALSE);
|
||||||
|
if (rc->rc_devidx == last_disk) {
|
||||||
|
/* empty columns */
|
||||||
|
for (int c = last_disk + 1; c < rr->rr_cols; c++) {
|
||||||
|
(void) printf(" %s",
|
||||||
|
line == 0 ? "` ` ` ` ` " : " ` ` ` ` `");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) printf(" │\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static u_longlong_t
|
static u_longlong_t
|
||||||
print_indirect(spa_t *spa, blkptr_t *bp, const zbookmark_phys_t *zb,
|
print_indirect(spa_t *spa, blkptr_t *bp, const zbookmark_phys_t *zb,
|
||||||
const dnode_phys_t *dnp)
|
const dnode_phys_t *dnp)
|
||||||
@ -2701,17 +2779,133 @@ print_indirect(spa_t *spa, blkptr_t *bp, const zbookmark_phys_t *zb,
|
|||||||
return (offset);
|
return (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_file_layout_raidz(vdev_t *vd, blkptr_t *bp, uint64_t file_offset,
|
||||||
|
boolean_t last)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* RAIDZ file data layout
|
||||||
|
*
|
||||||
|
* Use vdev_raidz_map_alloc() to get the actual layout
|
||||||
|
*/
|
||||||
|
const dva_t *dva = bp->blk_dva;
|
||||||
|
zio_t zio = {0};
|
||||||
|
zio.io_size = P2ROUNDUP_TYPED(BP_GET_PSIZE(bp),
|
||||||
|
1ULL << vd->vdev_ashift, uint64_t);
|
||||||
|
zio.io_offset = DVA_GET_OFFSET(&dva[0]);
|
||||||
|
zio.io_type = ZIO_TYPE_READ;
|
||||||
|
zio.io_abd = abd_alloc_for_io(zio.io_size, B_FALSE);
|
||||||
|
|
||||||
|
vdev_raidz_t *vdrz = vd->vdev_tsd;
|
||||||
|
raidz_map_t *rm = vdev_raidz_map_alloc(&zio, vd->vdev_ashift,
|
||||||
|
vd->vdev_children, vdrz->vd_nparity);
|
||||||
|
raidz_row_t *rr = rm->rm_row[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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))) {
|
||||||
|
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);
|
||||||
|
print_file_layout_line(0, first_disk, last_disk,
|
||||||
|
vd->vdev_ashift, rr);
|
||||||
|
(void) printf("%*c", 12, ' ');
|
||||||
|
print_file_layout_line(1, first_disk, last_disk,
|
||||||
|
vd->vdev_ashift, rr);
|
||||||
|
/* Check for split row */
|
||||||
|
if (first_disk != 0) {
|
||||||
|
(void) printf("%*c", 12, ' ');
|
||||||
|
print_file_layout_line(0, 0, first_disk - 1,
|
||||||
|
vd->vdev_ashift, rr);
|
||||||
|
(void) printf("%*c", 12, ' ');
|
||||||
|
print_file_layout_line(1, 0, first_disk - 1,
|
||||||
|
vd->vdev_ashift, rr);
|
||||||
|
}
|
||||||
|
/* seperate rows with a line */
|
||||||
|
(void) printf("%*c", 12, ' ');
|
||||||
|
for (int c = 0; c < vd->vdev_children; c++) {
|
||||||
|
(void) printf("%s%10s", (c == 0) ?
|
||||||
|
(last ? " └─" : " ├─") : "──",
|
||||||
|
"──────────");
|
||||||
|
}
|
||||||
|
(void) printf("─%s\n", last ? "┘" : "┤");
|
||||||
|
} else {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
next_offset = file_offset + BP_GET_LSIZE(bp);
|
||||||
|
|
||||||
|
for (int c = 0; c < rr->rr_cols; c++) {
|
||||||
|
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",
|
||||||
|
zfs_basename(path),
|
||||||
|
(u_longlong_t)(rc->rc_offset +
|
||||||
|
VDEV_LABEL_START_SIZE)/512,
|
||||||
|
(int)rc->rc_size/512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_file_layout(spa_t *spa, blkptr_t *bp, const zbookmark_phys_t *zb,
|
||||||
|
const dnode_phys_t *dnp)
|
||||||
|
{
|
||||||
|
if (!BP_IS_EMBEDDED(bp)) {
|
||||||
|
ASSERT3U(BP_GET_TYPE(bp), ==, dnp->dn_type);
|
||||||
|
ASSERT3U(BP_GET_LEVEL(bp), ==, zb->zb_level);
|
||||||
|
}
|
||||||
|
ASSERT(zb->zb_level >= 0);
|
||||||
|
|
||||||
|
if (BP_IS_HOLE(bp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (BP_IS_EMBEDDED(bp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const dva_t *dva = bp->blk_dva;
|
||||||
|
vdev_t *vd = spa->spa_root_vdev->vdev_child[DVA_GET_VDEV(&dva[0])];
|
||||||
|
uint64_t file_offset = blkid2offset(dnp, bp, zb);
|
||||||
|
|
||||||
|
if (strcmp("raidz", vd->vdev_ops->vdev_op_type) == 0) {
|
||||||
|
boolean_t last = (file_offset + BP_GET_LSIZE(bp)) >=
|
||||||
|
(dnp->dn_used & ~0x03ffULL);
|
||||||
|
print_file_layout_raidz(vd, bp, file_offset, last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
|
visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
|
||||||
blkptr_t *bp, const zbookmark_phys_t *zb)
|
blkptr_t *bp, const zbookmark_phys_t *zb)
|
||||||
{
|
{
|
||||||
u_longlong_t offset;
|
u_longlong_t offset = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (BP_GET_BIRTH(bp) == 0)
|
if (BP_GET_BIRTH(bp) == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
offset = print_indirect(spa, bp, zb, dnp);
|
if (dump_opt['f']) {
|
||||||
|
if (BP_GET_LEVEL(bp) == 0)
|
||||||
|
print_file_layout(spa, bp, zb, dnp);
|
||||||
|
} else {
|
||||||
|
print_indirect(spa, bp, zb, dnp);
|
||||||
|
}
|
||||||
|
|
||||||
if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
|
if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
|
||||||
arc_flags_t flags = ARC_FLAG_WAIT;
|
arc_flags_t flags = ARC_FLAG_WAIT;
|
||||||
@ -2763,6 +2957,63 @@ dump_indirect(dnode_t *dn)
|
|||||||
zbookmark_phys_t czb;
|
zbookmark_phys_t czb;
|
||||||
|
|
||||||
(void) printf("Indirect blocks:\n");
|
(void) printf("Indirect blocks:\n");
|
||||||
|
SET_BOOKMARK(&czb, dmu_objset_id(dn->dn_objset),
|
||||||
|
dn->dn_object, dnp->dn_nlevels - 1, 0);
|
||||||
|
for (int j = 0; j < dnp->dn_nblkptr; j++) {
|
||||||
|
czb.zb_blkid = j;
|
||||||
|
(void) visit_indirect(dmu_objset_spa(dn->dn_objset), dnp,
|
||||||
|
&dnp->dn_blkptr[j], &czb);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dump_indirect_layout(dnode_t *dn)
|
||||||
|
{
|
||||||
|
dnode_phys_t *dnp = dn->dn_phys;
|
||||||
|
zbookmark_phys_t czb;
|
||||||
|
|
||||||
|
spa_t *spa = dmu_objset_spa(dn->dn_objset);
|
||||||
|
int ashift = spa->spa_root_vdev->vdev_child[0]->vdev_ashift;
|
||||||
|
int children = spa->spa_root_vdev->vdev_child[0]->vdev_children;
|
||||||
|
|
||||||
|
if (strcmp(spa->spa_root_vdev->vdev_child[0]->vdev_ops->vdev_op_type,
|
||||||
|
"raidz") != 0) {
|
||||||
|
(void) fprintf(stderr, "file layout only supports raidz\n");
|
||||||
|
return (ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start layout with a header
|
||||||
|
*/
|
||||||
|
if (dump_opt['H']) {
|
||||||
|
(void) printf("DISK\t\tLBA\t\tCOUNT\n");
|
||||||
|
} else {
|
||||||
|
char diskhdr[16];
|
||||||
|
|
||||||
|
(void) printf("%12s: %d\n", "block size", dn->dn_datablksz);
|
||||||
|
(void) printf("%12s: %s%d\n", "vdev_type",
|
||||||
|
spa->spa_root_vdev->vdev_child[0]->vdev_ops->vdev_op_type,
|
||||||
|
(int)vdev_get_nparity(spa->spa_root_vdev->vdev_child[0]));
|
||||||
|
(void) printf("%12s: %d\n", "sector size", 1 << ashift);
|
||||||
|
(void) printf("%12s: %d\n\n", "child disks", children);
|
||||||
|
|
||||||
|
(void) printf("%*c ", 12, ' ');
|
||||||
|
|
||||||
|
for (int c = 0; c < children; c++) {
|
||||||
|
(void) snprintf(diskhdr, sizeof (diskhdr),
|
||||||
|
"V%d:DISK-%d", 0, c);
|
||||||
|
(void) printf(" %10s ", diskhdr);
|
||||||
|
}
|
||||||
|
(void) printf("\n");
|
||||||
|
|
||||||
|
(void) printf("%12s", "FILE OFFSET");
|
||||||
|
for (int c = 0; c < children; c++)
|
||||||
|
(void) printf("%s%10s", (c == 0) ? " ┌─" : "──",
|
||||||
|
"──────────");
|
||||||
|
(void) printf("─┐\n");
|
||||||
|
}
|
||||||
|
|
||||||
SET_BOOKMARK(&czb, dmu_objset_id(dn->dn_objset),
|
SET_BOOKMARK(&czb, dmu_objset_id(dn->dn_objset),
|
||||||
dn->dn_object, dnp->dn_nlevels - 1, 0);
|
dn->dn_object, dnp->dn_nlevels - 1, 0);
|
||||||
@ -2773,6 +3024,7 @@ dump_indirect(dnode_t *dn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3033,7 +3285,6 @@ dump_full_bpobj(bpobj_t *bpo, const char *name, int indent)
|
|||||||
if (dump_opt['d'] < 5)
|
if (dump_opt['d'] < 5)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
if (indent == 0) {
|
if (indent == 0) {
|
||||||
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
|
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
@ -4161,7 +4412,6 @@ dump_object(objset_t *os, uint64_t object, int verbosity,
|
|||||||
start = end;
|
start = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (db != NULL)
|
if (db != NULL)
|
||||||
dmu_buf_rele(db, FTAG);
|
dmu_buf_rele(db, FTAG);
|
||||||
@ -4169,6 +4419,60 @@ out:
|
|||||||
dnode_rele(dn, FTAG);
|
dnode_rele(dn, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_object_file_layout(objset_t *os, uint64_t object, int verbosity)
|
||||||
|
{
|
||||||
|
(void) verbosity;
|
||||||
|
dmu_buf_t *db = NULL;
|
||||||
|
dmu_object_info_t doi;
|
||||||
|
dnode_t *dn;
|
||||||
|
boolean_t dnode_held = B_FALSE;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
char osname[ZFS_MAX_DATASET_NAME_LEN];
|
||||||
|
dmu_objset_name(os, osname);
|
||||||
|
(void) printf("%12s: '%s'\n", "objset", osname);
|
||||||
|
(void) printf("%12s: %d\n", "object", (int)object);
|
||||||
|
|
||||||
|
if (object == 0) {
|
||||||
|
dn = DMU_META_DNODE(os);
|
||||||
|
dmu_object_info_from_dnode(dn, &doi);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Encrypted datasets will have sensitive bonus buffers
|
||||||
|
* encrypted. Therefore we cannot hold the bonus buffer and
|
||||||
|
* must hold the dnode itself instead.
|
||||||
|
*/
|
||||||
|
error = dmu_object_info(os, object, &doi);
|
||||||
|
if (error)
|
||||||
|
fatal("dmu_object_info() failed, errno %u", error);
|
||||||
|
|
||||||
|
if (!key_loaded && os->os_encrypted &&
|
||||||
|
DMU_OT_IS_ENCRYPTED(doi.doi_bonus_type)) {
|
||||||
|
error = dnode_hold(os, object, FTAG, &dn);
|
||||||
|
if (error)
|
||||||
|
fatal("dnode_hold() failed, errno %u", error);
|
||||||
|
dnode_held = B_TRUE;
|
||||||
|
} else {
|
||||||
|
error = dmu_bonus_hold(os, object, FTAG, &db);
|
||||||
|
if (error)
|
||||||
|
fatal("dmu_bonus_hold(%llu) failed, errno %u",
|
||||||
|
object, error);
|
||||||
|
dn = DB_DNODE((dmu_buf_impl_t *)db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = dump_indirect_layout(dn);
|
||||||
|
|
||||||
|
if (db != NULL)
|
||||||
|
dmu_buf_rele(db, FTAG);
|
||||||
|
if (dnode_held)
|
||||||
|
dnode_rele(dn, FTAG);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
zdb_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
count_dir_mos_objects(dsl_dir_t *dd)
|
count_dir_mos_objects(dsl_dir_t *dd)
|
||||||
{
|
{
|
||||||
@ -4357,7 +4661,7 @@ dump_objset(objset_t *os)
|
|||||||
|
|
||||||
zdb_nicenum(refdbytes, numbuf, sizeof (numbuf));
|
zdb_nicenum(refdbytes, numbuf, sizeof (numbuf));
|
||||||
|
|
||||||
if (verbosity >= 4) {
|
if (verbosity >= 4 || dump_opt['d']) {
|
||||||
(void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
|
(void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
|
||||||
(void) snprintf_blkptr(blkbuf + strlen(blkbuf),
|
(void) snprintf_blkptr(blkbuf + strlen(blkbuf),
|
||||||
sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
|
sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
|
||||||
@ -4380,21 +4684,21 @@ dump_objset(objset_t *os)
|
|||||||
flags = zopt_object_ranges[i].zor_flags;
|
flags = zopt_object_ranges[i].zor_flags;
|
||||||
|
|
||||||
object = obj_start;
|
object = obj_start;
|
||||||
if (object == 0 || obj_start == obj_end)
|
if (object == 0 || obj_start == obj_end) {
|
||||||
dump_object(os, object, verbosity, &print_header, NULL,
|
dump_object(os, object, verbosity,
|
||||||
flags);
|
&print_header, NULL, flags);
|
||||||
else
|
} else {
|
||||||
object--;
|
object--;
|
||||||
|
}
|
||||||
|
|
||||||
while ((dmu_object_next(os, &object, B_FALSE, 0) == 0) &&
|
while ((dmu_object_next(os, &object, B_FALSE, 0) == 0) &&
|
||||||
object <= obj_end) {
|
object <= obj_end) {
|
||||||
dump_object(os, object, verbosity, &print_header, NULL,
|
dump_object(os, object, verbosity,
|
||||||
flags);
|
&print_header, NULL, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zopt_object_args > 0) {
|
if (zopt_object_args > 0) {
|
||||||
(void) printf("\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4477,6 +4781,32 @@ dump_objset(objset_t *os)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump_file_data_layout(objset_t *os)
|
||||||
|
{
|
||||||
|
uint64_t object;
|
||||||
|
int verbosity = dump_opt['d'];
|
||||||
|
unsigned i;
|
||||||
|
uint64_t obj_start;
|
||||||
|
uint64_t obj_end;
|
||||||
|
|
||||||
|
for (i = 0; i < zopt_object_args; i++) {
|
||||||
|
obj_start = zopt_object_ranges[i].zor_obj_start;
|
||||||
|
obj_end = zopt_object_ranges[i].zor_obj_end;
|
||||||
|
|
||||||
|
object = obj_start;
|
||||||
|
if (object == 0 || obj_start == obj_end)
|
||||||
|
dump_object_file_layout(os, object, verbosity);
|
||||||
|
else
|
||||||
|
object--;
|
||||||
|
|
||||||
|
while ((dmu_object_next(os, &object, B_FALSE, 0) == 0) &&
|
||||||
|
object <= obj_end) {
|
||||||
|
dump_object_file_layout(os, object, verbosity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
|
dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
|
||||||
{
|
{
|
||||||
@ -5708,7 +6038,6 @@ dump_one_objset(const char *dsname, void *arg)
|
|||||||
!dmu_objset_is_snapshot(os)) {
|
!dmu_objset_is_snapshot(os)) {
|
||||||
global_feature_count[SPA_FEATURE_LIVELIST]++;
|
global_feature_count[SPA_FEATURE_LIVELIST]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
dump_objset(os);
|
dump_objset(os);
|
||||||
close_objset(os, FTAG);
|
close_objset(os, FTAG);
|
||||||
fuid_table_destroy();
|
fuid_table_destroy();
|
||||||
@ -9528,9 +9857,11 @@ main(int argc, char **argv)
|
|||||||
{"dedup-stats", no_argument, NULL, 'D'},
|
{"dedup-stats", no_argument, NULL, 'D'},
|
||||||
{"exported", no_argument, NULL, 'e'},
|
{"exported", no_argument, NULL, 'e'},
|
||||||
{"embedded-block-pointer", no_argument, NULL, 'E'},
|
{"embedded-block-pointer", no_argument, NULL, 'E'},
|
||||||
|
{"file-layout", no_argument, NULL, 'f'},
|
||||||
{"automatic-rewind", no_argument, NULL, 'F'},
|
{"automatic-rewind", no_argument, NULL, 'F'},
|
||||||
{"dump-debug-msg", no_argument, NULL, 'G'},
|
{"dump-debug-msg", no_argument, NULL, 'G'},
|
||||||
{"history", no_argument, NULL, 'h'},
|
{"history", no_argument, NULL, 'h'},
|
||||||
|
{"scripting-mode", no_argument, NULL, 'H'},
|
||||||
{"intent-logs", no_argument, NULL, 'i'},
|
{"intent-logs", no_argument, NULL, 'i'},
|
||||||
{"inflight", required_argument, NULL, 'I'},
|
{"inflight", required_argument, NULL, 'I'},
|
||||||
{"checkpointed-state", no_argument, NULL, 'k'},
|
{"checkpointed-state", no_argument, NULL, 'k'},
|
||||||
@ -9570,7 +9901,7 @@ main(int argc, char **argv)
|
|||||||
};
|
};
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv,
|
while ((c = getopt_long(argc, argv,
|
||||||
"AbBcCdDeEFGhiI:kK:lLmMNo:Op:PqrRsSt:TuU:vVx:XYyZ",
|
"AbBcCdDeEfFGhHiI:kK:lLmMNo:Op:PqrRsSt:TuU:vVx:XYyZ",
|
||||||
long_options, NULL)) != -1) {
|
long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'b':
|
case 'b':
|
||||||
@ -9580,6 +9911,7 @@ main(int argc, char **argv)
|
|||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
case 'E':
|
case 'E':
|
||||||
|
case 'f':
|
||||||
case 'G':
|
case 'G':
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'i':
|
case 'i':
|
||||||
@ -9603,6 +9935,7 @@ main(int argc, char **argv)
|
|||||||
case 'A':
|
case 'A':
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'F':
|
case 'F':
|
||||||
|
case 'H':
|
||||||
case 'k':
|
case 'k':
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'P':
|
case 'P':
|
||||||
@ -9742,6 +10075,10 @@ main(int argc, char **argv)
|
|||||||
(void) fprintf(stderr, "-p option requires use of -e\n");
|
(void) fprintf(stderr, "-p option requires use of -e\n");
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
if (dump_opt['H'] && !dump_opt['f']) {
|
||||||
|
(void) fprintf(stderr, "-H option requires use of -f\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
#if defined(_LP64)
|
#if defined(_LP64)
|
||||||
/*
|
/*
|
||||||
* ZDB does not typically re-read blocks; therefore limit the ARC
|
* ZDB does not typically re-read blocks; therefore limit the ARC
|
||||||
@ -9781,7 +10118,7 @@ main(int argc, char **argv)
|
|||||||
verbose = MAX(verbose, 1);
|
verbose = MAX(verbose, 1);
|
||||||
|
|
||||||
for (c = 0; c < 256; c++) {
|
for (c = 0; c < 256; c++) {
|
||||||
if (dump_all && strchr("ABeEFkKlLNOPrRSXy", c) == NULL)
|
if (dump_all && strchr("ABeEfFkKlLNOPrRSXy", c) == NULL)
|
||||||
dump_opt[c] = 1;
|
dump_opt[c] = 1;
|
||||||
if (dump_opt[c])
|
if (dump_opt[c])
|
||||||
dump_opt[c] += verbose;
|
dump_opt[c] += verbose;
|
||||||
@ -10153,7 +10490,7 @@ retry_lookup:
|
|||||||
flagbits['z'] = ZOR_FLAG_ZAP;
|
flagbits['z'] = ZOR_FLAG_ZAP;
|
||||||
flagbits['A'] = ZOR_FLAG_ALL_TYPES;
|
flagbits['A'] = ZOR_FLAG_ALL_TYPES;
|
||||||
|
|
||||||
if (argc > 0 && dump_opt['d']) {
|
if (argc > 0 && (dump_opt['d'] || dump_opt['f'])) {
|
||||||
zopt_object_args = argc;
|
zopt_object_args = argc;
|
||||||
zopt_object_ranges = calloc(zopt_object_args,
|
zopt_object_ranges = calloc(zopt_object_args,
|
||||||
sizeof (zopt_object_range_t));
|
sizeof (zopt_object_range_t));
|
||||||
@ -10179,7 +10516,10 @@ retry_lookup:
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dump_opt['B']) {
|
|
||||||
|
if (dump_opt['f'] && os != NULL) {
|
||||||
|
dump_file_data_layout(os);
|
||||||
|
} else if (dump_opt['B']) {
|
||||||
dump_backup(target, objset_id,
|
dump_backup(target, objset_id,
|
||||||
argc > 0 ? argv[0] : NULL);
|
argc > 0 ? argv[0] : NULL);
|
||||||
} else if (os != NULL) {
|
} else if (os != NULL) {
|
||||||
|
|||||||
@ -282,6 +282,13 @@ Also dump the contents of the deduplication tables describing unique blocks.
|
|||||||
Decode and display block from an embedded block pointer specified by the
|
Decode and display block from an embedded block pointer specified by the
|
||||||
.Ar word
|
.Ar word
|
||||||
arguments.
|
arguments.
|
||||||
|
.It Fl f , -file-layout
|
||||||
|
Display the file layout of an object for the disks of a raidz vdev.
|
||||||
|
With
|
||||||
|
.Fl H ,
|
||||||
|
the output is in scripted mode for easy parsing, with all values
|
||||||
|
being presented as 512 byte blocks.
|
||||||
|
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
|
||||||
.Nm zpool Cm history ,
|
.Nm zpool Cm history ,
|
||||||
|
|||||||
@ -57,7 +57,7 @@ set -A args "create" "add" "destroy" "import fakepool" \
|
|||||||
"add mirror fakepool" "add raidz fakepool" \
|
"add mirror fakepool" "add raidz fakepool" \
|
||||||
"add raidz1 fakepool" "add raidz2 fakepool" \
|
"add raidz1 fakepool" "add raidz2 fakepool" \
|
||||||
"setvprop" "blah blah" "-%" "--?" "-*" "-=" \
|
"setvprop" "blah blah" "-%" "--?" "-*" "-=" \
|
||||||
"-a" "-f" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \
|
"-a" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \
|
||||||
"-t" "-w" "-z" "-E" "-H" "-I" "-J" \
|
"-t" "-w" "-z" "-E" "-H" "-I" "-J" \
|
||||||
"-Q" "-R" "-W"
|
"-Q" "-R" "-W"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user