summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorGeorge Wilson <george.wilson@delphix.com>2016-07-13 14:31:56 -0700
committerMatthew Ahrens <mahrens@delphix.com>2016-07-14 11:55:57 -0700
commitdcbf3bd6a1f1360fc1afcee9e22c6dcff7844bf2 (patch)
treea4098fece7aa93244ddc9d2acfd8c9529e878a81 /usr/src/cmd
parenta5dce49383b67bfd3a81999460d579f53a67c029 (diff)
downloadillumos-joyent-dcbf3bd6a1f1360fc1afcee9e22c6dcff7844bf2.tar.gz
6950 ARC should cache compressed data
Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Don Brady <don.brady@intel.com> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.c20
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_ctf.h3
-rw-r--r--usr/src/cmd/mdb/common/modules/conf/mapfile-extern3
-rw-r--r--usr/src/cmd/mdb/common/modules/zfs/zfs.c429
-rw-r--r--usr/src/cmd/zdb/zdb.c2
-rw-r--r--usr/src/cmd/ztest/ztest.c7
6 files changed, 459 insertions, 5 deletions
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
index 66a8b009a3..8b8b72fd53 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -910,6 +910,24 @@ mdb_ctf_offsetof_by_name(const char *type, const char *member)
return (off);
}
+ssize_t
+mdb_ctf_sizeof_by_name(const char *type)
+{
+ mdb_ctf_id_t id;
+ ssize_t size;
+
+ if (mdb_ctf_lookup_by_name(type, &id) == -1) {
+ mdb_warn("couldn't find type %s", type);
+ return (-1);
+ }
+
+ if ((size = mdb_ctf_type_size(id)) == -1) {
+ mdb_warn("couldn't determine type size of %s", type);
+ return (-1);
+ }
+
+ return (size);
+}
/*ARGSUSED*/
static int
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_ctf.h b/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
index 85e60494d0..21f27d782b 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_ctf.h
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
* Copyright (c) 2015, Joyent, Inc.
*/
@@ -136,6 +136,7 @@ extern int mdb_ctf_member_info(mdb_ctf_id_t, const char *,
extern int mdb_ctf_offsetof(mdb_ctf_id_t, const char *, ulong_t *);
extern int mdb_ctf_num_members(mdb_ctf_id_t);
extern int mdb_ctf_offsetof_by_name(const char *, const char *);
+extern ssize_t mdb_ctf_sizeof_by_name(const char *);
extern ssize_t mdb_ctf_offset_to_name(mdb_ctf_id_t, ulong_t, char *, size_t,
int, mdb_ctf_id_t *, ulong_t *);
diff --git a/usr/src/cmd/mdb/common/modules/conf/mapfile-extern b/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
index 2491a7a8d5..73de8f1e41 100644
--- a/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
+++ b/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
@@ -1,6 +1,6 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2013 by Delphix. All rights reserved.
+# Copyright (c) 2013, 2015 by Delphix. All rights reserved.
#
# CDDL HEADER START
#
@@ -67,6 +67,7 @@ SYMBOL_SCOPE {
mdb_ctf_module_lookup { FLAGS = EXTERN };
mdb_ctf_offsetof { FLAGS = EXTERN };
mdb_ctf_offsetof_by_name { FLAGS = EXTERN };
+ mdb_ctf_sizeof_by_name { FLAGS = EXTERN };
mdb_ctf_readsym { FLAGS = EXTERN };
mdb_ctf_type_cmp { FLAGS = EXTERN };
mdb_ctf_type_invalidate { FLAGS = EXTERN };
diff --git a/usr/src/cmd/mdb/common/modules/zfs/zfs.c b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
index 697349b020..12f26d382c 100644
--- a/usr/src/cmd/mdb/common/modules/zfs/zfs.c
+++ b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
@@ -42,6 +42,7 @@
#include <ctype.h>
#include <sys/zfs_acl.h>
#include <sys/sa_impl.h>
+#include <sys/multilist.h>
#ifdef _KERNEL
#define ZFS_OBJ_NAME "zfs"
@@ -973,6 +974,7 @@ arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
"mfu_ghost_evictable_metadata", "evict_l2_cached",
"evict_l2_eligible", "evict_l2_ineligible", "l2_read_bytes",
"l2_write_bytes", "l2_size", "l2_asize", "l2_hdr_size",
+ "compressed_size", "uncompressed_size", "overhead_size",
NULL
};
@@ -1655,7 +1657,6 @@ metaslab_walk_step(mdb_walk_state_t *wsp)
return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata));
}
-/* ARGSUSED */
static int
metaslab_walk_init(mdb_walk_state_t *wsp)
{
@@ -2183,6 +2184,69 @@ zio_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (mdb_pwalk_dcmd("zio_root", "zio", argc, argv, addr));
}
+typedef struct mdb_multilist {
+ uint64_t ml_num_sublists;
+ uintptr_t ml_sublists;
+} mdb_multilist_t;
+
+typedef struct multilist_walk_data {
+ uint64_t mwd_idx;
+ mdb_multilist_t mwd_ml;
+} multilist_walk_data_t;
+
+/* ARGSUSED */
+static int
+multilist_print_cb(uintptr_t addr, const void *unknown, void *arg)
+{
+ mdb_printf("%#lr\n", addr);
+ return (WALK_NEXT);
+}
+
+static int
+multilist_walk_step(mdb_walk_state_t *wsp)
+{
+ multilist_walk_data_t *mwd = wsp->walk_data;
+
+ if (mwd->mwd_idx >= mwd->mwd_ml.ml_num_sublists)
+ return (WALK_DONE);
+
+ wsp->walk_addr = mwd->mwd_ml.ml_sublists +
+ mdb_ctf_sizeof_by_name("multilist_sublist_t") * mwd->mwd_idx +
+ mdb_ctf_offsetof_by_name("multilist_sublist_t", "mls_list");
+
+ mdb_pwalk("list", multilist_print_cb, (void*)NULL, wsp->walk_addr);
+ mwd->mwd_idx++;
+
+ return (WALK_NEXT);
+}
+
+static int
+multilist_walk_init(mdb_walk_state_t *wsp)
+{
+ multilist_walk_data_t *mwd;
+
+ if (wsp->walk_addr == NULL) {
+ mdb_warn("must supply address of multilist_t\n");
+ return (WALK_ERR);
+ }
+
+ mwd = mdb_zalloc(sizeof (multilist_walk_data_t), UM_SLEEP | UM_GC);
+ if (mdb_ctf_vread(&mwd->mwd_ml, "multilist_t", "mdb_multilist_t",
+ wsp->walk_addr, 0) == -1) {
+ return (WALK_ERR);
+ }
+
+ if (mwd->mwd_ml.ml_num_sublists == 0 ||
+ mwd->mwd_ml.ml_sublists == NULL) {
+ mdb_warn("invalid or uninitialized multilist at %#lx\n",
+ wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ wsp->walk_data = mwd;
+ return (WALK_NEXT);
+}
+
typedef struct txg_list_walk_data {
uintptr_t lw_head[TXG_SIZE];
int lw_txgoff;
@@ -3269,6 +3333,359 @@ rrwlock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_OK);
}
+typedef struct mdb_arc_buf_hdr_t {
+ uint16_t b_psize;
+ uint16_t b_lsize;
+ struct {
+ uint32_t b_bufcnt;
+ uintptr_t b_state;
+ uintptr_t b_pdata;
+ } b_l1hdr;
+} mdb_arc_buf_hdr_t;
+
+enum arc_cflags {
+ ARC_CFLAG_VERBOSE = 1 << 0,
+ ARC_CFLAG_ANON = 1 << 1,
+ ARC_CFLAG_MRU = 1 << 2,
+ ARC_CFLAG_MFU = 1 << 3,
+ ARC_CFLAG_BUFS = 1 << 4,
+};
+
+typedef struct arc_compression_stats_data {
+ GElf_Sym anon_sym; /* ARC_anon symbol */
+ GElf_Sym mru_sym; /* ARC_mru symbol */
+ GElf_Sym mrug_sym; /* ARC_mru_ghost symbol */
+ GElf_Sym mfu_sym; /* ARC_mfu symbol */
+ GElf_Sym mfug_sym; /* ARC_mfu_ghost symbol */
+ GElf_Sym l2c_sym; /* ARC_l2c_only symbol */
+ uint64_t *anon_c_hist; /* histogram of compressed sizes in anon */
+ uint64_t *anon_u_hist; /* histogram of uncompressed sizes in anon */
+ uint64_t *anon_bufs; /* histogram of buffer counts in anon state */
+ uint64_t *mru_c_hist; /* histogram of compressed sizes in mru */
+ uint64_t *mru_u_hist; /* histogram of uncompressed sizes in mru */
+ uint64_t *mru_bufs; /* histogram of buffer counts in mru */
+ uint64_t *mfu_c_hist; /* histogram of compressed sizes in mfu */
+ uint64_t *mfu_u_hist; /* histogram of uncompressed sizes in mfu */
+ uint64_t *mfu_bufs; /* histogram of buffer counts in mfu */
+ uint64_t *all_c_hist; /* histogram of compressed anon + mru + mfu */
+ uint64_t *all_u_hist; /* histogram of uncompressed anon + mru + mfu */
+ uint64_t *all_bufs; /* histogram of buffer counts in all states */
+ int arc_cflags; /* arc compression flags, specified by user */
+ int hist_nbuckets; /* number of buckets in each histogram */
+} arc_compression_stats_data_t;
+
+int
+highbit64(uint64_t i)
+{
+ int h = 1;
+
+ if (i == 0)
+ return (0);
+ if (i & 0xffffffff00000000ULL) {
+ h += 32; i >>= 32;
+ }
+ if (i & 0xffff0000) {
+ h += 16; i >>= 16;
+ }
+ if (i & 0xff00) {
+ h += 8; i >>= 8;
+ }
+ if (i & 0xf0) {
+ h += 4; i >>= 4;
+ }
+ if (i & 0xc) {
+ h += 2; i >>= 2;
+ }
+ if (i & 0x2) {
+ h += 1;
+ }
+ return (h);
+}
+
+/* ARGSUSED */
+static int
+arc_compression_stats_cb(uintptr_t addr, const void *unknown, void *arg)
+{
+ arc_compression_stats_data_t *data = arg;
+ mdb_arc_buf_hdr_t hdr;
+ int cbucket, ubucket, bufcnt;
+
+ if (mdb_ctf_vread(&hdr, "arc_buf_hdr_t", "mdb_arc_buf_hdr_t",
+ addr, 0) == -1) {
+ return (WALK_ERR);
+ }
+
+ /*
+ * Headers in the ghost states, or the l2c_only state don't have
+ * arc buffers linked off of them. Thus, their compressed size
+ * is meaningless, so we skip these from the stats.
+ */
+ if (hdr.b_l1hdr.b_state == data->mrug_sym.st_value ||
+ hdr.b_l1hdr.b_state == data->mfug_sym.st_value ||
+ hdr.b_l1hdr.b_state == data->l2c_sym.st_value) {
+ return (WALK_NEXT);
+ }
+
+ /*
+ * The physical size (compressed) and logical size
+ * (uncompressed) are in units of SPA_MINBLOCKSIZE. By default,
+ * we use the log2 of this value (rounded down to the nearest
+ * integer) to determine the bucket to assign this header to.
+ * Thus, the histogram is logarithmic with respect to the size
+ * of the header. For example, the following is a mapping of the
+ * bucket numbers and the range of header sizes they correspond to:
+ *
+ * 0: 0 byte headers
+ * 1: 512 byte headers
+ * 2: [1024 - 2048) byte headers
+ * 3: [2048 - 4096) byte headers
+ * 4: [4096 - 8192) byte headers
+ * 5: [8192 - 16394) byte headers
+ * 6: [16384 - 32768) byte headers
+ * 7: [32768 - 65536) byte headers
+ * 8: [65536 - 131072) byte headers
+ * 9: 131072 byte headers
+ *
+ * If the ARC_CFLAG_VERBOSE flag was specified, we use the
+ * physical and logical sizes directly. Thus, the histogram will
+ * no longer be logarithmic; instead it will be linear with
+ * respect to the size of the header. The following is a mapping
+ * of the first many bucket numbers and the header size they
+ * correspond to:
+ *
+ * 0: 0 byte headers
+ * 1: 512 byte headers
+ * 2: 1024 byte headers
+ * 3: 1536 byte headers
+ * 4: 2048 byte headers
+ * 5: 2560 byte headers
+ * 6: 3072 byte headers
+ *
+ * And so on. Keep in mind that a range of sizes isn't used in
+ * the case of linear scale because the headers can only
+ * increment or decrement in sizes of 512 bytes. So, it's not
+ * possible for a header to be sized in between whats listed
+ * above.
+ *
+ * Also, the above mapping values were calculated assuming a
+ * SPA_MINBLOCKSHIFT of 512 bytes and a SPA_MAXBLOCKSIZE of 128K.
+ */
+
+ if (data->arc_cflags & ARC_CFLAG_VERBOSE) {
+ cbucket = hdr.b_psize;
+ ubucket = hdr.b_lsize;
+ } else {
+ cbucket = highbit64(hdr.b_psize);
+ ubucket = highbit64(hdr.b_lsize);
+ }
+
+ bufcnt = hdr.b_l1hdr.b_bufcnt;
+ if (bufcnt >= data->hist_nbuckets)
+ bufcnt = data->hist_nbuckets - 1;
+
+ /* Ensure we stay within the bounds of the histogram array */
+ ASSERT3U(cbucket, <, data->hist_nbuckets);
+ ASSERT3U(ubucket, <, data->hist_nbuckets);
+
+ if (hdr.b_l1hdr.b_state == data->anon_sym.st_value) {
+ data->anon_c_hist[cbucket]++;
+ data->anon_u_hist[ubucket]++;
+ data->anon_bufs[bufcnt]++;
+ } else if (hdr.b_l1hdr.b_state == data->mru_sym.st_value) {
+ data->mru_c_hist[cbucket]++;
+ data->mru_u_hist[ubucket]++;
+ data->mru_bufs[bufcnt]++;
+ } else if (hdr.b_l1hdr.b_state == data->mfu_sym.st_value) {
+ data->mfu_c_hist[cbucket]++;
+ data->mfu_u_hist[ubucket]++;
+ data->mfu_bufs[bufcnt]++;
+ }
+
+ data->all_c_hist[cbucket]++;
+ data->all_u_hist[ubucket]++;
+ data->all_bufs[bufcnt]++;
+
+ return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+static int
+arc_compression_stats(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ arc_compression_stats_data_t data = { 0 };
+ unsigned int max_shifted = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT;
+ unsigned int hist_size;
+ char range[32];
+ int rc = DCMD_OK;
+
+ if (mdb_getopts(argc, argv,
+ 'v', MDB_OPT_SETBITS, ARC_CFLAG_VERBOSE, &data.arc_cflags,
+ 'a', MDB_OPT_SETBITS, ARC_CFLAG_ANON, &data.arc_cflags,
+ 'b', MDB_OPT_SETBITS, ARC_CFLAG_BUFS, &data.arc_cflags,
+ 'r', MDB_OPT_SETBITS, ARC_CFLAG_MRU, &data.arc_cflags,
+ 'f', MDB_OPT_SETBITS, ARC_CFLAG_MFU, &data.arc_cflags) != argc)
+ return (DCMD_USAGE);
+
+ if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_anon", &data.anon_sym) ||
+ mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru", &data.mru_sym) ||
+ mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru_ghost", &data.mrug_sym) ||
+ mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu", &data.mfu_sym) ||
+ mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu_ghost", &data.mfug_sym) ||
+ mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_l2c_only", &data.l2c_sym)) {
+ mdb_warn("can't find arc state symbol");
+ return (DCMD_ERR);
+ }
+
+ /*
+ * Determine the maximum expected size for any header, and use
+ * this to determine the number of buckets needed for each
+ * histogram. If ARC_CFLAG_VERBOSE is specified, this value is
+ * used directly; otherwise the log2 of the maximum size is
+ * used. Thus, if using a log2 scale there's a maximum of 10
+ * possible buckets, while the linear scale (when using
+ * ARC_CFLAG_VERBOSE) has a maximum of 257 buckets.
+ */
+ if (data.arc_cflags & ARC_CFLAG_VERBOSE)
+ data.hist_nbuckets = max_shifted + 1;
+ else
+ data.hist_nbuckets = highbit64(max_shifted) + 1;
+
+ hist_size = sizeof (uint64_t) * data.hist_nbuckets;
+
+ data.anon_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.anon_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.anon_bufs = mdb_zalloc(hist_size, UM_SLEEP);
+
+ data.mru_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.mru_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.mru_bufs = mdb_zalloc(hist_size, UM_SLEEP);
+
+ data.mfu_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.mfu_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.mfu_bufs = mdb_zalloc(hist_size, UM_SLEEP);
+
+ data.all_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.all_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
+ data.all_bufs = mdb_zalloc(hist_size, UM_SLEEP);
+
+ if (mdb_walk("arc_buf_hdr_t_full", arc_compression_stats_cb,
+ &data) != 0) {
+ mdb_warn("can't walk arc_buf_hdr's");
+ rc = DCMD_ERR;
+ goto out;
+ }
+
+ if (data.arc_cflags & ARC_CFLAG_VERBOSE) {
+ rc = mdb_snprintf(range, sizeof (range),
+ "[n*%llu, (n+1)*%llu)", SPA_MINBLOCKSIZE,
+ SPA_MINBLOCKSIZE);
+ } else {
+ rc = mdb_snprintf(range, sizeof (range),
+ "[2^(n-1)*%llu, 2^n*%llu)", SPA_MINBLOCKSIZE,
+ SPA_MINBLOCKSIZE);
+ }
+
+ if (rc < 0) {
+ /* snprintf failed, abort the dcmd */
+ rc = DCMD_ERR;
+ goto out;
+ } else {
+ /* snprintf succeeded above, reset return code */
+ rc = DCMD_OK;
+ }
+
+ if (data.arc_cflags & ARC_CFLAG_ANON) {
+ if (data.arc_cflags & ARC_CFLAG_BUFS) {
+ mdb_printf("Histogram of the number of anon buffers "
+ "that are associated with an arc hdr.\n");
+ dump_histogram(data.anon_bufs, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+ mdb_printf("Histogram of compressed anon buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.anon_c_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+
+ mdb_printf("Histogram of uncompressed anon buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.anon_u_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+
+ if (data.arc_cflags & ARC_CFLAG_MRU) {
+ if (data.arc_cflags & ARC_CFLAG_BUFS) {
+ mdb_printf("Histogram of the number of mru buffers "
+ "that are associated with an arc hdr.\n");
+ dump_histogram(data.mru_bufs, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+ mdb_printf("Histogram of compressed mru buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.mru_c_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+
+ mdb_printf("Histogram of uncompressed mru buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.mru_u_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+
+ if (data.arc_cflags & ARC_CFLAG_MFU) {
+ if (data.arc_cflags & ARC_CFLAG_BUFS) {
+ mdb_printf("Histogram of the number of mfu buffers "
+ "that are associated with an arc hdr.\n");
+ dump_histogram(data.mfu_bufs, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+
+ mdb_printf("Histogram of compressed mfu buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.mfu_c_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+
+ mdb_printf("Histogram of uncompressed mfu buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.mfu_u_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+
+ if (data.arc_cflags & ARC_CFLAG_BUFS) {
+ mdb_printf("Histogram of all buffers that "
+ "are associated with an arc hdr.\n");
+ dump_histogram(data.all_bufs, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+ }
+
+ mdb_printf("Histogram of all compressed buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.all_c_hist, data.hist_nbuckets, 0);
+ mdb_printf("\n");
+
+ mdb_printf("Histogram of all uncompressed buffers.\n"
+ "Each bucket represents buffers of size: %s.\n", range);
+ dump_histogram(data.all_u_hist, data.hist_nbuckets, 0);
+
+out:
+ mdb_free(data.anon_c_hist, hist_size);
+ mdb_free(data.anon_u_hist, hist_size);
+ mdb_free(data.anon_bufs, hist_size);
+
+ mdb_free(data.mru_c_hist, hist_size);
+ mdb_free(data.mru_u_hist, hist_size);
+ mdb_free(data.mru_bufs, hist_size);
+
+ mdb_free(data.mfu_c_hist, hist_size);
+ mdb_free(data.mfu_u_hist, hist_size);
+ mdb_free(data.mfu_bufs, hist_size);
+
+ mdb_free(data.all_c_hist, hist_size);
+ mdb_free(data.all_u_hist, hist_size);
+ mdb_free(data.all_bufs, hist_size);
+
+ return (rc);
+}
+
/*
* MDB module linkage information:
*
@@ -3339,6 +3756,14 @@ static const mdb_dcmd_t dcmds[] = {
"print zfs debug log", dbgmsg},
{ "rrwlock", ":",
"print rrwlock_t, including readers", rrwlock},
+ { "arc_compression_stats", ":[-vabrf]\n"
+ "\t-v verbose, display a linearly scaled histogram\n"
+ "\t-a display ARC_anon state statistics individually\n"
+ "\t-r display ARC_mru state statistics individually\n"
+ "\t-f display ARC_mfu state statistics individually\n"
+ "\t-b display histogram of buffer counts\n",
+ "print a histogram of compressed arc buffer sizes",
+ arc_compression_stats},
{ NULL }
};
@@ -3364,6 +3789,8 @@ static const mdb_walker_t walkers[] = {
spa_walk_init, spa_walk_step, NULL },
{ "metaslab", "given a spa_t *, walk all metaslab_t structures",
metaslab_walk_init, metaslab_walk_step, NULL },
+ { "multilist", "given a multilist_t *, walk all list_t structures",
+ multilist_walk_init, multilist_walk_step, NULL },
{ "zfs_acl_node", "given a zfs_acl_t, walk all zfs_acl_nodes",
zfs_acl_node_walk_init, zfs_acl_node_walk_step, NULL },
{ "zfs_acl_node_aces", "given a zfs_acl_node_t, walk all ACEs",
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c
index 812453b826..deef7b4084 100644
--- a/usr/src/cmd/zdb/zdb.c
+++ b/usr/src/cmd/zdb/zdb.c
@@ -1264,7 +1264,7 @@ visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
}
if (!err)
ASSERT3U(fill, ==, BP_GET_FILL(bp));
- (void) arc_buf_remove_ref(buf, &buf);
+ arc_buf_destroy(buf, &buf);
}
return (err);
diff --git a/usr/src/cmd/ztest/ztest.c b/usr/src/cmd/ztest/ztest.c
index a3800f60ce..b21d61d3a7 100644
--- a/usr/src/cmd/ztest/ztest.c
+++ b/usr/src/cmd/ztest/ztest.c
@@ -187,6 +187,7 @@ extern uint64_t metaslab_gang_bang;
extern uint64_t metaslab_df_alloc_threshold;
extern uint64_t zfs_deadman_synctime_ms;
extern int metaslab_preload_limit;
+extern boolean_t zfs_compressed_arc_enabled;
static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
@@ -5378,6 +5379,12 @@ ztest_resume_thread(void *arg)
if (spa_suspended(spa))
ztest_resume(spa);
(void) poll(NULL, 0, 100);
+
+ /*
+ * Periodically change the zfs_compressed_arc_enabled setting.
+ */
+ if (ztest_random(10) == 0)
+ zfs_compressed_arc_enabled = ztest_random(2);
}
return (NULL);
}