diff options
Diffstat (limited to 'sys/contrib/openzfs/cmd/zdb/zdb.c')
| -rw-r--r-- | sys/contrib/openzfs/cmd/zdb/zdb.c | 191 | 
1 files changed, 178 insertions, 13 deletions
| diff --git a/sys/contrib/openzfs/cmd/zdb/zdb.c b/sys/contrib/openzfs/cmd/zdb/zdb.c index 70a4ed46f263..2560ad045db3 100644 --- a/sys/contrib/openzfs/cmd/zdb/zdb.c +++ b/sys/contrib/openzfs/cmd/zdb/zdb.c @@ -106,11 +106,15 @@ extern boolean_t spa_mode_readable_spacemaps;  extern uint_t zfs_reconstruct_indirect_combinations_max;  extern uint_t zfs_btree_verify_intensity; +enum { +	ARG_ALLOCATED = 256, +	ARG_BLOCK_BIN_MODE, +	ARG_BLOCK_CLASSES, +}; +  static const char cmdname[] = "zdb";  uint8_t dump_opt[512]; -#define	ALLOCATED_OPT	256 -  typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);  static uint64_t *zopt_metaslab = NULL; @@ -131,6 +135,20 @@ static objset_t *os;  static boolean_t kernel_init_done;  static boolean_t corruption_found = B_FALSE; +static enum { +	BIN_AUTO = 0, +	BIN_PSIZE, +	BIN_LSIZE, +	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); @@ -749,6 +767,12 @@ usage(void)  	(void) fprintf(stderr, "    Options to control amount of output:\n");  	(void) fprintf(stderr, "        -b --block-stats             "  	    "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                " @@ -1694,7 +1718,7 @@ dump_metaslab(metaslab_t *msp)  	    (u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,  	    (u_longlong_t)space_map_object(sm), freebuf); -	if (dump_opt[ALLOCATED_OPT] || +	if (dump_opt[ARG_ALLOCATED] ||  	    (dump_opt['m'] > 2 && !dump_opt['L'])) {  		mutex_enter(&msp->ms_lock);  		VERIFY0(metaslab_load(msp)); @@ -1705,7 +1729,7 @@ dump_metaslab(metaslab_t *msp)  		dump_metaslab_stats(msp);  	} -	if (dump_opt[ALLOCATED_OPT]) { +	if (dump_opt[ARG_ALLOCATED]) {  		uint64_t off = msp->ms_start;  		zfs_range_tree_walk(msp->ms_allocatable, dump_allocated,  		    &off); @@ -1726,7 +1750,7 @@ dump_metaslab(metaslab_t *msp)  		    SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);  	} -	if (dump_opt[ALLOCATED_OPT] || +	if (dump_opt[ARG_ALLOCATED] ||  	    (dump_opt['m'] > 2 && !dump_opt['L'])) {  		metaslab_unload(msp);  		mutex_exit(&msp->ms_lock); @@ -5814,6 +5838,34 @@ dump_size_histograms(zdb_cb_t *zcb)  	(void) printf("\nBlock Size Histogram\n"); +	switch (block_bin_mode) { +	case BIN_PSIZE: +		printf("(note: all categories are binned by %s)\n", "psize"); +		break; +	case BIN_LSIZE: +		printf("(note: all categories are binned by %s)\n", "lsize"); +		break; +	case BIN_ASIZE: +		printf("(note: all categories are binned by %s)\n", "asize"); +		break; +	default: +		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  	 */ @@ -6162,29 +6214,85 @@ skipped:  		    [BPE_GET_PSIZE(bp)]++;  		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  	 * every possible blocksize found in the pool.  	 */ -	int bin = highbit64(BP_GET_PSIZE(bp)) - 1; +	int bin; + +	/* +	 * Binning strategy: each bin includes blocks up to and including +	 * the given size (excluding blocks that fit into the previous bin). +	 * This way, the "4K" bin includes blocks within the (2K; 4K] range. +	 */ +#define	BIN(size) (highbit64((size) - 1)) + +	switch (block_bin_mode) { +	case BIN_PSIZE: bin = BIN(BP_GET_PSIZE(bp)); break; +	case BIN_LSIZE: bin = BIN(BP_GET_LSIZE(bp)); break; +	case BIN_ASIZE: bin = BIN(BP_GET_ASIZE(bp)); break; +	case BIN_AUTO: break; +	default: PANIC("bad block_bin_mode"); abort(); +	} + +	if (block_bin_mode == BIN_AUTO) +		bin = BIN(BP_GET_PSIZE(bp));  	zcb->zcb_psize_count[bin]++;  	zcb->zcb_psize_len[bin] += BP_GET_PSIZE(bp);  	zcb->zcb_psize_total += BP_GET_PSIZE(bp); -	bin = highbit64(BP_GET_LSIZE(bp)) - 1; +	if (block_bin_mode == BIN_AUTO) +		bin = BIN(BP_GET_LSIZE(bp));  	zcb->zcb_lsize_count[bin]++;  	zcb->zcb_lsize_len[bin] += BP_GET_LSIZE(bp);  	zcb->zcb_lsize_total += BP_GET_LSIZE(bp); -	bin = highbit64(BP_GET_ASIZE(bp)) - 1; +	if (block_bin_mode == BIN_AUTO) +		bin = BIN(BP_GET_ASIZE(bp));  	zcb->zcb_asize_count[bin]++;  	zcb->zcb_asize_len[bin] += BP_GET_ASIZE(bp);  	zcb->zcb_asize_total += BP_GET_ASIZE(bp); +#undef BIN + +hist_skipped:  	if (!do_claim)  		return; @@ -9426,7 +9534,11 @@ main(int argc, char **argv)  		{"livelist",		no_argument,		NULL, 'y'},  		{"zstd-headers",	no_argument,		NULL, 'Z'},  		{"allocated-map",	no_argument,		NULL, -		    ALLOCATED_OPT}, +		    ARG_ALLOCATED}, +		{"bin",			required_argument,	NULL, +		    ARG_BLOCK_BIN_MODE}, +		{"class",		required_argument,	NULL, +		    ARG_BLOCK_CLASSES},  		{0, 0, 0, 0}  	}; @@ -9457,7 +9569,7 @@ main(int argc, char **argv)  		case 'u':  		case 'y':  		case 'Z': -		case ALLOCATED_OPT: +		case ARG_ALLOCATED:  			dump_opt[c]++;  			dump_all = 0;  			break; @@ -9540,6 +9652,59 @@ main(int argc, char **argv)  		case 'x':  			vn_dumpdir = optarg;  			break; +		case ARG_BLOCK_BIN_MODE: +			if (strcmp(optarg, "lsize") == 0) { +				block_bin_mode = BIN_LSIZE; +			} else if (strcmp(optarg, "psize") == 0) { +				block_bin_mode = BIN_PSIZE; +			} else if (strcmp(optarg, "asize") == 0) { +				block_bin_mode = BIN_ASIZE; +			} else { +				(void) fprintf(stderr, +				    "--bin=\"%s\" must be one of \"lsize\", " +				    "\"psize\" or \"asize\"\n", optarg); +				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; @@ -9582,6 +9747,9 @@ main(int argc, char **argv)  	 */  	spa_mode_readable_spacemaps = B_TRUE; +	libspl_set_assert_ok((dump_opt['A'] == 1) || (dump_opt['A'] > 2)); +	zfs_recover = (dump_opt['A'] > 1); +  	if (dump_all)  		verbose = MAX(verbose, 1); @@ -9592,9 +9760,6 @@ main(int argc, char **argv)  			dump_opt[c] += verbose;  	} -	libspl_set_assert_ok((dump_opt['A'] == 1) || (dump_opt['A'] > 2)); -	zfs_recover = (dump_opt['A'] > 1); -  	argc -= optind;  	argv += optind;  	if (argc < 2 && dump_opt['R']) | 
