From 968cfc3df2b1c0e1db346bceda6a23e4591c05f0 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Tue, 10 Dec 2024 17:12:53 +0400 Subject: [PATCH] zdb: add `--class=(normal|special|...)` to filter blocks by alloc class When counting blocks to generate block size histograms (`-bb`), accept a `--class=` argument (as a comma-separated list of either "normal", "special", "dedup" or "other") to only consider blocks that belong to these metaslab classes. Reviewed-by: Brian Behlendorf Signed-off-by: Ivan Shapovalov Closes #16999 --- cmd/zdb/zdb.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/zdb.8 | 4 ++ 2 files changed, 104 insertions(+) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 38439241b..2b64eeb72 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -109,6 +109,7 @@ extern uint_t zfs_btree_verify_intensity; enum { ARG_ALLOCATED = 256, ARG_BLOCK_BIN_MODE, + ARG_BLOCK_CLASSES, }; static const char cmdname[] = "zdb"; @@ -141,6 +142,13 @@ static enum { BIN_ASIZE, } block_bin_mode = BIN_AUTO; +static enum { + CLASS_NORMAL = 1 << 1, + CLASS_SPECIAL = 1 << 2, + CLASS_DEDUP = 1 << 3, + CLASS_OTHER = 1 << 4, +} block_classes = 0; + static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *, boolean_t); static void mos_obj_refd(uint64_t); @@ -761,6 +769,10 @@ usage(void) "block statistics\n"); (void) fprintf(stderr, " --bin=(lsize|psize|asize) " "bin blocks based on this size in all three columns\n"); + (void) fprintf(stderr, + " --class=(normal|special|dedup|other)[,...]\n" + " only consider blocks from " + "these allocation classes\n"); (void) fprintf(stderr, " -B --backup " "backup stream\n"); (void) fprintf(stderr, " -c --checksum " @@ -5840,6 +5852,20 @@ dump_size_histograms(zdb_cb_t *zcb) printf("(note: all categories are binned separately)\n"); break; } + if (block_classes != 0) { + char buf[256] = ""; + if (block_classes & CLASS_NORMAL) + strlcat(buf, "\"normal\", ", sizeof (buf)); + if (block_classes & CLASS_SPECIAL) + strlcat(buf, "\"special\", ", sizeof (buf)); + if (block_classes & CLASS_DEDUP) + strlcat(buf, "\"dedup\", ", sizeof (buf)); + if (block_classes & CLASS_OTHER) + strlcat(buf, "\"other\", ", sizeof (buf)); + buf[strlen(buf)-2] = '\0'; + printf("(note: only blocks in these classes are counted: %s)\n", + buf); + } /* * Print the first line titles */ @@ -6189,6 +6215,38 @@ skipped: return; } + if (block_classes != 0) { + spa_config_enter(zcb->zcb_spa, SCL_CONFIG, FTAG, RW_READER); + + uint64_t vdev = DVA_GET_VDEV(&bp->blk_dva[0]); + uint64_t offset = DVA_GET_OFFSET(&bp->blk_dva[0]); + vdev_t *vd = vdev_lookup_top(zcb->zcb_spa, vdev); + ASSERT(vd != NULL); + metaslab_t *ms = vd->vdev_ms[offset >> vd->vdev_ms_shift]; + ASSERT(ms != NULL); + metaslab_group_t *mg = ms->ms_group; + ASSERT(mg != NULL); + metaslab_class_t *mc = mg->mg_class; + ASSERT(mc != NULL); + + spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG); + + int class; + if (mc == spa_normal_class(zcb->zcb_spa)) { + class = CLASS_NORMAL; + } else if (mc == spa_special_class(zcb->zcb_spa)) { + class = CLASS_SPECIAL; + } else if (mc == spa_dedup_class(zcb->zcb_spa)) { + class = CLASS_DEDUP; + } else { + class = CLASS_OTHER; + } + + if (!(block_classes & class)) { + goto hist_skipped; + } + } + /* * The binning histogram bins by powers of two up to * SPA_MAXBLOCKSIZE rather than creating bins for @@ -6225,6 +6283,7 @@ skipped: zcb->zcb_asize_len[bin] += BP_GET_ASIZE(bp); zcb->zcb_asize_total += BP_GET_ASIZE(bp); +hist_skipped: if (!do_claim) return; @@ -9469,6 +9528,8 @@ main(int argc, char **argv) ARG_ALLOCATED}, {"bin", required_argument, NULL, ARG_BLOCK_BIN_MODE}, + {"class", required_argument, NULL, + ARG_BLOCK_CLASSES}, {0, 0, 0, 0} }; @@ -9596,6 +9657,45 @@ main(int argc, char **argv) usage(); } break; + + case ARG_BLOCK_CLASSES: { + char *buf = strdup(optarg), *tok = buf, *next, + *save = NULL; + + while ((next = strtok_r(tok, ",", &save)) != NULL) { + tok = NULL; + + if (strcmp(next, "normal") == 0) { + block_classes |= CLASS_NORMAL; + } else if (strcmp(next, "special") == 0) { + block_classes |= CLASS_SPECIAL; + } else if (strcmp(next, "dedup") == 0) { + block_classes |= CLASS_DEDUP; + } else if (strcmp(next, "other") == 0) { + block_classes |= CLASS_OTHER; + } else { + (void) fprintf(stderr, + "--class=\"%s\" must be a " + "comma-separated list of either " + "\"normal\", \"special\", " + "\"asize\" or \"other\"; " + "got \"%s\"\n", + optarg, next); + usage(); + } + } + + if (block_classes == 0) { + (void) fprintf(stderr, + "--class= must be a comma-separated " + "list of either \"normal\", \"special\", " + "\"asize\" or \"other\"; got empty\n"); + usage(); + } + + free(buf); + break; + } default: usage(); break; diff --git a/man/man8/zdb.8 b/man/man8/zdb.8 index c0ec2c81e..f51e24fa8 100644 --- a/man/man8/zdb.8 +++ b/man/man8/zdb.8 @@ -154,6 +154,10 @@ For instance, with .Fl -bin Ns = Ns Li lsize , a block with lsize of 16K and psize of 4K will be added to the 16K bin in all three columns. +.It Fl -class Ns = Ns ( Li normal Ns | Ns Li special Ns | Ns Li dedup Ns | Ns Li other ) Ns Op , Ns … +When used with +.Fl bb , +only consider blocks from these allocation classes. .It Fl B , -backup Generate a backup stream, similar to .Nm zfs Cm send ,