From ed828c0c375477ff27d5fa9a7bf46ae6b6f2e57a Mon Sep 17 00:00:00 2001 From: George Melikov Date: Tue, 31 Jan 2017 21:13:10 +0300 Subject: [PATCH] OpenZFS 7280 - Allow changing global libzpool variables in zdb and ztest through command line Authored by: Pavel Zakharov Reviewed by: Matthew Ahrens Reviewed by: Dan Kimmel Approved by: Robert Mustacchi Reviewed-by: Brian Behlendorf Ported-by: George Melikov OpenZFS-issue: https://www.illumos.org/issues/7280 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/0e60744 Closes #5676 --- cmd/zdb/zdb.c | 18 +++++++++---- cmd/ztest/ztest.c | 8 +++++- include/sys/zfs_context.h | 10 +++---- lib/libzpool/Makefile.am | 2 +- lib/libzpool/util.c | 57 +++++++++++++++++++++++++++++++++++++++ man/man8/zdb.8 | 14 +++++++++- 6 files changed, 95 insertions(+), 14 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 6a36aa1ef..10bca4a91 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -127,7 +127,8 @@ usage(void) { (void) fprintf(stderr, "Usage: %s [-CumMdibcsDvhLXFPAG] [-t txg] [-e [-p path...]] " - "[-U config] [-I inflight I/Os] [-x dumpdir] poolname [object...]\n" + "[-U config] [-I inflight I/Os] [-x dumpdir] [-o var=value] " + "poolname [object...]\n" " %s [-divPA] [-e -p path...] [-U config] dataset " "[object...]\n" " %s -mM [-LXFPA] [-t txg] [-e [-p path...]] [-U config] " @@ -189,6 +190,8 @@ usage(void) "checksumming I/Os [default is 200]\n"); (void) fprintf(stderr, " -G dump zfs_dbgmsg buffer before " "exiting\n"); + (void) fprintf(stderr, " -o = set global " + "variable to an unsigned 32-bit integer value\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"); @@ -3707,7 +3710,7 @@ main(int argc, char **argv) spa_config_path = spa_config_path_env; while ((c = getopt(argc, argv, - "bcdhilmMI:suCDRSAFLXx:evp:t:U:PVG")) != -1) { + "bcdhilmMI:suCDRSAFLXx:evp:t:U:PVGo")) != -1) { switch (c) { case 'b': case 'c': @@ -3762,9 +3765,6 @@ main(int argc, char **argv) } searchdirs[nsearch++] = optarg; break; - case 'x': - vn_dumpdir = optarg; - break; case 't': max_txg = strtoull(optarg, NULL, 0); if (max_txg < TXG_INITIAL) { @@ -3779,6 +3779,14 @@ main(int argc, char **argv) case 'v': verbose++; break; + case 'x': + vn_dumpdir = optarg; + break; + case 'o': + error = set_global_var(optarg); + if (error != 0) + usage(); + break; default: usage(); break; diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 70a3e206f..d1c6a783a 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -629,6 +629,8 @@ usage(boolean_t requested) "\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n" "\t[-P passtime (default: %llu sec)] time per pass\n" "\t[-B alt_ztest (default: )] alternate ztest path\n" + "\t[-o variable=value] ... set global variable to an unsigned\n" + "\t 32-bit integer value\n" "\t[-h] (print help)\n" "", zo->zo_pool, @@ -664,7 +666,7 @@ process_options(int argc, char **argv) bcopy(&ztest_opts_defaults, zo, sizeof (*zo)); while ((opt = getopt(argc, argv, - "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:hF:B:")) != EOF) { + "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:hF:B:o:")) != EOF) { value = 0; switch (opt) { case 'v': @@ -752,6 +754,10 @@ process_options(int argc, char **argv) case 'B': (void) strlcpy(altdir, optarg, sizeof (altdir)); break; + case 'o': + if (set_global_var(optarg) != 0) + usage(B_FALSE); + break; case 'h': usage(B_TRUE); break; diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index bca89e1c9..b4f63e19c 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -19,13 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. - * Copyright (c) 2012, 2015 by Delphix. All rights reserved. */ #ifndef _SYS_ZFS_CONTEXT_H @@ -695,6 +692,7 @@ extern void random_fini(void); struct spa; extern void nicenum(uint64_t num, char *buf); extern void show_pool_stats(struct spa *); +extern int set_global_var(char *arg); typedef struct callb_cpr { kmutex_t *cc_lockp; diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 40c460284..1e95f8064 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -140,7 +140,7 @@ libzpool_la_LIBADD = \ $(top_builddir)/lib/libnvpair/libnvpair.la \ $(top_builddir)/lib/libicp/libicp.la -libzpool_la_LIBADD += $(ZLIB) +libzpool_la_LIBADD += $(ZLIB) -ldl libzpool_la_LDFLAGS = -version-info 2:0:0 EXTRA_DIST = $(USER_C) diff --git a/lib/libzpool/util.c b/lib/libzpool/util.c index bc3bcbe78..3bdc31722 100644 --- a/lib/libzpool/util.c +++ b/lib/libzpool/util.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 by Delphix. All rights reserved. */ #include @@ -31,6 +32,7 @@ #include #include #include +#include /* * Routines needed by more than one client of libzpool. @@ -158,3 +160,58 @@ show_pool_stats(spa_t *spa) nvlist_free(config); } + +/* + * Sets given global variable in libzpool to given unsigned 32-bit value. + * arg: "=" + */ +int +set_global_var(char *arg) +{ + void *zpoolhdl; + char *varname = arg, *varval; + u_longlong_t val; + +#ifndef _LITTLE_ENDIAN + /* + * On big endian systems changing a 64-bit variable would set the high + * 32 bits instead of the low 32 bits, which could cause unexpected + * results. + */ + fprintf(stderr, "Setting global variables is only supported on " + "little-endian systems\n"); + return (ENOTSUP); +#endif + if ((varval = strchr(arg, '=')) != NULL) { + *varval = '\0'; + varval++; + val = strtoull(varval, NULL, 0); + if (val > UINT32_MAX) { + fprintf(stderr, "Value for global variable '%s' must " + "be a 32-bit unsigned integer\n", varname); + return (EOVERFLOW); + } + } else { + return (EINVAL); + } + + zpoolhdl = dlopen("libzpool.so", RTLD_LAZY); + if (zpoolhdl != NULL) { + uint32_t *var; + var = dlsym(zpoolhdl, varname); + if (var == NULL) { + fprintf(stderr, "Global variable '%s' does not exist " + "in libzpool.so\n", varname); + return (EINVAL); + } + *var = (uint32_t)val; + + dlclose(zpoolhdl); + } else { + fprintf(stderr, "Failed to open libzpool.so to set global " + "variable\n"); + return (EIO); + } + + return (0); +} diff --git a/man/man8/zdb.8 b/man/man8/zdb.8 index 271e512d5..6696a2fe0 100644 --- a/man/man8/zdb.8 +++ b/man/man8/zdb.8 @@ -21,7 +21,7 @@ .SH "SYNOPSIS" \fBzdb\fR [-CumdibcsDvhLMXFPAG] [-e [-p \fIpath\fR...]] [-t \fItxg\fR] [-U \fIcache\fR] [-I \fIinflight I/Os\fR] [-x \fIdumpdir\fR] - [\fIpoolname\fR [\fIobject\fR ...]] + [-o \fIvar\fR=\fIvalue\fR] ... [\fIpoolname\fR [\fIobject\fR ...]] .P \fBzdb\fR [-divPA] [-e [-p \fIpath\fR...]] [-U \fIcache\fR] @@ -420,6 +420,18 @@ default value is 200. This option affects the performance of the \fB-c\fR option. .RE +.sp +.ne 2 +.na +\fB-o \fIvar\fR=\fIvalue\fR ... \fR +.ad +.sp .6 +.RS 4n +Set the given global libzpool variable to the provided value. The value must +be an unsigned 32-bit integer. Currently only little-endian systems are +supported to avoid accidentally setting the high 32 bits of 64-bit variables. +.RE + .sp .ne 2 .na