zdb.c revision fbabab8faf7439009737ccefe9d50152b38c26d1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <sys/zfs_context.h>
#include <sys/spa_impl.h>
#include <sys/zfs_znode.h>
#include <sys/vdev_impl.h>
#include <sys/metaslab_impl.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_pool.h>
#include <sys/zil_impl.h>
#include <sys/resource.h>
#include <sys/dmu_traverse.h>
#include <sys/zio_checksum.h>
#include <sys/zio_compress.h>
const char cmdname[] = "zdb";
extern void dump_intent_log(zilog_t *);
int zopt_objects = 0;
int zdb_advance = ADVANCE_PRE;
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
*/
const char *
{
return ("default,verbose"); /* $UMEM_DEBUG setting */
}
const char *
_umem_logging_init(void)
{
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
static void
usage(void)
{
"Usage: %s [-udibcsvLU] [-O order] [-B os:obj:level:blkid] "
"dataset [object...]\n"
" %s -C [pool]\n"
" %s -l dev\n",
"visitation order\n");
"simulate bad block\n");
"to make only that option verbose\n");
exit(1);
}
static void
{
exit(1);
}
static void
{
switch (nvpair_type(elem)) {
case DATA_TYPE_STRING:
{
char *value;
}
break;
case DATA_TYPE_UINT64:
{
}
break;
case DATA_TYPE_NVLIST:
{
nvpair_name(elem));
}
break;
case DATA_TYPE_NVLIST_ARRAY:
{
&count) == 0);
for (c = 0; c < count; c++) {
nvpair_name(elem), c);
}
}
break;
default:
(void) printf("bad config type %d for %s\n",
}
}
}
/* ARGSUSED */
static void
{
}
const char dump_zap_stars[] = "****************************************";
static void
{
int i;
int maxidx = 0;
for (i = 0; i < ZAP_HISTOGRAM_SIZE; i++) {
maxidx = i;
minidx = i;
}
if (max < dump_zap_width)
}
static void
{
int error;
if (error)
return;
if (zs.zs_ptrtbl_len == 0) {
(void) printf("\tmicrozap: %llu bytes, %llu entries\n",
return;
}
(void) printf("\tFat ZAP stats:\n");
(void) printf("\t\tPointer table: %llu elements\n",
(void) printf("\t\tZAP entries: %llu\n",
(void) printf("\t\tLeaf blocks: %llu\n",
(void) printf("\t\tTotal blocks: %llu\n",
(void) printf("\t\tOversize blocks: %llu\n",
(void) printf("\t\tLeafs with 2^n pointers:\n");
(void) printf("\t\tLeafs with n chained:\n");
(void) printf("\t\tBlocks with n*5 entries:\n");
(void) printf("\t\tBlocks n/10 full:\n");
(void) printf("\t\tEntries with n chunks:\n");
(void) printf("\t\tBuckets with n entries:\n");
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
void *prop;
int i;
(void) printf("\n");
zap_cursor_advance(&zc)) {
if (attr.za_num_integers == 0) {
(void) printf("\n");
continue;
}
} else {
for (i = 0; i < attr.za_num_integers; i++) {
switch (attr.za_integer_length) {
case 2:
(void) printf("%u ",
break;
case 4:
(void) printf("%u ",
break;
case 8:
(void) printf("%lld ",
break;
}
}
}
(void) printf("\n");
}
}
static void
{
if (smo->smo_object == 0)
return;
/*
* Print out the freelist entries in both encoded and decoded form.
*/
alloc = 0;
if (SM_DEBUG_DECODE(entry)) {
(void) printf("\t\t[%4llu] %s: txg %llu, pass %llu\n",
} else {
(void) printf("\t\t[%4llu] %c range:"
" %08llx-%08llx size: %06llx\n",
else
}
}
(void) printf("space_map_object alloc (%llu) INCONSISTENT "
"with space map summary (%llu)\n",
}
}
static void
{
char freebuf[5];
(void) printf("\t%10llx %10llu %5s\n",
freebuf);
return;
}
(void) printf(
"\tvdev %llu offset %08llx spacemap %4llu free %5s\n",
}
static void
{
int c, m;
(void) printf("\nMetaslabs:\n");
for (c = 0; c < rvd->vdev_children; c++) {
(void) printf("\n vdev %llu = %s\n\n",
(void) printf("\t%10s %10s %5s\n",
"offset", "spacemap", "free");
(void) printf("\t%10s %10s %5s\n",
"------", "--------", "----");
}
for (m = 0; m < vd->vdev_ms_count; m++)
(void) printf("\n");
}
}
static void
{
int c;
if (indent == 0)
(void) printf("\nDirty time logs:\n\n");
/*
* Everything in this DTL must appear in all parent DTL unions.
*/
(void) printf("\t%*soutage [%llu,%llu] length %llu\n",
indent, "",
}
(void) printf("\n");
&vd->vdev_dtl_map);
(void) printf("\n");
}
for (c = 0; c < vd->vdev_children; c++)
}
/*ARGSUSED*/
static void
{
}
static uint64_t
{
if (level < 0)
return (blkid);
}
/* ARGSUSED */
static int
{
char buffer[300];
int l;
"Error %d reading <%llu, %llu, %d, %llu>: ",
goto out;
}
} else {
}
} else {
}
}
}
fill++;
}
}
} else {
}
}
out:
} else {
// XXBP - Need to print number of active BPs here
"vdev=%llu off=%llx %llxL/%llxP/%llxA F=%llu B=%llu",
}
}
/*ARGSUSED*/
static void
{
int advance = zdb_advance;
(void) printf("Indirect blocks:\n");
if (object == 0)
advance |= ADVANCE_DATA;
continue;
(void) printf("\n");
}
/*ARGSUSED*/
static void
{
return;
(void) printf("\t\thead_dataset_obj = %llu\n",
(void) printf("\t\tparent_dir_obj = %llu\n",
(void) printf("\t\tclone_parent_obj = %llu\n",
(void) printf("\t\tchild_dir_zapobj = %llu\n",
(void) printf("\t\tprops_zapobj = %llu\n",
}
/*ARGSUSED*/
static void
{
char blkbuf[BP_SPRINTF_LEN];
return;
(void) printf("\t\tdataset_obj = %llu\n",
(void) printf("\t\tprev_snap_obj = %llu\n",
(void) printf("\t\tprev_snap_txg = %llu\n",
(void) printf("\t\tnext_snap_obj = %llu\n",
(void) printf("\t\tsnapnames_zapobj = %llu\n",
(void) printf("\t\tnum_children = %llu\n",
(void) printf("\t\tcreation_txg = %llu\n",
(void) printf("\t\tdeadlist_obj = %llu\n",
(void) printf("\t\tfsid_guid = %llu\n",
(void) printf("\t\tguid = %llu\n",
(void) printf("\t\trestoring = %llu\n",
}
static void
{
char numbuf[6];
return;
if (bplist_empty(&bpl)) {
bplist_close(&bpl);
return;
}
(void) printf("\n %s: %llu entries, %s\n",
bplist_close(&bpl);
return;
}
(void) printf("\n");
// XXBP - Do we want to see all DVAs, or just one?
(void) printf("\tItem %3llu: vdev=%llu off=%llx "
"%llxL/%llxP/%llxA F=%llu B=%llu\n",
}
bplist_close(&bpl);
}
static char *
{
char *path;
*--path = '\0';
for (;;) {
break;
break;
if (path[0] != '/')
*--path = '/';
return (path);
}
break;
*--path = '/';
}
return (path);
}
/*ARGSUSED*/
static void
{
(void) printf("\t%s\n",
return;
}
(void) printf("\tpath %s\n",
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
}
dump_none, /* unallocated */
dump_zap, /* object directory */
dump_uint64, /* object array */
dump_none, /* packed nvlist */
dump_packed_nvlist, /* packed nvlist size */
dump_none, /* bplist */
dump_none, /* bplist header */
dump_none, /* SPA space map header */
dump_none, /* SPA space map */
dump_none, /* ZIL intent log */
dump_dnode, /* DMU dnode */
dump_dmu_objset, /* DMU objset */
dump_dsl_dir, /* DSL directory */
dump_zap, /* DSL directory child map */
dump_zap, /* DSL dataset snap map */
dump_zap, /* DSL props */
dump_dsl_dataset, /* DSL dataset */
dump_znode, /* ZFS znode */
dump_acl, /* ZFS ACL */
dump_uint8, /* ZFS plain file */
dump_zap, /* ZFS directory */
dump_zap, /* ZFS master node */
dump_zap, /* ZFS delete queue */
dump_uint8, /* zvol object */
dump_zap, /* zvol prop */
dump_uint8, /* other uint8[] */
dump_uint64, /* other uint64[] */
dump_zap, /* other ZAP */
};
static void
{
char aux[50];
int error;
if (*print_header) {
(void) printf("\n Object lvl iblk dblk lsize"
" psize type\n");
*print_header = 0;
}
if (object == 0) {
} else {
}
lsize);
aux[0] = '\0';
(void) printf("%10lld %3u %5s %5s %5s %5s %s%s\n",
(void) printf("%10s %3s %5s %5s %5s %5s %s\n",
}
if (verbosity >= 4) {
*print_header = 1;
}
if (verbosity >= 5)
if (verbosity >= 5) {
/*
* Report the list of segments that comprise the object.
*/
int minlvl = 1;
minlvl = 0;
}
for (;;) {
blkfill);
if (error)
break;
blkfill);
(void) printf("\t\tsegment [%016llx, %016llx)"
if (error)
break;
}
}
}
static char *objset_types[DMU_OST_NUMTYPES] = {
"NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
/*ARGSUSED*/
static void
{
char numbuf[8];
char blkbuf[BP_SPRINTF_LEN];
char osname[MAXNAMELEN];
char *type = "UNKNOWN";
int print_header = 1;
int i, error;
}
if (verbosity >= 4) {
} else {
blkbuf[0] = '\0';
}
(void) printf("Dataset %s [%s], ID %llu, cr_txg %llu, last_txg %llu, "
"%s, %llu objects%s\n",
blkbuf);
if (verbosity < 2)
return;
if (zopt_objects != 0) {
for (i = 0; i < zopt_objects; i++)
&print_header);
(void) printf("\n");
return;
}
object_count = 1;
object = 0;
object_count++;
}
(void) printf("\n");
}
static void
{
(void) printf("Uberblock\n\n");
(void) printf("\ttimestamp = %llu UTC = %s",
char blkbuf[BP_SPRINTF_LEN];
}
(void) printf("\n");
}
static void
dump_config(const char *pool)
{
}
}
static void
dump_label(const char *dev)
{
int fd;
int l;
exit(1);
}
exit(1);
}
for (l = 0; l < VDEV_LABELS; l++) {
(void) printf("--------------------------------------------\n");
(void) printf("LABEL %d\n", l);
(void) printf("--------------------------------------------\n");
(void) printf("failed to read label %d\n", l);
continue;
}
(void) printf("failed to unpack label %d\n", l);
continue;
}
}
}
/*ARGSUSED*/
static void
{
int error;
if (error) {
return;
}
}
static void
{
int c, m, error;
for (c = 0; c < rvd->vdev_children; c++) {
for (m = 0; m < vd->vdev_ms_count; m++) {
if (error)
fatal("%s bad space map #%d, error %d",
}
}
}
static int
{
int error;
return (ENXIO);
return (ENXIO);
if (DVA_GET_GANG(dva)) {
int g;
/* LINTED - compile time assert */
if (error)
return (error);
if (BP_SHOULD_BYTESWAP(&blk))
for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
break;
if (error)
return (error);
}
}
return (EAGAIN); /* allocated more than once */
}
return (ESTALE); /* not allocated at all */
}
return (0);
}
static void
{
/* LINTED */
(void) printf("leaked space: vdev %llu, offset 0x%llx, size %llu\n",
(u_longlong_t)size);
}
static void
{
int c, m;
for (c = 0; c < rvd->vdev_children; c++) {
for (m = 0; m < vd->vdev_ms_count; m++) {
&msp->ms_allocmap[0]);
}
}
}
static void
{
uberblock_t ub = { 0 };
/*
* Reopen all devices to purge zdb's vdev caches.
*/
/*
* Reload the uberblock.
*/
}
/*
* Verify that the sum of the sizes of all blocks in the pool adds up
* to the SPA's sa_alloc total.
*/
typedef struct zdb_blkstats {
#define DMU_OT_DEFERRED DMU_OT_NONE
#define DMU_OT_TOTAL DMU_OT_NUMTYPES
#define ZB_TOTAL ZB_MAXLEVEL
typedef struct zdb_cb {
int zcb_readfails;
int zcb_haderrors;
} zdb_cb_t;
static blkptr_cb_t zdb_blkptr_cb;
static void
{
int i, error;
for (i = 0; i < 4; i++) {
}
if (dump_opt['L'])
return;
if (error == 0)
return;
}
static void
{
}
}
static int
{
char blkbuf[BP_SPRINTF_LEN];
int error = 0;
} else {
}
else
blkbuf[0] = '\0';
(void) printf("zdb_blkptr_cb: Got error %d reading "
"<%llu, %llu, %d, %llx> %s -- %s\n",
return (error);
}
zcb->zcb_readfails = 0;
(void) printf("objset %llu object %llu offset 0x%llx %s\n",
blkbuf);
}
if (type == DMU_OT_OBJSET) {
spa_first_txg(spa));
}
return (0);
}
static int
{
int leaks = 0;
int advance = zdb_advance;
int flags;
int e;
if (dump_opt['c'])
advance |= ADVANCE_DATA;
advance |= ADVANCE_PRUNE;
(void) printf("\nTraversing all blocks to %sverify"
" nothing leaked ...\n",
/*
* Load all space maps. As we traverse the pool, if we find a block
* that's not in its space map, that indicates a double-allocation,
* reference to a freed block, or an unclaimed block. Otherwise we
* remove the block from the space map. If the space maps are not
* empty when we're done, that indicates leaked blocks.
*/
if (!dump_opt['L'])
/*
* If there's a deferred-free bplist, process that first.
*/
if (spa->spa_sync_bplist_obj != 0) {
char blkbuf[BP_SPRINTF_LEN];
(void) printf("[%s] %s\n",
"deferred free", blkbuf);
}
}
}
/*
* Now traverse the pool. If we're read all data to verify checksums,
* do a scrubbing read so that we validate all copies.
*/
if (advance & ADVANCE_DATA)
flags |= ZIO_FLAG_SCRUB;
continue;
if (zcb.zcb_haderrors) {
(void) printf("\nError counts:\n\n");
for (e = 0; e < 256; e++) {
if (zcb.zcb_errors[e] != 0) {
(void) printf("\t%5d %llu\n",
}
}
}
/*
* Report any leaked segments.
*/
if (!dump_opt['L'])
if (dump_opt['L'])
(void) printf("\n\n *** Live pool traversal; "
"block counts are only approximate ***\n\n");
(void) printf("\n\tNo leaks (block sum matches space"
" maps exactly)\n");
} else {
(void) printf("block traversal size %llu != alloc %llu "
"(leaked %lld)\n",
leaks = 1;
}
return (2);
(void) printf("\n");
(void) printf("\tbp count: %10llu\n",
(void) printf("\tbp logical: %10llu\t avg: %6llu\n",
(void) printf("\tbp physical: %10llu\t avg:"
" %6llu\tcompression: %6.2f\n",
(void) printf("\tbp allocated: %10llu\t avg:"
" %6llu\tcompression: %6.2f\n",
(void) printf("\tSPA allocated: %10llu\tused: %5.2f%%\n",
int l, t, level;
(void) printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
"\t avg\t comp\t%%Total\tType\n");
for (t = 0; t <= DMU_OT_NUMTYPES; t++) {
char *typename;
(void) printf("%6s\t%5s\t%5s\t%5s"
"\t%5s\t%5s\t%6s\t%s\n",
"-",
"-",
"-",
"-",
"-",
"-",
"-",
typename);
continue;
}
continue;
continue;
continue;
(void) printf("%6s\t%5s\t%5s\t%5s\t%5s"
"\t%5.2f\t%6.2f\t",
else
(void) printf(" L%d %s\n",
}
}
}
(void) printf("\n");
if (leaks)
return (2);
if (zcb.zcb_haderrors)
return (3);
return (0);
}
static void
{
int rc = 0;
if (dump_opt['u'])
}
}
if (dump_opt['s'])
if (rc != 0)
}
int
{
int i, c;
char *endstr;
int dump_all = 1;
int verbose = 0;
int error;
switch (c) {
case 'u':
case 'd':
case 'i':
case 'b':
case 'c':
case 's':
case 'C':
case 'l':
dump_opt[c]++;
dump_all = 0;
break;
case 'L':
dump_opt[c]++;
break;
case 'O':
if (endstr[0] == '!') {
endstr++;
set = 0;
} else {
set = 1;
}
flag = ADVANCE_PRE;
flag = ADVANCE_PRE;
flag = ADVANCE_DATA;
} else {
usage();
}
if (set)
zdb_advance |= flag;
else
zdb_advance &= ~flag;
break;
case 'B':
(void) printf("simulating bad block "
"<%llu, %llu, %d, %llx>\n",
break;
case 'v':
verbose++;
break;
case 'U':
spa_config_dir = "/tmp";
break;
default:
usage();
break;
}
}
for (c = 0; c < 256; c++) {
dump_opt[c] = 1;
if (dump_opt[c])
}
if (argc < 1) {
if (dump_opt['C']) {
return (0);
}
usage();
}
if (dump_opt['l']) {
dump_label(argv[0]);
return (0);
}
if (dump_opt['C'])
dump_config(argv[0]);
} else {
}
if (error)
argv++;
if (--argc > 0) {
zopt_objects = argc;
for (i = 0; i < zopt_objects; i++) {
errno = 0;
if (zopt_object[i] == 0 && errno != 0)
fatal("bad object number %s: %s",
}
}
} else {
}
kernel_fini();
return (0);
}