summaryrefslogtreecommitdiffstats
path: root/cddl/contrib/opensolaris/cmd/zdb
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2007-04-06 01:09:06 +0000
committerpjd <pjd@FreeBSD.org>2007-04-06 01:09:06 +0000
commit3b005d330261f33318ca1ee3fef1940237fd788b (patch)
tree3061c8734d9ce560165e672836837a0f411a83c9 /cddl/contrib/opensolaris/cmd/zdb
parent3be454b8211f48e634e6587f53807d3b5013e973 (diff)
downloadFreeBSD-src-3b005d330261f33318ca1ee3fef1940237fd788b.zip
FreeBSD-src-3b005d330261f33318ca1ee3fef1940237fd788b.tar.gz
Please welcome ZFS - The last word in file systems.
ZFS file system was ported from OpenSolaris operating system. The code in under CDDL license. I'd like to thank all SUN developers that created this great piece of software. Supported by: Wheel LTD (http://www.wheel.pl/) Supported by: The FreeBSD Foundation (http://www.freebsdfoundation.org/) Supported by: Sentex (http://www.sentex.net/)
Diffstat (limited to 'cddl/contrib/opensolaris/cmd/zdb')
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.897
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c2185
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb_il.c354
3 files changed, 2636 insertions, 0 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.8 b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
new file mode 100644
index 0000000..2f1c541
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
@@ -0,0 +1,97 @@
+'\" te
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (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
+.\" or http://www.opensolaris.org/os/licensing.
+.\" 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 (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
+.TH zdb 1M "31 Oct 2005" "SunOS 5.11" "System Administration Commands"
+.SH NAME
+zdb \- ZFS debugger
+.SH SYNOPSIS
+.LP
+.nf
+\fBzdb\fR \fIpool\fR
+.fi
+
+.SH DESCRIPTION
+
+.LP
+The \fBzdb\fR command is used by support engineers to diagnose failures and gather statistics. Since the \fBZFS\fR file system is always consistent on disk and is self-repairing, \fBzdb\fR should only be run under the direction by a support engineer.
+.LP
+If no arguments are specified, \fBzdb\fR, performs basic consistency checks on the pool and associated datasets, and report any problems detected.
+.LP
+Any options supported by this command are internal to Sun and subject to change at any time.
+.SH EXIT STATUS
+
+.LP
+The following exit values are returned:
+.sp
+.ne 2
+.mk
+.na
+\fB\fB0\fR\fR
+.ad
+.RS 5n
+.rt
+The pool is consistent.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB1\fR\fR
+.ad
+.RS 5n
+.rt
+An error was detected.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB2\fR\fR
+.ad
+.RS 5n
+.rt
+Invalid command line options were specified.
+.RE
+
+.SH ATTRIBUTES
+
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+tab() box;
+cw(2.75i) |cw(2.75i)
+lw(2.75i) |lw(2.75i)
+.
+ATTRIBUTE TYPEATTRIBUTE VALUE
+_
+AvailabilitySUNWzfsu
+_
+Interface StabilityUnstable
+.TE
+
+.SH SEE ALSO
+
+.LP
+\fBzfs\fR(1M), \fBzpool\fR(1M), \fBattributes\fR(5)
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
new file mode 100644
index 0000000..bb7a52e
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -0,0 +1,2185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/metaslab_impl.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_pool.h>
+#include <sys/dbuf.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/dmu_traverse.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+
+const char cmdname[] = "zdb";
+uint8_t dump_opt[256];
+
+typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
+
+extern void dump_intent_log(zilog_t *);
+uint64_t *zopt_object = NULL;
+int zopt_objects = 0;
+int zdb_advance = ADVANCE_PRE;
+zbookmark_t zdb_noread = { 0, 0, ZB_NO_LEVEL, 0 };
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "Usage: %s [-udibcsvLU] [-O order] [-B os:obj:level:blkid] "
+ "dataset [object...]\n"
+ " %s -C [pool]\n"
+ " %s -l dev\n"
+ " %s -R vdev:offset:size:flags\n",
+ cmdname, cmdname, cmdname, cmdname);
+
+ (void) fprintf(stderr, " -u uberblock\n");
+ (void) fprintf(stderr, " -d datasets\n");
+ (void) fprintf(stderr, " -C cached pool configuration\n");
+ (void) fprintf(stderr, " -i intent logs\n");
+ (void) fprintf(stderr, " -b block statistics\n");
+ (void) fprintf(stderr, " -c checksum all data blocks\n");
+ (void) fprintf(stderr, " -s report stats on zdb's I/O\n");
+ (void) fprintf(stderr, " -v verbose (applies to all others)\n");
+ (void) fprintf(stderr, " -l dump label contents\n");
+ (void) fprintf(stderr, " -L live pool (allows some errors)\n");
+ (void) fprintf(stderr, " -O [!]<pre|post|prune|data|holes> "
+ "visitation order\n");
+ (void) fprintf(stderr, " -U use zpool.cache in /tmp\n");
+ (void) fprintf(stderr, " -B objset:object:level:blkid -- "
+ "simulate bad block\n");
+ (void) fprintf(stderr, " -R read and display block from a"
+ "device\n");
+ (void) fprintf(stderr, "Specify an option more than once (e.g. -bb) "
+ "to make only that option verbose\n");
+ (void) fprintf(stderr, "Default is to dump everything non-verbosely\n");
+ exit(1);
+}
+
+static void
+fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) fprintf(stderr, "%s: ", cmdname);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+static void
+dump_nvlist(nvlist_t *list, int indent)
+{
+ nvpair_t *elem = NULL;
+
+ while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
+ switch (nvpair_type(elem)) {
+ case DATA_TYPE_STRING:
+ {
+ char *value;
+
+ VERIFY(nvpair_value_string(elem, &value) == 0);
+ (void) printf("%*s%s='%s'\n", indent, "",
+ nvpair_name(elem), value);
+ }
+ break;
+
+ case DATA_TYPE_UINT64:
+ {
+ uint64_t value;
+
+ VERIFY(nvpair_value_uint64(elem, &value) == 0);
+ (void) printf("%*s%s=%llu\n", indent, "",
+ nvpair_name(elem), (u_longlong_t)value);
+ }
+ break;
+
+ case DATA_TYPE_NVLIST:
+ {
+ nvlist_t *value;
+
+ VERIFY(nvpair_value_nvlist(elem, &value) == 0);
+ (void) printf("%*s%s\n", indent, "",
+ nvpair_name(elem));
+ dump_nvlist(value, indent + 4);
+ }
+ break;
+
+ case DATA_TYPE_NVLIST_ARRAY:
+ {
+ nvlist_t **value;
+ uint_t c, count;
+
+ VERIFY(nvpair_value_nvlist_array(elem, &value,
+ &count) == 0);
+
+ for (c = 0; c < count; c++) {
+ (void) printf("%*s%s[%u]\n", indent, "",
+ nvpair_name(elem), c);
+ dump_nvlist(value[c], indent + 8);
+ }
+ }
+ break;
+
+ default:
+
+ (void) printf("bad config type %d for %s\n",
+ nvpair_type(elem), nvpair_name(elem));
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ nvlist_t *nv;
+ size_t nvsize = *(uint64_t *)data;
+ char *packed = umem_alloc(nvsize, UMEM_NOFAIL);
+
+ VERIFY(0 == dmu_read(os, object, 0, nvsize, packed));
+
+ VERIFY(nvlist_unpack(packed, nvsize, &nv, 0) == 0);
+
+ umem_free(packed, nvsize);
+
+ dump_nvlist(nv, 8);
+
+ nvlist_free(nv);
+}
+
+const char dump_zap_stars[] = "****************************************";
+const int dump_zap_width = sizeof (dump_zap_stars) - 1;
+
+static void
+dump_zap_histogram(uint64_t histo[ZAP_HISTOGRAM_SIZE])
+{
+ int i;
+ int minidx = ZAP_HISTOGRAM_SIZE - 1;
+ int maxidx = 0;
+ uint64_t max = 0;
+
+ for (i = 0; i < ZAP_HISTOGRAM_SIZE; i++) {
+ if (histo[i] > max)
+ max = histo[i];
+ if (histo[i] > 0 && i > maxidx)
+ maxidx = i;
+ if (histo[i] > 0 && i < minidx)
+ minidx = i;
+ }
+
+ if (max < dump_zap_width)
+ max = dump_zap_width;
+
+ for (i = minidx; i <= maxidx; i++)
+ (void) printf("\t\t\t%u: %6llu %s\n", i, (u_longlong_t)histo[i],
+ &dump_zap_stars[(max - histo[i]) * dump_zap_width / max]);
+}
+
+static void
+dump_zap_stats(objset_t *os, uint64_t object)
+{
+ int error;
+ zap_stats_t zs;
+
+ error = zap_get_stats(os, object, &zs);
+ if (error)
+ return;
+
+ if (zs.zs_ptrtbl_len == 0) {
+ ASSERT(zs.zs_num_blocks == 1);
+ (void) printf("\tmicrozap: %llu bytes, %llu entries\n",
+ (u_longlong_t)zs.zs_blocksize,
+ (u_longlong_t)zs.zs_num_entries);
+ return;
+ }
+
+ (void) printf("\tFat ZAP stats:\n");
+
+ (void) printf("\t\tPointer table:\n");
+ (void) printf("\t\t\t%llu elements\n",
+ (u_longlong_t)zs.zs_ptrtbl_len);
+ (void) printf("\t\t\tzt_blk: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_blk);
+ (void) printf("\t\t\tzt_numblks: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_numblks);
+ (void) printf("\t\t\tzt_shift: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_zt_shift);
+ (void) printf("\t\t\tzt_blks_copied: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_blks_copied);
+ (void) printf("\t\t\tzt_nextblk: %llu\n",
+ (u_longlong_t)zs.zs_ptrtbl_nextblk);
+
+ (void) printf("\t\tZAP entries: %llu\n",
+ (u_longlong_t)zs.zs_num_entries);
+ (void) printf("\t\tLeaf blocks: %llu\n",
+ (u_longlong_t)zs.zs_num_leafs);
+ (void) printf("\t\tTotal blocks: %llu\n",
+ (u_longlong_t)zs.zs_num_blocks);
+ (void) printf("\t\tzap_block_type: 0x%llx\n",
+ (u_longlong_t)zs.zs_block_type);
+ (void) printf("\t\tzap_magic: 0x%llx\n",
+ (u_longlong_t)zs.zs_magic);
+ (void) printf("\t\tzap_salt: 0x%llx\n",
+ (u_longlong_t)zs.zs_salt);
+
+ (void) printf("\t\tLeafs with 2^n pointers:\n");
+ dump_zap_histogram(zs.zs_leafs_with_2n_pointers);
+
+ (void) printf("\t\tBlocks with n*5 entries:\n");
+ dump_zap_histogram(zs.zs_blocks_with_n5_entries);
+
+ (void) printf("\t\tBlocks n/10 full:\n");
+ dump_zap_histogram(zs.zs_blocks_n_tenths_full);
+
+ (void) printf("\t\tEntries with n chunks:\n");
+ dump_zap_histogram(zs.zs_entries_using_n_chunks);
+
+ (void) printf("\t\tBuckets with n entries:\n");
+ dump_zap_histogram(zs.zs_buckets_with_n_entries);
+}
+
+/*ARGSUSED*/
+static void
+dump_none(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+void
+dump_uint8(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_uint64(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_zap(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+ void *prop;
+ int i;
+
+ dump_zap_stats(os, object);
+ (void) printf("\n");
+
+ for (zap_cursor_init(&zc, os, object);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ (void) printf("\t\t%s = ", attr.za_name);
+ if (attr.za_num_integers == 0) {
+ (void) printf("\n");
+ continue;
+ }
+ prop = umem_zalloc(attr.za_num_integers *
+ attr.za_integer_length, UMEM_NOFAIL);
+ (void) zap_lookup(os, object, attr.za_name,
+ attr.za_integer_length, attr.za_num_integers, prop);
+ if (attr.za_integer_length == 1) {
+ (void) printf("%s", (char *)prop);
+ } else {
+ for (i = 0; i < attr.za_num_integers; i++) {
+ switch (attr.za_integer_length) {
+ case 2:
+ (void) printf("%u ",
+ ((uint16_t *)prop)[i]);
+ break;
+ case 4:
+ (void) printf("%u ",
+ ((uint32_t *)prop)[i]);
+ break;
+ case 8:
+ (void) printf("%lld ",
+ (u_longlong_t)((int64_t *)prop)[i]);
+ break;
+ }
+ }
+ }
+ (void) printf("\n");
+ umem_free(prop, attr.za_num_integers * attr.za_integer_length);
+ }
+ zap_cursor_fini(&zc);
+}
+
+static void
+dump_spacemap(objset_t *os, space_map_obj_t *smo, space_map_t *sm)
+{
+ uint64_t alloc, offset, entry;
+ uint8_t mapshift = sm->sm_shift;
+ uint64_t mapstart = sm->sm_start;
+ char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
+ "INVALID", "INVALID", "INVALID", "INVALID" };
+
+ if (smo->smo_object == 0)
+ return;
+
+ /*
+ * Print out the freelist entries in both encoded and decoded form.
+ */
+ alloc = 0;
+ for (offset = 0; offset < smo->smo_objsize; offset += sizeof (entry)) {
+ VERIFY(0 == dmu_read(os, smo->smo_object, offset,
+ sizeof (entry), &entry));
+ if (SM_DEBUG_DECODE(entry)) {
+ (void) printf("\t\t[%4llu] %s: txg %llu, pass %llu\n",
+ (u_longlong_t)(offset / sizeof (entry)),
+ ddata[SM_DEBUG_ACTION_DECODE(entry)],
+ (u_longlong_t)SM_DEBUG_TXG_DECODE(entry),
+ (u_longlong_t)SM_DEBUG_SYNCPASS_DECODE(entry));
+ } else {
+ (void) printf("\t\t[%4llu] %c range:"
+ " %08llx-%08llx size: %06llx\n",
+ (u_longlong_t)(offset / sizeof (entry)),
+ SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F',
+ (u_longlong_t)((SM_OFFSET_DECODE(entry) <<
+ mapshift) + mapstart),
+ (u_longlong_t)((SM_OFFSET_DECODE(entry) <<
+ mapshift) + mapstart + (SM_RUN_DECODE(entry) <<
+ mapshift)),
+ (u_longlong_t)(SM_RUN_DECODE(entry) << mapshift));
+ if (SM_TYPE_DECODE(entry) == SM_ALLOC)
+ alloc += SM_RUN_DECODE(entry) << mapshift;
+ else
+ alloc -= SM_RUN_DECODE(entry) << mapshift;
+ }
+ }
+ if (alloc != smo->smo_alloc) {
+ (void) printf("space_map_object alloc (%llu) INCONSISTENT "
+ "with space map summary (%llu)\n",
+ (u_longlong_t)smo->smo_alloc, (u_longlong_t)alloc);
+ }
+}
+
+static void
+dump_metaslab(metaslab_t *msp)
+{
+ char freebuf[5];
+ space_map_obj_t *smo = &msp->ms_smo;
+ vdev_t *vd = msp->ms_group->mg_vd;
+ spa_t *spa = vd->vdev_spa;
+
+ nicenum(msp->ms_map.sm_size - smo->smo_alloc, freebuf);
+
+ if (dump_opt['d'] <= 5) {
+ (void) printf("\t%10llx %10llu %5s\n",
+ (u_longlong_t)msp->ms_map.sm_start,
+ (u_longlong_t)smo->smo_object,
+ freebuf);
+ return;
+ }
+
+ (void) printf(
+ "\tvdev %llu offset %08llx spacemap %4llu free %5s\n",
+ (u_longlong_t)vd->vdev_id, (u_longlong_t)msp->ms_map.sm_start,
+ (u_longlong_t)smo->smo_object, freebuf);
+
+ ASSERT(msp->ms_map.sm_size == (1ULL << vd->vdev_ms_shift));
+
+ dump_spacemap(spa->spa_meta_objset, smo, &msp->ms_map);
+}
+
+static void
+dump_metaslabs(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ vdev_t *vd;
+ int c, m;
+
+ (void) printf("\nMetaslabs:\n");
+
+ for (c = 0; c < rvd->vdev_children; c++) {
+ vd = rvd->vdev_child[c];
+
+ spa_config_enter(spa, RW_READER, FTAG);
+ (void) printf("\n vdev %llu = %s\n\n",
+ (u_longlong_t)vd->vdev_id, vdev_description(vd));
+ spa_config_exit(spa, FTAG);
+
+ if (dump_opt['d'] <= 5) {
+ (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++)
+ dump_metaslab(vd->vdev_ms[m]);
+ (void) printf("\n");
+ }
+}
+
+static void
+dump_dtl(vdev_t *vd, int indent)
+{
+ avl_tree_t *t = &vd->vdev_dtl_map.sm_root;
+ spa_t *spa = vd->vdev_spa;
+ space_seg_t *ss;
+ vdev_t *pvd;
+ int c;
+
+ if (indent == 0)
+ (void) printf("\nDirty time logs:\n\n");
+
+ spa_config_enter(spa, RW_READER, FTAG);
+ (void) printf("\t%*s%s\n", indent, "", vdev_description(vd));
+ spa_config_exit(spa, FTAG);
+
+ for (ss = avl_first(t); ss; ss = AVL_NEXT(t, ss)) {
+ /*
+ * Everything in this DTL must appear in all parent DTL unions.
+ */
+ for (pvd = vd; pvd; pvd = pvd->vdev_parent)
+ ASSERT(vdev_dtl_contains(&pvd->vdev_dtl_map,
+ ss->ss_start, ss->ss_end - ss->ss_start));
+ (void) printf("\t%*soutage [%llu,%llu] length %llu\n",
+ indent, "",
+ (u_longlong_t)ss->ss_start,
+ (u_longlong_t)ss->ss_end - 1,
+ (u_longlong_t)(ss->ss_end - ss->ss_start));
+ }
+
+ (void) printf("\n");
+
+ if (dump_opt['d'] > 5 && vd->vdev_children == 0) {
+ dump_spacemap(vd->vdev_spa->spa_meta_objset, &vd->vdev_dtl,
+ &vd->vdev_dtl_map);
+ (void) printf("\n");
+ }
+
+ for (c = 0; c < vd->vdev_children; c++)
+ dump_dtl(vd->vdev_child[c], indent + 4);
+}
+
+/*ARGSUSED*/
+static void
+dump_dnode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static uint64_t
+blkid2offset(dnode_phys_t *dnp, int level, uint64_t blkid)
+{
+ if (level < 0)
+ return (blkid);
+
+ return ((blkid << (level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) *
+ dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+}
+
+static void
+sprintf_blkptr_compact(char *blkbuf, blkptr_t *bp, int alldvas)
+{
+ dva_t *dva = bp->blk_dva;
+ int ndvas = alldvas ? BP_GET_NDVAS(bp) : 1;
+ int i;
+
+ blkbuf[0] = '\0';
+
+ for (i = 0; i < ndvas; i++)
+ (void) sprintf(blkbuf + strlen(blkbuf), "%llu:%llx:%llx ",
+ (u_longlong_t)DVA_GET_VDEV(&dva[i]),
+ (u_longlong_t)DVA_GET_OFFSET(&dva[i]),
+ (u_longlong_t)DVA_GET_ASIZE(&dva[i]));
+
+ (void) sprintf(blkbuf + strlen(blkbuf), "%llxL/%llxP F=%llu B=%llu",
+ (u_longlong_t)BP_GET_LSIZE(bp),
+ (u_longlong_t)BP_GET_PSIZE(bp),
+ (u_longlong_t)bp->blk_fill,
+ (u_longlong_t)bp->blk_birth);
+}
+
+/* ARGSUSED */
+static int
+zdb_indirect_cb(traverse_blk_cache_t *bc, spa_t *spa, void *a)
+{
+ zbookmark_t *zb = &bc->bc_bookmark;
+ blkptr_t *bp = &bc->bc_blkptr;
+ void *data = bc->bc_data;
+ dnode_phys_t *dnp = bc->bc_dnode;
+ char blkbuf[BP_SPRINTF_LEN + 80];
+ int l;
+
+ if (bc->bc_errno) {
+ (void) sprintf(blkbuf,
+ "Error %d reading <%llu, %llu, %lld, %llu>: ",
+ bc->bc_errno,
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (u_longlong_t)zb->zb_level,
+ (u_longlong_t)zb->zb_blkid);
+ goto out;
+ }
+
+ if (zb->zb_level == -1) {
+ ASSERT3U(BP_GET_TYPE(bp), ==, DMU_OT_OBJSET);
+ ASSERT3U(BP_GET_LEVEL(bp), ==, 0);
+ } else {
+ ASSERT3U(BP_GET_TYPE(bp), ==, dnp->dn_type);
+ ASSERT3U(BP_GET_LEVEL(bp), ==, zb->zb_level);
+ }
+
+ if (zb->zb_level > 0) {
+ uint64_t fill = 0;
+ blkptr_t *bpx, *bpend;
+
+ for (bpx = data, bpend = bpx + BP_GET_LSIZE(bp) / sizeof (*bpx);
+ bpx < bpend; bpx++) {
+ if (bpx->blk_birth != 0) {
+ fill += bpx->blk_fill;
+ } else {
+ ASSERT(bpx->blk_fill == 0);
+ }
+ }
+ ASSERT3U(fill, ==, bp->blk_fill);
+ }
+
+ if (zb->zb_level == 0 && dnp->dn_type == DMU_OT_DNODE) {
+ uint64_t fill = 0;
+ dnode_phys_t *dnx, *dnend;
+
+ for (dnx = data, dnend = dnx + (BP_GET_LSIZE(bp)>>DNODE_SHIFT);
+ dnx < dnend; dnx++) {
+ if (dnx->dn_type != DMU_OT_NONE)
+ fill++;
+ }
+ ASSERT3U(fill, ==, bp->blk_fill);
+ }
+
+ (void) sprintf(blkbuf, "%16llx ",
+ (u_longlong_t)blkid2offset(dnp, zb->zb_level, zb->zb_blkid));
+
+ ASSERT(zb->zb_level >= 0);
+
+ for (l = dnp->dn_nlevels - 1; l >= -1; l--) {
+ if (l == zb->zb_level) {
+ (void) sprintf(blkbuf + strlen(blkbuf), "L%llx",
+ (u_longlong_t)zb->zb_level);
+ } else {
+ (void) sprintf(blkbuf + strlen(blkbuf), " ");
+ }
+ }
+
+out:
+ if (bp->blk_birth == 0) {
+ (void) sprintf(blkbuf + strlen(blkbuf), "<hole>");
+ (void) printf("%s\n", blkbuf);
+ } else {
+ sprintf_blkptr_compact(blkbuf + strlen(blkbuf), bp,
+ dump_opt['d'] > 5 ? 1 : 0);
+ (void) printf("%s\n", blkbuf);
+ }
+
+ return (bc->bc_errno ? ERESTART : 0);
+}
+
+/*ARGSUSED*/
+static void
+dump_indirect(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ traverse_handle_t *th;
+ uint64_t objset = dmu_objset_id(os);
+ int advance = zdb_advance;
+
+ (void) printf("Indirect blocks:\n");
+
+ if (object == 0)
+ advance |= ADVANCE_DATA;
+
+ th = traverse_init(dmu_objset_spa(os), zdb_indirect_cb, NULL, advance,
+ ZIO_FLAG_CANFAIL);
+ th->th_noread = zdb_noread;
+
+ traverse_add_dnode(th, 0, -1ULL, objset, object);
+
+ while (traverse_more(th) == EAGAIN)
+ continue;
+
+ (void) printf("\n");
+
+ traverse_fini(th);
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dsl_dir_phys_t *dd = data;
+ time_t crtime;
+ char used[6], compressed[6], uncompressed[6], quota[6], resv[6];
+
+ if (dd == NULL)
+ return;
+
+ ASSERT(size == sizeof (*dd));
+
+ crtime = dd->dd_creation_time;
+ nicenum(dd->dd_used_bytes, used);
+ nicenum(dd->dd_compressed_bytes, compressed);
+ nicenum(dd->dd_uncompressed_bytes, uncompressed);
+ nicenum(dd->dd_quota, quota);
+ nicenum(dd->dd_reserved, resv);
+
+ (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+ (void) printf("\t\thead_dataset_obj = %llu\n",
+ (u_longlong_t)dd->dd_head_dataset_obj);
+ (void) printf("\t\tparent_dir_obj = %llu\n",
+ (u_longlong_t)dd->dd_parent_obj);
+ (void) printf("\t\tclone_parent_obj = %llu\n",
+ (u_longlong_t)dd->dd_clone_parent_obj);
+ (void) printf("\t\tchild_dir_zapobj = %llu\n",
+ (u_longlong_t)dd->dd_child_dir_zapobj);
+ (void) printf("\t\tused_bytes = %s\n", used);
+ (void) printf("\t\tcompressed_bytes = %s\n", compressed);
+ (void) printf("\t\tuncompressed_bytes = %s\n", uncompressed);
+ (void) printf("\t\tquota = %s\n", quota);
+ (void) printf("\t\treserved = %s\n", resv);
+ (void) printf("\t\tprops_zapobj = %llu\n",
+ (u_longlong_t)dd->dd_props_zapobj);
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ dsl_dataset_phys_t *ds = data;
+ time_t crtime;
+ char used[6], compressed[6], uncompressed[6], unique[6];
+ char blkbuf[BP_SPRINTF_LEN];
+
+ if (ds == NULL)
+ return;
+
+ ASSERT(size == sizeof (*ds));
+ crtime = ds->ds_creation_time;
+ nicenum(ds->ds_used_bytes, used);
+ nicenum(ds->ds_compressed_bytes, compressed);
+ nicenum(ds->ds_uncompressed_bytes, uncompressed);
+ nicenum(ds->ds_unique_bytes, unique);
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, &ds->ds_bp);
+
+ (void) printf("\t\tdataset_obj = %llu\n",
+ (u_longlong_t)ds->ds_dir_obj);
+ (void) printf("\t\tprev_snap_obj = %llu\n",
+ (u_longlong_t)ds->ds_prev_snap_obj);
+ (void) printf("\t\tprev_snap_txg = %llu\n",
+ (u_longlong_t)ds->ds_prev_snap_txg);
+ (void) printf("\t\tnext_snap_obj = %llu\n",
+ (u_longlong_t)ds->ds_next_snap_obj);
+ (void) printf("\t\tsnapnames_zapobj = %llu\n",
+ (u_longlong_t)ds->ds_snapnames_zapobj);
+ (void) printf("\t\tnum_children = %llu\n",
+ (u_longlong_t)ds->ds_num_children);
+ (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+ (void) printf("\t\tcreation_txg = %llu\n",
+ (u_longlong_t)ds->ds_creation_txg);
+ (void) printf("\t\tdeadlist_obj = %llu\n",
+ (u_longlong_t)ds->ds_deadlist_obj);
+ (void) printf("\t\tused_bytes = %s\n", used);
+ (void) printf("\t\tcompressed_bytes = %s\n", compressed);
+ (void) printf("\t\tuncompressed_bytes = %s\n", uncompressed);
+ (void) printf("\t\tunique = %s\n", unique);
+ (void) printf("\t\tfsid_guid = %llu\n",
+ (u_longlong_t)ds->ds_fsid_guid);
+ (void) printf("\t\tguid = %llu\n",
+ (u_longlong_t)ds->ds_guid);
+ (void) printf("\t\tflags = %llx\n",
+ (u_longlong_t)ds->ds_flags);
+ (void) printf("\t\tbp = %s\n", blkbuf);
+}
+
+static void
+dump_bplist(objset_t *mos, uint64_t object, char *name)
+{
+ bplist_t bpl = { 0 };
+ blkptr_t blk, *bp = &blk;
+ uint64_t itor = 0;
+ char bytes[6];
+ char comp[6];
+ char uncomp[6];
+
+ if (dump_opt['d'] < 3)
+ return;
+
+ VERIFY(0 == bplist_open(&bpl, mos, object));
+ if (bplist_empty(&bpl)) {
+ bplist_close(&bpl);
+ return;
+ }
+
+ nicenum(bpl.bpl_phys->bpl_bytes, bytes);
+ if (bpl.bpl_dbuf->db_size == sizeof (bplist_phys_t)) {
+ nicenum(bpl.bpl_phys->bpl_comp, comp);
+ nicenum(bpl.bpl_phys->bpl_uncomp, uncomp);
+ (void) printf("\n %s: %llu entries, %s (%s/%s comp)\n",
+ name, (u_longlong_t)bpl.bpl_phys->bpl_entries,
+ bytes, comp, uncomp);
+ } else {
+ (void) printf("\n %s: %llu entries, %s\n",
+ name, (u_longlong_t)bpl.bpl_phys->bpl_entries, bytes);
+ }
+
+ if (dump_opt['d'] < 5) {
+ bplist_close(&bpl);
+ return;
+ }
+
+ (void) printf("\n");
+
+ while (bplist_iterate(&bpl, &itor, bp) == 0) {
+ char blkbuf[BP_SPRINTF_LEN];
+
+ ASSERT(bp->blk_birth != 0);
+ sprintf_blkptr_compact(blkbuf, bp, dump_opt['d'] > 5 ? 1 : 0);
+ (void) printf("\tItem %3llu: %s\n",
+ (u_longlong_t)itor - 1, blkbuf);
+ }
+
+ bplist_close(&bpl);
+}
+
+/*ARGSUSED*/
+static void
+dump_znode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+ znode_phys_t *zp = data;
+ time_t z_crtime, z_atime, z_mtime, z_ctime;
+ char path[MAXPATHLEN * 2]; /* allow for xattr and failure prefix */
+ int error;
+
+ ASSERT(size >= sizeof (znode_phys_t));
+
+ error = zfs_obj_to_path(os, object, path, sizeof (path));
+ if (error != 0) {
+ (void) snprintf(path, sizeof (path), "\?\?\?<object#%llu>",
+ (u_longlong_t)object);
+ }
+
+ if (dump_opt['d'] < 3) {
+ (void) printf("\t%s\n", path);
+ return;
+ }
+
+ z_crtime = (time_t)zp->zp_crtime[0];
+ z_atime = (time_t)zp->zp_atime[0];
+ z_mtime = (time_t)zp->zp_mtime[0];
+ z_ctime = (time_t)zp->zp_ctime[0];
+
+ (void) printf("\tpath %s\n", path);
+ (void) printf("\tatime %s", ctime(&z_atime));
+ (void) printf("\tmtime %s", ctime(&z_mtime));
+ (void) printf("\tctime %s", ctime(&z_ctime));
+ (void) printf("\tcrtime %s", ctime(&z_crtime));
+ (void) printf("\tgen %llu\n", (u_longlong_t)zp->zp_gen);
+ (void) printf("\tmode %llo\n", (u_longlong_t)zp->zp_mode);
+ (void) printf("\tsize %llu\n", (u_longlong_t)zp->zp_size);
+ (void) printf("\tparent %llu\n", (u_longlong_t)zp->zp_parent);
+ (void) printf("\tlinks %llu\n", (u_longlong_t)zp->zp_links);
+ (void) printf("\txattr %llu\n", (u_longlong_t)zp->zp_xattr);
+ (void) printf("\trdev 0x%016llx\n", (u_longlong_t)zp->zp_rdev);
+}
+
+/*ARGSUSED*/
+static void
+dump_acl(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_dmu_objset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static object_viewer_t *object_viewer[DMU_OT_NUMTYPES] = {
+ 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 */
+ dump_zap, /* persistent error log */
+ dump_uint8, /* SPA history */
+ dump_uint64, /* SPA history offsets */
+ dump_zap, /* Pool properties */
+};
+
+static void
+dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
+{
+ dmu_buf_t *db = NULL;
+ dmu_object_info_t doi;
+ dnode_t *dn;
+ void *bonus = NULL;
+ size_t bsize = 0;
+ char iblk[6], dblk[6], lsize[6], asize[6], bonus_size[6], segsize[6];
+ char aux[50];
+ int error;
+
+ if (*print_header) {
+ (void) printf("\n Object lvl iblk dblk lsize"
+ " asize type\n");
+ *print_header = 0;
+ }
+
+ if (object == 0) {
+ dn = os->os->os_meta_dnode;
+ } else {
+ error = dmu_bonus_hold(os, object, FTAG, &db);
+ if (error)
+ fatal("dmu_bonus_hold(%llu) failed, errno %u",
+ object, error);
+ bonus = db->db_data;
+ bsize = db->db_size;
+ dn = ((dmu_buf_impl_t *)db)->db_dnode;
+ }
+ dmu_object_info_from_dnode(dn, &doi);
+
+ nicenum(doi.doi_metadata_block_size, iblk);
+ nicenum(doi.doi_data_block_size, dblk);
+ nicenum(doi.doi_data_block_size * (doi.doi_max_block_offset + 1),
+ lsize);
+ nicenum(doi.doi_physical_blks << 9, asize);
+ nicenum(doi.doi_bonus_size, bonus_size);
+
+ aux[0] = '\0';
+
+ if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6)
+ (void) snprintf(aux + strlen(aux), sizeof (aux), " (K=%s)",
+ zio_checksum_table[doi.doi_checksum].ci_name);
+
+ if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6)
+ (void) snprintf(aux + strlen(aux), sizeof (aux), " (Z=%s)",
+ zio_compress_table[doi.doi_compress].ci_name);
+
+ (void) printf("%10lld %3u %5s %5s %5s %5s %s%s\n",
+ (u_longlong_t)object, doi.doi_indirection, iblk, dblk, lsize,
+ asize, dmu_ot[doi.doi_type].ot_name, aux);
+
+ if (doi.doi_bonus_type != DMU_OT_NONE && verbosity > 3) {
+ (void) printf("%10s %3s %5s %5s %5s %5s %s\n",
+ "", "", "", "", bonus_size, "bonus",
+ dmu_ot[doi.doi_bonus_type].ot_name);
+ }
+
+ if (verbosity >= 4) {
+ object_viewer[doi.doi_bonus_type](os, object, bonus, bsize);
+ object_viewer[doi.doi_type](os, object, NULL, 0);
+ *print_header = 1;
+ }
+
+ if (verbosity >= 5)
+ dump_indirect(os, object, NULL, 0);
+
+ if (verbosity >= 5) {
+ /*
+ * Report the list of segments that comprise the object.
+ */
+ uint64_t start = 0;
+ uint64_t end;
+ uint64_t blkfill = 1;
+ int minlvl = 1;
+
+ if (dn->dn_type == DMU_OT_DNODE) {
+ minlvl = 0;
+ blkfill = DNODES_PER_BLOCK;
+ }
+
+ for (;;) {
+ error = dnode_next_offset(dn, B_FALSE, &start, minlvl,
+ blkfill, 0);
+ if (error)
+ break;
+ end = start;
+ error = dnode_next_offset(dn, B_TRUE, &end, minlvl,
+ blkfill, 0);
+ nicenum(end - start, segsize);
+ (void) printf("\t\tsegment [%016llx, %016llx)"
+ " size %5s\n", (u_longlong_t)start,
+ (u_longlong_t)end, segsize);
+ if (error)
+ break;
+ start = end;
+ }
+ }
+
+ if (db != NULL)
+ dmu_buf_rele(db, FTAG);
+}
+
+static char *objset_types[DMU_OST_NUMTYPES] = {
+ "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
+
+/*ARGSUSED*/
+static void
+dump_dir(objset_t *os)
+{
+ dmu_objset_stats_t dds;
+ uint64_t object, object_count;
+ uint64_t refdbytes, usedobjs, scratch;
+ char numbuf[8];
+ char blkbuf[BP_SPRINTF_LEN];
+ char osname[MAXNAMELEN];
+ char *type = "UNKNOWN";
+ int verbosity = dump_opt['d'];
+ int print_header = 1;
+ int i, error;
+
+ dmu_objset_fast_stat(os, &dds);
+
+ if (dds.dds_type < DMU_OST_NUMTYPES)
+ type = objset_types[dds.dds_type];
+
+ if (dds.dds_type == DMU_OST_META) {
+ dds.dds_creation_txg = TXG_INITIAL;
+ usedobjs = os->os->os_rootbp->blk_fill;
+ refdbytes =
+ os->os->os_spa->spa_dsl_pool->dp_mos_dir->dd_used_bytes;
+ } else {
+ dmu_objset_space(os, &refdbytes, &scratch, &usedobjs, &scratch);
+ }
+
+ ASSERT3U(usedobjs, ==, os->os->os_rootbp->blk_fill);
+
+ nicenum(refdbytes, numbuf);
+
+ if (verbosity >= 4) {
+ (void) strcpy(blkbuf, ", rootbp ");
+ sprintf_blkptr(blkbuf + strlen(blkbuf),
+ BP_SPRINTF_LEN - strlen(blkbuf), os->os->os_rootbp);
+ } else {
+ blkbuf[0] = '\0';
+ }
+
+ dmu_objset_name(os, osname);
+
+ (void) printf("Dataset %s [%s], ID %llu, cr_txg %llu, "
+ "%s, %llu objects%s\n",
+ osname, type, (u_longlong_t)dmu_objset_id(os),
+ (u_longlong_t)dds.dds_creation_txg,
+ numbuf, (u_longlong_t)usedobjs, blkbuf);
+
+ dump_intent_log(dmu_objset_zil(os));
+
+ if (dmu_objset_ds(os) != NULL)
+ dump_bplist(dmu_objset_pool(os)->dp_meta_objset,
+ dmu_objset_ds(os)->ds_phys->ds_deadlist_obj, "Deadlist");
+
+ if (verbosity < 2)
+ return;
+
+ if (zopt_objects != 0) {
+ for (i = 0; i < zopt_objects; i++)
+ dump_object(os, zopt_object[i], verbosity,
+ &print_header);
+ (void) printf("\n");
+ return;
+ }
+
+ dump_object(os, 0, verbosity, &print_header);
+ object_count = 1;
+
+ object = 0;
+ while ((error = dmu_object_next(os, &object, B_FALSE, 0)) == 0) {
+ dump_object(os, object, verbosity, &print_header);
+ object_count++;
+ }
+
+ ASSERT3U(object_count, ==, usedobjs);
+
+ (void) printf("\n");
+
+ if (error != ESRCH)
+ fatal("dmu_object_next() = %d", error);
+}
+
+static void
+dump_uberblock(uberblock_t *ub)
+{
+ time_t timestamp = ub->ub_timestamp;
+
+ (void) printf("Uberblock\n\n");
+ (void) printf("\tmagic = %016llx\n", (u_longlong_t)ub->ub_magic);
+ (void) printf("\tversion = %llu\n", (u_longlong_t)ub->ub_version);
+ (void) printf("\ttxg = %llu\n", (u_longlong_t)ub->ub_txg);
+ (void) printf("\tguid_sum = %llu\n", (u_longlong_t)ub->ub_guid_sum);
+ (void) printf("\ttimestamp = %llu UTC = %s",
+ (u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
+ if (dump_opt['u'] >= 3) {
+ char blkbuf[BP_SPRINTF_LEN];
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, &ub->ub_rootbp);
+ (void) printf("\trootbp = %s\n", blkbuf);
+ }
+ (void) printf("\n");
+}
+
+static void
+dump_config(const char *pool)
+{
+ spa_t *spa = NULL;
+
+ mutex_enter(&spa_namespace_lock);
+ while ((spa = spa_next(spa)) != NULL) {
+ if (pool == NULL)
+ (void) printf("%s\n", spa_name(spa));
+ if (pool == NULL || strcmp(pool, spa_name(spa)) == 0)
+ dump_nvlist(spa->spa_config, 4);
+ }
+ mutex_exit(&spa_namespace_lock);
+}
+
+static void
+dump_label(const char *dev)
+{
+ int fd;
+ vdev_label_t label;
+ char *buf = label.vl_vdev_phys.vp_nvlist;
+ size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist);
+ struct stat64 statbuf;
+ uint64_t psize;
+ int l;
+
+ if ((fd = open64(dev, O_RDONLY)) < 0) {
+ (void) printf("cannot open '%s': %s\n", dev, strerror(errno));
+ exit(1);
+ }
+
+ if (fstat64(fd, &statbuf) != 0) {
+ (void) printf("failed to stat '%s': %s\n", dev,
+ strerror(errno));
+ exit(1);
+ }
+
+ psize = statbuf.st_size;
+ psize = P2ALIGN(psize, (uint64_t)sizeof (vdev_label_t));
+
+ for (l = 0; l < VDEV_LABELS; l++) {
+
+ nvlist_t *config = NULL;
+
+ (void) printf("--------------------------------------------\n");
+ (void) printf("LABEL %d\n", l);
+ (void) printf("--------------------------------------------\n");
+
+ if (pread64(fd, &label, sizeof (label),
+ vdev_label_offset(psize, l, 0)) != sizeof (label)) {
+ (void) printf("failed to read label %d\n", l);
+ continue;
+ }
+
+ if (nvlist_unpack(buf, buflen, &config, 0) != 0) {
+ (void) printf("failed to unpack label %d\n", l);
+ continue;
+ }
+ dump_nvlist(config, 4);
+ nvlist_free(config);
+ }
+}
+
+/*ARGSUSED*/
+static int
+dump_one_dir(char *dsname, void *arg)
+{
+ int error;
+ objset_t *os;
+
+ error = dmu_objset_open(dsname, DMU_OST_ANY,
+ DS_MODE_STANDARD | DS_MODE_READONLY, &os);
+ if (error) {
+ (void) printf("Could not open %s\n", dsname);
+ return (0);
+ }
+ dump_dir(os);
+ dmu_objset_close(os);
+ return (0);
+}
+
+static void
+zdb_space_map_load(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ vdev_t *vd;
+ int c, m, error;
+
+ for (c = 0; c < rvd->vdev_children; c++) {
+ vd = rvd->vdev_child[c];
+ for (m = 0; m < vd->vdev_ms_count; m++) {
+ metaslab_t *msp = vd->vdev_ms[m];
+ mutex_enter(&msp->ms_lock);
+ error = space_map_load(&msp->ms_allocmap[0], NULL,
+ SM_ALLOC, &msp->ms_smo, spa->spa_meta_objset);
+ mutex_exit(&msp->ms_lock);
+ if (error)
+ fatal("%s bad space map #%d, error %d",
+ spa->spa_name, c, error);
+ }
+ }
+}
+
+static int
+zdb_space_map_claim(spa_t *spa, blkptr_t *bp, zbookmark_t *zb)
+{
+ dva_t *dva = bp->blk_dva;
+ vdev_t *vd;
+ metaslab_t *msp;
+ space_map_t *allocmap, *freemap;
+ int error;
+ int d;
+ blkptr_t blk = *bp;
+
+ for (d = 0; d < BP_GET_NDVAS(bp); d++) {
+ uint64_t vdev = DVA_GET_VDEV(&dva[d]);
+ uint64_t offset = DVA_GET_OFFSET(&dva[d]);
+ uint64_t size = DVA_GET_ASIZE(&dva[d]);
+
+ if ((vd = vdev_lookup_top(spa, vdev)) == NULL)
+ return (ENXIO);
+
+ if ((offset >> vd->vdev_ms_shift) >= vd->vdev_ms_count)
+ return (ENXIO);
+
+ msp = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+ allocmap = &msp->ms_allocmap[0];
+ freemap = &msp->ms_freemap[0];
+
+ /* Prepare our copy of the bp in case we need to read GBHs */
+ if (DVA_GET_GANG(&dva[d])) {
+ size = vdev_psize_to_asize(vd, SPA_GANGBLOCKSIZE);
+ DVA_SET_ASIZE(&blk.blk_dva[d], size);
+ DVA_SET_GANG(&blk.blk_dva[d], 0);
+ }
+
+ mutex_enter(&msp->ms_lock);
+ if (space_map_contains(freemap, offset, size)) {
+ mutex_exit(&msp->ms_lock);
+ return (EAGAIN); /* allocated more than once */
+ }
+
+ if (!space_map_contains(allocmap, offset, size)) {
+ mutex_exit(&msp->ms_lock);
+ return (ESTALE); /* not allocated at all */
+ }
+
+ space_map_remove(allocmap, offset, size);
+ space_map_add(freemap, offset, size);
+
+ mutex_exit(&msp->ms_lock);
+ }
+
+ if (BP_IS_GANG(bp)) {
+ zio_gbh_phys_t gbh;
+ int g;
+
+ /* LINTED - compile time assert */
+ ASSERT(sizeof (zio_gbh_phys_t) == SPA_GANGBLOCKSIZE);
+
+ BP_SET_CHECKSUM(&blk, ZIO_CHECKSUM_GANG_HEADER);
+ BP_SET_PSIZE(&blk, SPA_GANGBLOCKSIZE);
+ BP_SET_LSIZE(&blk, SPA_GANGBLOCKSIZE);
+ BP_SET_COMPRESS(&blk, ZIO_COMPRESS_OFF);
+ error = zio_wait(zio_read(NULL, spa, &blk, &gbh,
+ SPA_GANGBLOCKSIZE, NULL, NULL, ZIO_PRIORITY_SYNC_READ,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_CONFIG_HELD, zb));
+ if (error)
+ return (error);
+ if (BP_SHOULD_BYTESWAP(&blk))
+ byteswap_uint64_array(&gbh, SPA_GANGBLOCKSIZE);
+ for (g = 0; g < SPA_GBH_NBLKPTRS; g++) {
+ if (BP_IS_HOLE(&gbh.zg_blkptr[g]))
+ break;
+ error = zdb_space_map_claim(spa, &gbh.zg_blkptr[g], zb);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static void
+zdb_leak(space_map_t *sm, uint64_t start, uint64_t size)
+{
+ metaslab_t *msp;
+
+ /* LINTED */
+ msp = (metaslab_t *)((char *)sm - offsetof(metaslab_t, ms_allocmap[0]));
+
+ (void) printf("leaked space: vdev %llu, offset 0x%llx, size %llu\n",
+ (u_longlong_t)msp->ms_group->mg_vd->vdev_id,
+ (u_longlong_t)start,
+ (u_longlong_t)size);
+}
+
+static void
+zdb_space_map_unload(spa_t *spa)
+{
+ vdev_t *rvd = spa->spa_root_vdev;
+ vdev_t *vd;
+ int c, m;
+
+ for (c = 0; c < rvd->vdev_children; c++) {
+ vd = rvd->vdev_child[c];
+ for (m = 0; m < vd->vdev_ms_count; m++) {
+ metaslab_t *msp = vd->vdev_ms[m];
+ mutex_enter(&msp->ms_lock);
+ space_map_vacate(&msp->ms_allocmap[0], zdb_leak,
+ &msp->ms_allocmap[0]);
+ space_map_unload(&msp->ms_allocmap[0]);
+ space_map_vacate(&msp->ms_freemap[0], NULL, NULL);
+ mutex_exit(&msp->ms_lock);
+ }
+ }
+}
+
+static void
+zdb_refresh_ubsync(spa_t *spa)
+{
+ uberblock_t ub = { 0 };
+ vdev_t *rvd = spa->spa_root_vdev;
+ zio_t *zio;
+
+ /*
+ * Reload the uberblock.
+ */
+ zio = zio_root(spa, NULL, NULL,
+ ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE);
+ vdev_uberblock_load(zio, rvd, &ub);
+ (void) zio_wait(zio);
+
+ if (ub.ub_txg != 0)
+ spa->spa_ubsync = ub;
+}
+
+/*
+ * 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 {
+ uint64_t zb_asize;
+ uint64_t zb_lsize;
+ uint64_t zb_psize;
+ uint64_t zb_count;
+} zdb_blkstats_t;
+
+#define DMU_OT_DEFERRED DMU_OT_NONE
+#define DMU_OT_TOTAL DMU_OT_NUMTYPES
+
+#define ZB_TOTAL ZB_MAXLEVEL
+
+typedef struct zdb_cb {
+ zdb_blkstats_t zcb_type[ZB_TOTAL + 1][DMU_OT_TOTAL + 1];
+ uint64_t zcb_errors[256];
+ traverse_blk_cache_t *zcb_cache;
+ int zcb_readfails;
+ int zcb_haderrors;
+} zdb_cb_t;
+
+static void
+zdb_count_block(spa_t *spa, zdb_cb_t *zcb, blkptr_t *bp, int type)
+{
+ int i, error;
+
+ for (i = 0; i < 4; i++) {
+ int l = (i < 2) ? BP_GET_LEVEL(bp) : ZB_TOTAL;
+ int t = (i & 1) ? type : DMU_OT_TOTAL;
+ zdb_blkstats_t *zb = &zcb->zcb_type[l][t];
+
+ zb->zb_asize += BP_GET_ASIZE(bp);
+ zb->zb_lsize += BP_GET_LSIZE(bp);
+ zb->zb_psize += BP_GET_PSIZE(bp);
+ zb->zb_count++;
+ }
+
+ if (dump_opt['L'])
+ return;
+
+ error = zdb_space_map_claim(spa, bp, &zcb->zcb_cache->bc_bookmark);
+
+ if (error == 0)
+ return;
+
+ if (error == EAGAIN)
+ (void) fatal("double-allocation, bp=%p", bp);
+
+ if (error == ESTALE)
+ (void) fatal("reference to freed block, bp=%p", bp);
+
+ (void) fatal("fatal error %d in bp %p", error, bp);
+}
+
+static int
+zdb_blkptr_cb(traverse_blk_cache_t *bc, spa_t *spa, void *arg)
+{
+ zbookmark_t *zb = &bc->bc_bookmark;
+ zdb_cb_t *zcb = arg;
+ blkptr_t *bp = &bc->bc_blkptr;
+ dmu_object_type_t type = BP_GET_TYPE(bp);
+ char blkbuf[BP_SPRINTF_LEN];
+ int error = 0;
+
+ if (bc->bc_errno) {
+ if (zcb->zcb_readfails++ < 10 && dump_opt['L']) {
+ zdb_refresh_ubsync(spa);
+ error = EAGAIN;
+ } else {
+ zcb->zcb_haderrors = 1;
+ zcb->zcb_errors[bc->bc_errno]++;
+ error = ERESTART;
+ }
+
+ if (dump_opt['b'] >= 3 || (dump_opt['b'] >= 2 && bc->bc_errno))
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
+ else
+ blkbuf[0] = '\0';
+
+ (void) printf("zdb_blkptr_cb: Got error %d reading "
+ "<%llu, %llu, %lld, %llx> %s -- %s\n",
+ bc->bc_errno,
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (u_longlong_t)zb->zb_level,
+ (u_longlong_t)zb->zb_blkid,
+ blkbuf,
+ error == EAGAIN ? "retrying" : "skipping");
+
+ return (error);
+ }
+
+ zcb->zcb_readfails = 0;
+
+ ASSERT(!BP_IS_HOLE(bp));
+
+ if (dump_opt['b'] >= 4) {
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
+ (void) printf("objset %llu object %llu offset 0x%llx %s\n",
+ (u_longlong_t)zb->zb_objset,
+ (u_longlong_t)zb->zb_object,
+ (u_longlong_t)blkid2offset(bc->bc_dnode,
+ zb->zb_level, zb->zb_blkid),
+ blkbuf);
+ }
+
+ zdb_count_block(spa, zcb, bp, type);
+
+ return (0);
+}
+
+static int
+dump_block_stats(spa_t *spa)
+{
+ traverse_handle_t *th;
+ zdb_cb_t zcb = { 0 };
+ traverse_blk_cache_t dummy_cache = { 0 };
+ zdb_blkstats_t *zb, *tzb;
+ uint64_t alloc, space;
+ int leaks = 0;
+ int advance = zdb_advance;
+ int flags;
+ int e;
+
+ zcb.zcb_cache = &dummy_cache;
+
+ if (dump_opt['c'])
+ advance |= ADVANCE_DATA;
+
+ advance |= ADVANCE_PRUNE | ADVANCE_ZIL;
+
+ (void) printf("\nTraversing all blocks to %sverify"
+ " nothing leaked ...\n",
+ dump_opt['c'] ? "verify checksums and " : "");
+
+ /*
+ * 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'])
+ zdb_space_map_load(spa);
+
+ /*
+ * If there's a deferred-free bplist, process that first.
+ */
+ if (spa->spa_sync_bplist_obj != 0) {
+ bplist_t *bpl = &spa->spa_sync_bplist;
+ blkptr_t blk;
+ uint64_t itor = 0;
+
+ VERIFY(0 == bplist_open(bpl, spa->spa_meta_objset,
+ spa->spa_sync_bplist_obj));
+
+ while (bplist_iterate(bpl, &itor, &blk) == 0) {
+ if (dump_opt['b'] >= 4) {
+ char blkbuf[BP_SPRINTF_LEN];
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, &blk);
+ (void) printf("[%s] %s\n",
+ "deferred free", blkbuf);
+ }
+ zdb_count_block(spa, &zcb, &blk, DMU_OT_DEFERRED);
+ }
+
+ bplist_close(bpl);
+ }
+
+ /*
+ * Now traverse the pool. If we're reading all data to verify
+ * checksums, do a scrubbing read so that we validate all copies.
+ */
+ flags = ZIO_FLAG_CANFAIL;
+ if (advance & ADVANCE_DATA)
+ flags |= ZIO_FLAG_SCRUB;
+ th = traverse_init(spa, zdb_blkptr_cb, &zcb, advance, flags);
+ th->th_noread = zdb_noread;
+
+ traverse_add_pool(th, 0, spa_first_txg(spa) + TXG_CONCURRENT_STATES);
+
+ while (traverse_more(th) == EAGAIN)
+ continue;
+
+ traverse_fini(th);
+
+ if (zcb.zcb_haderrors) {
+ (void) printf("\nError counts:\n\n");
+ (void) printf("\t%5s %s\n", "errno", "count");
+ for (e = 0; e < 256; e++) {
+ if (zcb.zcb_errors[e] != 0) {
+ (void) printf("\t%5d %llu\n",
+ e, (u_longlong_t)zcb.zcb_errors[e]);
+ }
+ }
+ }
+
+ /*
+ * Report any leaked segments.
+ */
+ if (!dump_opt['L'])
+ zdb_space_map_unload(spa);
+
+ if (dump_opt['L'])
+ (void) printf("\n\n *** Live pool traversal; "
+ "block counts are only approximate ***\n\n");
+
+ alloc = spa_get_alloc(spa);
+ space = spa_get_space(spa);
+
+ tzb = &zcb.zcb_type[ZB_TOTAL][DMU_OT_TOTAL];
+
+ if (tzb->zb_asize == alloc) {
+ (void) printf("\n\tNo leaks (block sum matches space"
+ " maps exactly)\n");
+ } else {
+ (void) printf("block traversal size %llu != alloc %llu "
+ "(leaked %lld)\n",
+ (u_longlong_t)tzb->zb_asize,
+ (u_longlong_t)alloc,
+ (u_longlong_t)(alloc - tzb->zb_asize));
+ leaks = 1;
+ }
+
+ if (tzb->zb_count == 0)
+ return (2);
+
+ (void) printf("\n");
+ (void) printf("\tbp count: %10llu\n",
+ (u_longlong_t)tzb->zb_count);
+ (void) printf("\tbp logical: %10llu\t avg: %6llu\n",
+ (u_longlong_t)tzb->zb_lsize,
+ (u_longlong_t)(tzb->zb_lsize / tzb->zb_count));
+ (void) printf("\tbp physical: %10llu\t avg:"
+ " %6llu\tcompression: %6.2f\n",
+ (u_longlong_t)tzb->zb_psize,
+ (u_longlong_t)(tzb->zb_psize / tzb->zb_count),
+ (double)tzb->zb_lsize / tzb->zb_psize);
+ (void) printf("\tbp allocated: %10llu\t avg:"
+ " %6llu\tcompression: %6.2f\n",
+ (u_longlong_t)tzb->zb_asize,
+ (u_longlong_t)(tzb->zb_asize / tzb->zb_count),
+ (double)tzb->zb_lsize / tzb->zb_asize);
+ (void) printf("\tSPA allocated: %10llu\tused: %5.2f%%\n",
+ (u_longlong_t)alloc, 100.0 * alloc / space);
+
+ if (dump_opt['b'] >= 2) {
+ 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 csize[6], lsize[6], psize[6], asize[6], avg[6];
+ char *typename;
+
+ typename = t == DMU_OT_DEFERRED ? "deferred free" :
+ t == DMU_OT_TOTAL ? "Total" : dmu_ot[t].ot_name;
+
+ if (zcb.zcb_type[ZB_TOTAL][t].zb_asize == 0) {
+ (void) printf("%6s\t%5s\t%5s\t%5s"
+ "\t%5s\t%5s\t%6s\t%s\n",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ "-",
+ typename);
+ continue;
+ }
+
+ for (l = ZB_TOTAL - 1; l >= -1; l--) {
+ level = (l == -1 ? ZB_TOTAL : l);
+ zb = &zcb.zcb_type[level][t];
+
+ if (zb->zb_asize == 0)
+ continue;
+
+ if (dump_opt['b'] < 3 && level != ZB_TOTAL)
+ continue;
+
+ if (level == 0 && zb->zb_asize ==
+ zcb.zcb_type[ZB_TOTAL][t].zb_asize)
+ continue;
+
+ nicenum(zb->zb_count, csize);
+ nicenum(zb->zb_lsize, lsize);
+ nicenum(zb->zb_psize, psize);
+ nicenum(zb->zb_asize, asize);
+ nicenum(zb->zb_asize / zb->zb_count, avg);
+
+ (void) printf("%6s\t%5s\t%5s\t%5s\t%5s"
+ "\t%5.2f\t%6.2f\t",
+ csize, lsize, psize, asize, avg,
+ (double)zb->zb_lsize / zb->zb_psize,
+ 100.0 * zb->zb_asize / tzb->zb_asize);
+
+ if (level == ZB_TOTAL)
+ (void) printf("%s\n", typename);
+ else
+ (void) printf(" L%d %s\n",
+ level, typename);
+ }
+ }
+ }
+
+ (void) printf("\n");
+
+ if (leaks)
+ return (2);
+
+ if (zcb.zcb_haderrors)
+ return (3);
+
+ return (0);
+}
+
+static void
+dump_zpool(spa_t *spa)
+{
+ dsl_pool_t *dp = spa_get_dsl(spa);
+ int rc = 0;
+
+ if (dump_opt['u'])
+ dump_uberblock(&spa->spa_uberblock);
+
+ if (dump_opt['d'] || dump_opt['i']) {
+ dump_dir(dp->dp_meta_objset);
+ if (dump_opt['d'] >= 3) {
+ dump_bplist(dp->dp_meta_objset,
+ spa->spa_sync_bplist_obj, "Deferred frees");
+ dump_dtl(spa->spa_root_vdev, 0);
+ dump_metaslabs(spa);
+ }
+ (void) dmu_objset_find(spa->spa_name, dump_one_dir, NULL,
+ DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+ }
+
+ if (dump_opt['b'] || dump_opt['c'])
+ rc = dump_block_stats(spa);
+
+ if (dump_opt['s'])
+ show_pool_stats(spa);
+
+ if (rc != 0)
+ exit(rc);
+}
+
+#define ZDB_FLAG_CHECKSUM 0x0001
+#define ZDB_FLAG_DECOMPRESS 0x0002
+#define ZDB_FLAG_BSWAP 0x0004
+#define ZDB_FLAG_GBH 0x0008
+#define ZDB_FLAG_INDIRECT 0x0010
+#define ZDB_FLAG_PHYS 0x0020
+#define ZDB_FLAG_RAW 0x0040
+#define ZDB_FLAG_PRINT_BLKPTR 0x0080
+
+int flagbits[256];
+
+static void
+zdb_print_blkptr(blkptr_t *bp, int flags)
+{
+ dva_t *dva = bp->blk_dva;
+ int d;
+
+ if (flags & ZDB_FLAG_BSWAP)
+ byteswap_uint64_array((void *)bp, sizeof (blkptr_t));
+ /*
+ * Super-ick warning: This code is also duplicated in
+ * cmd/mdb/common/modules/zfs/zfs.c . Yeah, I hate code
+ * replication, too.
+ */
+ for (d = 0; d < BP_GET_NDVAS(bp); d++) {
+ (void) printf("\tDVA[%d]: vdev_id %lld / %llx\n", d,
+ (longlong_t)DVA_GET_VDEV(&dva[d]),
+ (longlong_t)DVA_GET_OFFSET(&dva[d]));
+ (void) printf("\tDVA[%d]: GANG: %-5s GRID: %04llx\t"
+ "ASIZE: %llx\n", d,
+ DVA_GET_GANG(&dva[d]) ? "TRUE" : "FALSE",
+ (longlong_t)DVA_GET_GRID(&dva[d]),
+ (longlong_t)DVA_GET_ASIZE(&dva[d]));
+ (void) printf("\tDVA[%d]: :%llu:%llx:%llx:%s%s%s%s\n", d,
+ (u_longlong_t)DVA_GET_VDEV(&dva[d]),
+ (longlong_t)DVA_GET_OFFSET(&dva[d]),
+ (longlong_t)BP_GET_PSIZE(bp),
+ BP_SHOULD_BYTESWAP(bp) ? "e" : "",
+ !DVA_GET_GANG(&dva[d]) && BP_GET_LEVEL(bp) != 0 ?
+ "d" : "",
+ DVA_GET_GANG(&dva[d]) ? "g" : "",
+ BP_GET_COMPRESS(bp) != 0 ? "d" : "");
+ }
+ (void) printf("\tLSIZE: %-16llx\t\tPSIZE: %llx\n",
+ (longlong_t)BP_GET_LSIZE(bp), (longlong_t)BP_GET_PSIZE(bp));
+ (void) printf("\tENDIAN: %6s\t\t\t\t\tTYPE: %s\n",
+ BP_GET_BYTEORDER(bp) ? "LITTLE" : "BIG",
+ dmu_ot[BP_GET_TYPE(bp)].ot_name);
+ (void) printf("\tBIRTH: %-16llx LEVEL: %-2llu\tFILL: %llx\n",
+ (u_longlong_t)bp->blk_birth, (u_longlong_t)BP_GET_LEVEL(bp),
+ (u_longlong_t)bp->blk_fill);
+ (void) printf("\tCKFUNC: %-16s\t\tCOMP: %s\n",
+ zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_name,
+ zio_compress_table[BP_GET_COMPRESS(bp)].ci_name);
+ (void) printf("\tCKSUM: %llx:%llx:%llx:%llx\n",
+ (u_longlong_t)bp->blk_cksum.zc_word[0],
+ (u_longlong_t)bp->blk_cksum.zc_word[1],
+ (u_longlong_t)bp->blk_cksum.zc_word[2],
+ (u_longlong_t)bp->blk_cksum.zc_word[3]);
+}
+
+static void
+zdb_dump_indirect(blkptr_t *bp, int nbps, int flags)
+{
+ int i;
+
+ for (i = 0; i < nbps; i++)
+ zdb_print_blkptr(&bp[i], flags);
+}
+
+static void
+zdb_dump_gbh(void *buf, int flags)
+{
+ zdb_dump_indirect((blkptr_t *)buf, SPA_GBH_NBLKPTRS, flags);
+}
+
+static void
+zdb_dump_block_raw(void *buf, uint64_t size, int flags)
+{
+ if (flags & ZDB_FLAG_BSWAP)
+ byteswap_uint64_array(buf, size);
+ (void) write(2, buf, size);
+}
+
+static void
+zdb_dump_block(char *label, void *buf, uint64_t size, int flags)
+{
+ uint64_t *d = (uint64_t *)buf;
+ int nwords = size / sizeof (uint64_t);
+ int do_bswap = !!(flags & ZDB_FLAG_BSWAP);
+ int i, j;
+ char *hdr, *c;
+
+
+ if (do_bswap)
+ hdr = " 7 6 5 4 3 2 1 0 f e d c b a 9 8";
+ else
+ hdr = " 0 1 2 3 4 5 6 7 8 9 a b c d e f";
+
+ (void) printf("\n%s\n%6s %s 0123456789abcdef\n", label, "", hdr);
+
+ for (i = 0; i < nwords; i += 2) {
+ (void) printf("%06llx: %016llx %016llx ",
+ (u_longlong_t)(i * sizeof (uint64_t)),
+ (u_longlong_t)(do_bswap ? BSWAP_64(d[i]) : d[i]),
+ (u_longlong_t)(do_bswap ? BSWAP_64(d[i + 1]) : d[i + 1]));
+
+ c = (char *)&d[i];
+ for (j = 0; j < 2 * sizeof (uint64_t); j++)
+ (void) printf("%c", isprint(c[j]) ? c[j] : '.');
+ (void) printf("\n");
+ }
+}
+
+/*
+ * There are two acceptable formats:
+ * leaf_name - For example: c1t0d0 or /tmp/ztest.0a
+ * child[.child]* - For example: 0.1.1
+ *
+ * The second form can be used to specify arbitrary vdevs anywhere
+ * in the heirarchy. For example, in a pool with a mirror of
+ * RAID-Zs, you can specify either RAID-Z vdev with 0.0 or 0.1 .
+ */
+static vdev_t *
+zdb_vdev_lookup(vdev_t *vdev, char *path)
+{
+ char *s, *p, *q;
+ int i;
+
+ if (vdev == NULL)
+ return (NULL);
+
+ /* First, assume the x.x.x.x format */
+ i = (int)strtoul(path, &s, 10);
+ if (s == path || (s && *s != '.' && *s != '\0'))
+ goto name;
+ if (i < 0 || i >= vdev->vdev_children)
+ return (NULL);
+
+ vdev = vdev->vdev_child[i];
+ if (*s == '\0')
+ return (vdev);
+ return (zdb_vdev_lookup(vdev, s+1));
+
+name:
+ for (i = 0; i < vdev->vdev_children; i++) {
+ vdev_t *vc = vdev->vdev_child[i];
+
+ if (vc->vdev_path == NULL) {
+ vc = zdb_vdev_lookup(vc, path);
+ if (vc == NULL)
+ continue;
+ else
+ return (vc);
+ }
+
+ p = strrchr(vc->vdev_path, '/');
+ p = p ? p + 1 : vc->vdev_path;
+ q = &vc->vdev_path[strlen(vc->vdev_path) - 2];
+
+ if (strcmp(vc->vdev_path, path) == 0)
+ return (vc);
+ if (strcmp(p, path) == 0)
+ return (vc);
+ if (strcmp(q, "s0") == 0 && strncmp(p, path, q - p) == 0)
+ return (vc);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Read a block from a pool and print it out. The syntax of the
+ * block descriptor is:
+ *
+ * pool:vdev_specifier:offset:size[:flags]
+ *
+ * pool - The name of the pool you wish to read from
+ * vdev_specifier - Which vdev (see comment for zdb_vdev_lookup)
+ * offset - offset, in hex, in bytes
+ * size - Amount of data to read, in hex, in bytes
+ * flags - A string of characters specifying options
+ * b: Decode a blkptr at given offset within block
+ * *c: Calculate and display checksums
+ * *d: Decompress data before dumping
+ * e: Byteswap data before dumping
+ * *g: Display data as a gang block header
+ * *i: Display as an indirect block
+ * p: Do I/O to physical offset
+ * r: Dump raw data to stdout
+ *
+ * * = not yet implemented
+ */
+static void
+zdb_read_block(char *thing, spa_t **spap)
+{
+ spa_t *spa = *spap;
+ int flags = 0;
+ uint64_t offset = 0, size = 0, blkptr_offset = 0;
+ zio_t *zio;
+ vdev_t *vd;
+ void *buf;
+ char *s, *p, *dup, *spa_name, *vdev, *flagstr;
+ int i, error, zio_flags;
+
+ dup = strdup(thing);
+ s = strtok(dup, ":");
+ spa_name = s ? s : "";
+ s = strtok(NULL, ":");
+ vdev = s ? s : "";
+ s = strtok(NULL, ":");
+ offset = strtoull(s ? s : "", NULL, 16);
+ s = strtok(NULL, ":");
+ size = strtoull(s ? s : "", NULL, 16);
+ s = strtok(NULL, ":");
+ flagstr = s ? s : "";
+
+ s = NULL;
+ if (size == 0)
+ s = "size must not be zero";
+ if (!IS_P2ALIGNED(size, DEV_BSIZE))
+ s = "size must be a multiple of sector size";
+ if (!IS_P2ALIGNED(offset, DEV_BSIZE))
+ s = "offset must be a multiple of sector size";
+ if (s) {
+ (void) printf("Invalid block specifier: %s - %s\n", thing, s);
+ free(dup);
+ return;
+ }
+
+ for (s = strtok(flagstr, ":"); s; s = strtok(NULL, ":")) {
+ for (i = 0; flagstr[i]; i++) {
+ int bit = flagbits[(uchar_t)flagstr[i]];
+
+ if (bit == 0) {
+ (void) printf("***Invalid flag: %c\n",
+ flagstr[i]);
+ continue;
+ }
+ flags |= bit;
+
+ /* If it's not something with an argument, keep going */
+ if ((bit & (ZDB_FLAG_CHECKSUM | ZDB_FLAG_DECOMPRESS |
+ ZDB_FLAG_PRINT_BLKPTR)) == 0)
+ continue;
+
+ p = &flagstr[i + 1];
+ if (bit == ZDB_FLAG_PRINT_BLKPTR)
+ blkptr_offset = strtoull(p, &p, 16);
+ if (*p != ':' && *p != '\0') {
+ (void) printf("***Invalid flag arg: '%s'\n", s);
+ free(dup);
+ return;
+ }
+ }
+ }
+
+ if (spa == NULL || spa->spa_name == NULL ||
+ strcmp(spa->spa_name, spa_name)) {
+ if (spa && spa->spa_name)
+ spa_close(spa, (void *)zdb_read_block);
+ error = spa_open(spa_name, spap, (void *)zdb_read_block);
+ if (error)
+ fatal("Failed to open pool '%s': errno = %d\n",
+ spa_name, error);
+ spa = *spap;
+ }
+
+ vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
+ if (vd == NULL) {
+ (void) printf("***Invalid vdev: %s\n", vdev);
+ free(dup);
+ return;
+ } else {
+ if (vd->vdev_path)
+ (void) printf("Found vdev: %s\n", vd->vdev_path);
+ else
+ (void) printf("Found vdev type: %s\n",
+ vd->vdev_ops->vdev_op_type);
+ }
+
+ buf = umem_alloc(size, UMEM_NOFAIL);
+
+ zio_flags = ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE |
+ ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY | ZIO_FLAG_NOBOOKMARK;
+
+ if (flags & ZDB_FLAG_PHYS)
+ zio_flags |= ZIO_FLAG_PHYSICAL;
+
+ zio = zio_root(spa, NULL, NULL, 0);
+ /* XXX todo - cons up a BP so RAID-Z will be happy */
+ zio_nowait(zio_vdev_child_io(zio, NULL, vd, offset, buf, size,
+ ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ, zio_flags, NULL, NULL));
+ error = zio_wait(zio);
+
+ if (error) {
+ (void) printf("Read of %s failed, error: %d\n", thing, error);
+ goto out;
+ }
+
+ if (flags & ZDB_FLAG_PRINT_BLKPTR)
+ zdb_print_blkptr((blkptr_t *)(void *)
+ ((uintptr_t)buf + (uintptr_t)blkptr_offset), flags);
+ else if (flags & ZDB_FLAG_RAW)
+ zdb_dump_block_raw(buf, size, flags);
+ else if (flags & ZDB_FLAG_INDIRECT)
+ zdb_dump_indirect((blkptr_t *)buf, size / sizeof (blkptr_t),
+ flags);
+ else if (flags & ZDB_FLAG_GBH)
+ zdb_dump_gbh(buf, flags);
+ else
+ zdb_dump_block(thing, buf, size, flags);
+
+out:
+ umem_free(buf, size);
+ free(dup);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i, c;
+ struct rlimit rl = { 1024, 1024 };
+ spa_t *spa;
+ objset_t *os = NULL;
+ char *endstr;
+ int dump_all = 1;
+ int verbose = 0;
+ int error;
+ int flag, set;
+
+ (void) setrlimit(RLIMIT_NOFILE, &rl);
+ (void) enable_extended_FILE_stdio(-1, -1);
+
+ dprintf_setup(&argc, argv);
+
+ while ((c = getopt(argc, argv, "udibcsvCLO:B:UlR")) != -1) {
+ switch (c) {
+ case 'u':
+ case 'd':
+ case 'i':
+ case 'b':
+ case 'c':
+ case 's':
+ case 'C':
+ case 'l':
+ case 'R':
+ dump_opt[c]++;
+ dump_all = 0;
+ break;
+ case 'L':
+ dump_opt[c]++;
+ break;
+ case 'O':
+ endstr = optarg;
+ if (endstr[0] == '!') {
+ endstr++;
+ set = 0;
+ } else {
+ set = 1;
+ }
+ if (strcmp(endstr, "post") == 0) {
+ flag = ADVANCE_PRE;
+ set = !set;
+ } else if (strcmp(endstr, "pre") == 0) {
+ flag = ADVANCE_PRE;
+ } else if (strcmp(endstr, "prune") == 0) {
+ flag = ADVANCE_PRUNE;
+ } else if (strcmp(endstr, "data") == 0) {
+ flag = ADVANCE_DATA;
+ } else if (strcmp(endstr, "holes") == 0) {
+ flag = ADVANCE_HOLES;
+ } else {
+ usage();
+ }
+ if (set)
+ zdb_advance |= flag;
+ else
+ zdb_advance &= ~flag;
+ break;
+ case 'B':
+ endstr = optarg - 1;
+ zdb_noread.zb_objset = strtoull(endstr + 1, &endstr, 0);
+ zdb_noread.zb_object = strtoull(endstr + 1, &endstr, 0);
+ zdb_noread.zb_level = strtol(endstr + 1, &endstr, 0);
+ zdb_noread.zb_blkid = strtoull(endstr + 1, &endstr, 16);
+ (void) printf("simulating bad block "
+ "<%llu, %llu, %lld, %llx>\n",
+ (u_longlong_t)zdb_noread.zb_objset,
+ (u_longlong_t)zdb_noread.zb_object,
+ (u_longlong_t)zdb_noread.zb_level,
+ (u_longlong_t)zdb_noread.zb_blkid);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'U':
+ spa_config_dir = "/tmp";
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ kernel_init(FREAD);
+
+ /*
+ * Disable vdev caching. If we don't do this, live pool traversal
+ * won't make progress because it will never see disk updates.
+ */
+ zfs_vdev_cache_size = 0;
+
+ for (c = 0; c < 256; c++) {
+ if (dump_all && c != 'L' && c != 'l' && c != 'R')
+ dump_opt[c] = 1;
+ if (dump_opt[c])
+ dump_opt[c] += verbose;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ if (dump_opt['C']) {
+ dump_config(NULL);
+ return (0);
+ }
+ usage();
+ }
+
+ if (dump_opt['l']) {
+ dump_label(argv[0]);
+ return (0);
+ }
+
+ if (dump_opt['R']) {
+ flagbits['b'] = ZDB_FLAG_PRINT_BLKPTR;
+ flagbits['c'] = ZDB_FLAG_CHECKSUM;
+ flagbits['d'] = ZDB_FLAG_DECOMPRESS;
+ flagbits['e'] = ZDB_FLAG_BSWAP;
+ flagbits['g'] = ZDB_FLAG_GBH;
+ flagbits['i'] = ZDB_FLAG_INDIRECT;
+ flagbits['p'] = ZDB_FLAG_PHYS;
+ flagbits['r'] = ZDB_FLAG_RAW;
+
+ spa = NULL;
+ while (argv[0]) {
+ zdb_read_block(argv[0], &spa);
+ argv++;
+ argc--;
+ }
+ if (spa)
+ spa_close(spa, (void *)zdb_read_block);
+ return (0);
+ }
+
+ if (dump_opt['C'])
+ dump_config(argv[0]);
+
+ if (strchr(argv[0], '/') != NULL) {
+ error = dmu_objset_open(argv[0], DMU_OST_ANY,
+ DS_MODE_STANDARD | DS_MODE_READONLY, &os);
+ } else {
+ error = spa_open(argv[0], &spa, FTAG);
+ }
+
+ if (error)
+ fatal("can't open %s: error %d", argv[0], error);
+
+ argv++;
+ if (--argc > 0) {
+ zopt_objects = argc;
+ zopt_object = calloc(zopt_objects, sizeof (uint64_t));
+ for (i = 0; i < zopt_objects; i++) {
+ errno = 0;
+ zopt_object[i] = strtoull(argv[i], NULL, 0);
+ if (zopt_object[i] == 0 && errno != 0)
+ fatal("bad object number %s: %s",
+ argv[i], strerror(errno));
+ }
+ }
+
+ if (os != NULL) {
+ dump_dir(os);
+ dmu_objset_close(os);
+ } else {
+ dump_zpool(spa);
+ spa_close(spa, FTAG);
+ }
+
+ kernel_fini();
+
+ return (0);
+}
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
new file mode 100644
index 0000000..10dfe20
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
@@ -0,0 +1,354 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Print intent log header and statistics.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+
+extern uint8_t dump_opt[256];
+
+static void
+print_log_bp(const blkptr_t *bp, const char *prefix)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+
+ sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
+ (void) printf("%s%s\n", prefix, blkbuf);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
+{
+ time_t crtime = lr->lr_crtime[0];
+ char *name = (char *)(lr + 1);
+ char *link = name + strlen(name) + 1;
+
+ if (txtype == TX_SYMLINK)
+ (void) printf("\t\t\t%s -> %s\n", name, link);
+ else
+ (void) printf("\t\t\t%s\n", name);
+
+ (void) printf("\t\t\t%s", ctime(&crtime));
+ (void) printf("\t\t\tdoid %llu, foid %llu, mode %llo\n",
+ (u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_foid,
+ (longlong_t)lr->lr_mode);
+ (void) printf("\t\t\tuid %llu, gid %llu, gen %llu, rdev 0x%llx\n",
+ (u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
+ (u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
+{
+ (void) printf("\t\t\tdoid %llu, name %s\n",
+ (u_longlong_t)lr->lr_doid, (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
+{
+ (void) printf("\t\t\tdoid %llu, link_obj %llu, name %s\n",
+ (u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
+ (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
+{
+ char *snm = (char *)(lr + 1);
+ char *tnm = snm + strlen(snm) + 1;
+
+ (void) printf("\t\t\tsdoid %llu, tdoid %llu\n",
+ (u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
+ (void) printf("\t\t\tsrc %s tgt %s\n", snm, tnm);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
+{
+ char *data, *dlimit;
+ blkptr_t *bp = &lr->lr_blkptr;
+ char buf[SPA_MAXBLOCKSIZE];
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ int error;
+
+ (void) printf("\t\t\tfoid %llu, offset 0x%llx,"
+ " length 0x%llx, blkoff 0x%llx\n",
+ (u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
+ (u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blkoff);
+
+ if (verbose < 5)
+ return;
+
+ if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+ (void) printf("\t\t\thas blkptr, %s\n",
+ bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
+ "will claim" : "won't claim");
+ print_log_bp(bp, "\t\t\t");
+ if (bp->blk_birth == 0) {
+ bzero(buf, sizeof (buf));
+ } else {
+ zbookmark_t zb;
+
+ ASSERT3U(bp->blk_cksum.zc_word[ZIL_ZC_OBJSET], ==,
+ dmu_objset_id(zilog->zl_os));
+
+ zb.zb_objset = bp->blk_cksum.zc_word[ZIL_ZC_OBJSET];
+ zb.zb_object = 0;
+ zb.zb_level = -1;
+ zb.zb_blkid = bp->blk_cksum.zc_word[ZIL_ZC_SEQ];
+
+ error = zio_wait(zio_read(NULL, zilog->zl_spa,
+ bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
+ ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
+ if (error)
+ return;
+ }
+ data = buf + lr->lr_blkoff;
+ } else {
+ data = (char *)(lr + 1);
+ }
+
+ dlimit = data + MIN(lr->lr_length,
+ (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE));
+
+ (void) printf("\t\t\t");
+ while (data < dlimit) {
+ if (isprint(*data))
+ (void) printf("%c ", *data);
+ else
+ (void) printf("%2X", *data);
+ data++;
+ }
+ (void) printf("\n");
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
+{
+ (void) printf("\t\t\tfoid %llu, offset 0x%llx, length 0x%llx\n",
+ (u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
+ (u_longlong_t)lr->lr_length);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
+{
+ time_t atime = (time_t)lr->lr_atime[0];
+ time_t mtime = (time_t)lr->lr_mtime[0];
+
+ (void) printf("\t\t\tfoid %llu, mask 0x%llx\n",
+ (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
+
+ if (lr->lr_mask & AT_MODE) {
+ (void) printf("\t\t\tAT_MODE %llo\n",
+ (longlong_t)lr->lr_mode);
+ }
+
+ if (lr->lr_mask & AT_UID) {
+ (void) printf("\t\t\tAT_UID %llu\n",
+ (u_longlong_t)lr->lr_uid);
+ }
+
+ if (lr->lr_mask & AT_GID) {
+ (void) printf("\t\t\tAT_GID %llu\n",
+ (u_longlong_t)lr->lr_gid);
+ }
+
+ if (lr->lr_mask & AT_SIZE) {
+ (void) printf("\t\t\tAT_SIZE %llu\n",
+ (u_longlong_t)lr->lr_size);
+ }
+
+ if (lr->lr_mask & AT_ATIME) {
+ (void) printf("\t\t\tAT_ATIME %llu.%09llu %s",
+ (u_longlong_t)lr->lr_atime[0],
+ (u_longlong_t)lr->lr_atime[1],
+ ctime(&atime));
+ }
+
+ if (lr->lr_mask & AT_MTIME) {
+ (void) printf("\t\t\tAT_MTIME %llu.%09llu %s",
+ (u_longlong_t)lr->lr_mtime[0],
+ (u_longlong_t)lr->lr_mtime[1],
+ ctime(&mtime));
+ }
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
+{
+ (void) printf("\t\t\tfoid %llu, aclcnt %llu\n",
+ (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
+}
+
+typedef void (*zil_prt_rec_func_t)();
+typedef struct zil_rec_info {
+ zil_prt_rec_func_t zri_print;
+ char *zri_name;
+ uint64_t zri_count;
+} zil_rec_info_t;
+
+static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
+ { NULL, "Total " },
+ { zil_prt_rec_create, "TX_CREATE " },
+ { zil_prt_rec_create, "TX_MKDIR " },
+ { zil_prt_rec_create, "TX_MKXATTR " },
+ { zil_prt_rec_create, "TX_SYMLINK " },
+ { zil_prt_rec_remove, "TX_REMOVE " },
+ { zil_prt_rec_remove, "TX_RMDIR " },
+ { zil_prt_rec_link, "TX_LINK " },
+ { zil_prt_rec_rename, "TX_RENAME " },
+ { zil_prt_rec_write, "TX_WRITE " },
+ { zil_prt_rec_truncate, "TX_TRUNCATE" },
+ { zil_prt_rec_setattr, "TX_SETATTR " },
+ { zil_prt_rec_acl, "TX_ACL " },
+};
+
+/* ARGSUSED */
+static void
+print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
+{
+ int txtype;
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+
+ txtype = lr->lrc_txtype;
+
+ ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
+ ASSERT(lr->lrc_txg);
+
+ (void) printf("\t\t%s len %6llu, txg %llu, seq %llu\n",
+ zil_rec_info[txtype].zri_name,
+ (u_longlong_t)lr->lrc_reclen,
+ (u_longlong_t)lr->lrc_txg,
+ (u_longlong_t)lr->lrc_seq);
+
+ if (txtype && verbose >= 3)
+ zil_rec_info[txtype].zri_print(zilog, txtype, lr);
+
+ zil_rec_info[txtype].zri_count++;
+ zil_rec_info[0].zri_count++;
+}
+
+/* ARGSUSED */
+static void
+print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+ char blkbuf[BP_SPRINTF_LEN];
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ char *claim;
+
+ if (verbose <= 3)
+ return;
+
+ if (verbose >= 5) {
+ (void) strcpy(blkbuf, ", ");
+ sprintf_blkptr(blkbuf + strlen(blkbuf),
+ BP_SPRINTF_LEN - strlen(blkbuf), bp);
+ } else {
+ blkbuf[0] = '\0';
+ }
+
+ if (claim_txg != 0)
+ claim = "already claimed";
+ else if (bp->blk_birth >= spa_first_txg(zilog->zl_spa))
+ claim = "will claim";
+ else
+ claim = "won't claim";
+
+ (void) printf("\tBlock seqno %llu, %s%s\n",
+ (u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
+}
+
+static void
+print_log_stats(int verbose)
+{
+ int i, w, p10;
+
+ if (verbose > 3)
+ (void) printf("\n");
+
+ if (zil_rec_info[0].zri_count == 0)
+ return;
+
+ for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10)
+ w++;
+
+ for (i = 0; i < TX_MAX_TYPE; i++)
+ if (zil_rec_info[i].zri_count || verbose >= 3)
+ (void) printf("\t\t%s %*llu\n",
+ zil_rec_info[i].zri_name, w,
+ (u_longlong_t)zil_rec_info[i].zri_count);
+ (void) printf("\n");
+}
+
+/* ARGSUSED */
+void
+dump_intent_log(zilog_t *zilog)
+{
+ const zil_header_t *zh = zilog->zl_header;
+ int verbose = MAX(dump_opt['d'], dump_opt['i']);
+ int i;
+
+ if (zh->zh_log.blk_birth == 0 || verbose < 2)
+ return;
+
+ (void) printf("\n ZIL header: claim_txg %llu, seq %llu\n",
+ (u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_replay_seq);
+
+ if (verbose >= 4)
+ print_log_bp(&zh->zh_log, "\n\tfirst block: ");
+
+ for (i = 0; i < TX_MAX_TYPE; i++)
+ zil_rec_info[i].zri_count = 0;
+
+ if (verbose >= 2) {
+ (void) printf("\n");
+ (void) zil_parse(zilog, print_log_block, print_log_record, NULL,
+ zh->zh_claim_txg);
+ print_log_stats(verbose);
+ }
+}
OpenPOWER on IntegriCloud