zdb: show BRT statistics and dump its contents

Same idea as the dedup stats, but for block cloning.

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Kay Pedersen <mail@mkwg.de>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <robn@despairlabs.com>
Closes #15541
This commit is contained in:
Rob Norris 2023-11-18 21:33:45 +11:00 committed by Brian Behlendorf
parent d702f86eaf
commit e96675a7b1
3 changed files with 99 additions and 4 deletions

View File

@ -34,6 +34,7 @@
* Copyright (c) 2021 Allan Jude * Copyright (c) 2021 Allan Jude
* Copyright (c) 2021 Toomas Soome <tsoome@me.com> * Copyright (c) 2021 Toomas Soome <tsoome@me.com>
* Copyright (c) 2023, Klara Inc. * Copyright (c) 2023, Klara Inc.
* Copyright (c) 2023, Rob Norris <robn@despairlabs.com>
*/ */
#include <stdio.h> #include <stdio.h>
@ -80,6 +81,7 @@
#include <sys/dsl_scan.h> #include <sys/dsl_scan.h>
#include <sys/btree.h> #include <sys/btree.h>
#include <sys/brt.h> #include <sys/brt.h>
#include <sys/brt_impl.h>
#include <zfs_comutil.h> #include <zfs_comutil.h>
#include <sys/zstd/zstd.h> #include <sys/zstd/zstd.h>
@ -899,6 +901,8 @@ usage(void)
"don't print label contents\n"); "don't print label contents\n");
(void) fprintf(stderr, " -t --txg=INTEGER " (void) fprintf(stderr, " -t --txg=INTEGER "
"highest txg to use when searching for uberblocks\n"); "highest txg to use when searching for uberblocks\n");
(void) fprintf(stderr, " -T --brt-stats "
"BRT statistics\n");
(void) fprintf(stderr, " -u --uberblock " (void) fprintf(stderr, " -u --uberblock "
"uberblock\n"); "uberblock\n");
(void) fprintf(stderr, " -U --cachefile=PATH " (void) fprintf(stderr, " -U --cachefile=PATH "
@ -999,6 +1003,15 @@ zdb_nicenum(uint64_t num, char *buf, size_t buflen)
nicenum(num, buf, buflen); nicenum(num, buf, buflen);
} }
static void
zdb_nicebytes(uint64_t bytes, char *buf, size_t buflen)
{
if (dump_opt['P'])
(void) snprintf(buf, buflen, "%llu", (longlong_t)bytes);
else
zfs_nicebytes(bytes, buf, buflen);
}
static const char histo_stars[] = "****************************************"; static const char histo_stars[] = "****************************************";
static const uint64_t histo_width = sizeof (histo_stars) - 1; static const uint64_t histo_width = sizeof (histo_stars) - 1;
@ -2081,6 +2094,76 @@ dump_all_ddts(spa_t *spa)
dump_dedup_ratio(&dds_total); dump_dedup_ratio(&dds_total);
} }
static void
dump_brt(spa_t *spa)
{
if (!spa_feature_is_enabled(spa, SPA_FEATURE_BLOCK_CLONING)) {
printf("BRT: unsupported on this pool\n");
return;
}
if (!spa_feature_is_active(spa, SPA_FEATURE_BLOCK_CLONING)) {
printf("BRT: empty\n");
return;
}
brt_t *brt = spa->spa_brt;
VERIFY(brt);
char count[32], used[32], saved[32];
zdb_nicebytes(brt_get_used(spa), used, sizeof (used));
zdb_nicebytes(brt_get_saved(spa), saved, sizeof (saved));
uint64_t ratio = brt_get_ratio(spa);
printf("BRT: used %s; saved %s; ratio %llu.%02llux\n", used, saved,
(u_longlong_t)(ratio / 100), (u_longlong_t)(ratio % 100));
if (dump_opt['T'] < 2)
return;
for (uint64_t vdevid = 0; vdevid < brt->brt_nvdevs; vdevid++) {
brt_vdev_t *brtvd = &brt->brt_vdevs[vdevid];
if (brtvd == NULL)
continue;
if (!brtvd->bv_initiated) {
printf("BRT: vdev %lu: empty\n", vdevid);
continue;
}
zdb_nicenum(brtvd->bv_totalcount, count, sizeof (count));
zdb_nicebytes(brtvd->bv_usedspace, used, sizeof (used));
zdb_nicebytes(brtvd->bv_savedspace, saved, sizeof (saved));
printf("BRT: vdev %lu: refcnt %s; used %s; saved %s\n",
vdevid, count, used, saved);
}
if (dump_opt['T'] < 3)
return;
char dva[64];
printf("\n%-16s %-10s\n", "DVA", "REFCNT");
for (uint64_t vdevid = 0; vdevid < brt->brt_nvdevs; vdevid++) {
brt_vdev_t *brtvd = &brt->brt_vdevs[vdevid];
if (brtvd == NULL || !brtvd->bv_initiated)
continue;
zap_cursor_t zc;
zap_attribute_t za;
for (zap_cursor_init(&zc, brt->brt_mos, brtvd->bv_mos_entries);
zap_cursor_retrieve(&zc, &za) == 0;
zap_cursor_advance(&zc)) {
uint64_t offset = *(uint64_t *)za.za_name;
uint64_t refcnt = za.za_first_integer;
snprintf(dva, sizeof (dva), "%lu:%llx", vdevid,
(u_longlong_t)offset);
printf("%-16s %-10llu\n", dva, (u_longlong_t)refcnt);
}
zap_cursor_fini(&zc);
}
}
static void static void
dump_dtl_seg(void *arg, uint64_t start, uint64_t size) dump_dtl_seg(void *arg, uint64_t start, uint64_t size)
{ {
@ -8093,6 +8176,9 @@ dump_zpool(spa_t *spa)
if (dump_opt['D']) if (dump_opt['D'])
dump_all_ddts(spa); dump_all_ddts(spa);
if (dump_opt['T'])
dump_brt(spa);
if (dump_opt['d'] > 2 || dump_opt['m']) if (dump_opt['d'] > 2 || dump_opt['m'])
dump_metaslabs(spa); dump_metaslabs(spa);
if (dump_opt['M']) if (dump_opt['M'])
@ -8879,6 +8965,7 @@ main(int argc, char **argv)
{"io-stats", no_argument, NULL, 's'}, {"io-stats", no_argument, NULL, 's'},
{"simulate-dedup", no_argument, NULL, 'S'}, {"simulate-dedup", no_argument, NULL, 'S'},
{"txg", required_argument, NULL, 't'}, {"txg", required_argument, NULL, 't'},
{"brt-stats", no_argument, NULL, 'T'},
{"uberblock", no_argument, NULL, 'u'}, {"uberblock", no_argument, NULL, 'u'},
{"cachefile", required_argument, NULL, 'U'}, {"cachefile", required_argument, NULL, 'U'},
{"verbose", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'v'},
@ -8892,7 +8979,7 @@ main(int argc, char **argv)
}; };
while ((c = getopt_long(argc, argv, while ((c = getopt_long(argc, argv,
"AbBcCdDeEFGhiI:kK:lLmMNo:Op:PqrRsSt:uU:vVx:XYyZ", "AbBcCdDeEFGhiI:kK:lLmMNo:Op:PqrRsSt:TuU:vVx:XYyZ",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
@ -8914,6 +9001,7 @@ main(int argc, char **argv)
case 'R': case 'R':
case 's': case 's':
case 'S': case 'S':
case 'T':
case 'u': case 'u':
case 'y': case 'y':
case 'Z': case 'Z':

View File

@ -14,7 +14,7 @@
.\" Copyright (c) 2017 Lawrence Livermore National Security, LLC. .\" Copyright (c) 2017 Lawrence Livermore National Security, LLC.
.\" Copyright (c) 2017 Intel Corporation. .\" Copyright (c) 2017 Intel Corporation.
.\" .\"
.Dd June 27, 2023 .Dd November 18, 2023
.Dt ZDB 8 .Dt ZDB 8
.Os .Os
. .
@ -23,7 +23,7 @@
.Nd display ZFS storage pool debugging and consistency information .Nd display ZFS storage pool debugging and consistency information
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl AbcdDFGhikLMNPsvXYy .Op Fl AbcdDFGhikLMNPsTvXYy
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns .Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns
.Op Fl I Ar inflight-I/O-ops .Op Fl I Ar inflight-I/O-ops
.Oo Fl o Ar var Ns = Ns Ar value Oc Ns .Oo Fl o Ar var Ns = Ns Ar value Oc Ns
@ -403,6 +403,13 @@ Display operation counts, bandwidth, and error counts of I/O to the pool from
Simulate the effects of deduplication, constructing a DDT and then display Simulate the effects of deduplication, constructing a DDT and then display
that DDT as with that DDT as with
.Fl DD . .Fl DD .
.It Fl T , -brt-stats
Display block reference table (BRT) statistics, including the size of uniques
blocks cloned, the space saving as a result of cloning, and the saving ratio.
.It Fl TT
Display the per-vdev BRT statistics, including total references.
.It Fl TTT
Dump the contents of the block reference tables.
.It Fl u , -uberblock .It Fl u , -uberblock
Display the current uberblock. Display the current uberblock.
.El .El

View File

@ -58,7 +58,7 @@ set -A args "create" "add" "destroy" "import fakepool" \
"setvprop" "blah blah" "-%" "--?" "-*" "-=" \ "setvprop" "blah blah" "-%" "--?" "-*" "-=" \
"-a" "-f" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \ "-a" "-f" "-g" "-j" "-n" "-o" "-p" "-p /tmp" \
"-t" "-w" "-z" "-E" "-H" "-I" "-J" \ "-t" "-w" "-z" "-E" "-H" "-I" "-J" \
"-Q" "-R" "-T" "-W" "-Q" "-R" "-W"
log_assert "Execute zdb using invalid parameters." log_assert "Execute zdb using invalid parameters."