mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-01-14 09:12:11 +03:00
libzpool: tunable-based option interface for zdb/ztest
Removes the old dlsym() based option setter and adds a new function handle_tunable_option() that can set, get and list all the tunables in the system. And then wire it up to zdb and ztest. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Signed-off-by: Rob Norris <robn@despairlabs.com> Closes #17537
This commit is contained in:
parent
cb9742e532
commit
fce18e04d5
@ -797,8 +797,8 @@ usage(void)
|
||||
"[default is 200]\n");
|
||||
(void) fprintf(stderr, " -K --key=KEY "
|
||||
"decryption key for encrypted dataset\n");
|
||||
(void) fprintf(stderr, " -o --option=\"OPTION=INTEGER\" "
|
||||
"set global variable to an unsigned 32-bit integer\n");
|
||||
(void) fprintf(stderr, " -o --option=\"NAME=VALUE\" "
|
||||
"set the named tunable to the given value\n");
|
||||
(void) fprintf(stderr, " -p --path==PATH "
|
||||
"use one or more with -e to specify path to vdev dir\n");
|
||||
(void) fprintf(stderr, " -P --parseable "
|
||||
@ -9377,9 +9377,11 @@ main(int argc, char **argv)
|
||||
while (*optarg != '\0') { *optarg++ = '*'; }
|
||||
break;
|
||||
case 'o':
|
||||
error = set_global_var(optarg);
|
||||
dump_opt[c]++;
|
||||
dump_all = 0;
|
||||
error = handle_tunable_option(optarg, B_FALSE);
|
||||
if (error != 0)
|
||||
usage();
|
||||
zdb_exit(1);
|
||||
break;
|
||||
case 'p':
|
||||
if (searchdirs == NULL) {
|
||||
@ -9545,6 +9547,12 @@ main(int argc, char **argv)
|
||||
error = 0;
|
||||
goto fini;
|
||||
}
|
||||
if (dump_opt['o'])
|
||||
/*
|
||||
* Avoid blasting tunable options off the top of the
|
||||
* screen.
|
||||
*/
|
||||
zdb_exit(1);
|
||||
usage();
|
||||
}
|
||||
|
||||
|
||||
@ -809,8 +809,8 @@ static ztest_option_t option_table[] = {
|
||||
{ 'X', "raidz-expansion", NULL,
|
||||
"Perform a dedicated raidz expansion test",
|
||||
NO_DEFAULT, NULL},
|
||||
{ 'o', "option", "\"OPTION=INTEGER\"",
|
||||
"Set global variable to an unsigned 32-bit integer value",
|
||||
{ 'o', "option", "\"NAME=VALUE\"",
|
||||
"Set the named tunable to the given value",
|
||||
NO_DEFAULT, NULL},
|
||||
{ 'G', "dump-debug-msg", NULL,
|
||||
"Dump zfs_dbgmsg buffer before exiting due to an error",
|
||||
@ -7069,7 +7069,7 @@ ztest_set_global_vars(void)
|
||||
char *kv = ztest_opts.zo_gvars[i];
|
||||
VERIFY3U(strlen(kv), <=, ZO_GVARS_MAX_ARGLEN);
|
||||
VERIFY3U(strlen(kv), >, 0);
|
||||
int err = set_global_var(kv);
|
||||
int err = handle_tunable_option(kv, B_TRUE);
|
||||
if (ztest_opts.zo_verbose > 0) {
|
||||
(void) printf("setting global var %s ... %s\n", kv,
|
||||
err ? "failed" : "ok");
|
||||
|
||||
@ -661,7 +661,7 @@ extern void random_fini(void);
|
||||
|
||||
struct spa;
|
||||
extern void show_pool_stats(struct spa *);
|
||||
extern int set_global_var(char const *arg);
|
||||
extern int handle_tunable_option(const char *, boolean_t);
|
||||
|
||||
typedef struct callb_cpr {
|
||||
kmutex_t *cc_lockp;
|
||||
|
||||
@ -199,7 +199,7 @@ libzpool_la_LIBADD = \
|
||||
libzstd.la \
|
||||
libzutil.la
|
||||
|
||||
libzpool_la_LIBADD += $(LIBCLOCK_GETTIME) $(ZLIB_LIBS) -ldl -lm
|
||||
libzpool_la_LIBADD += $(LIBCLOCK_GETTIME) $(ZLIB_LIBS) -lm
|
||||
|
||||
libzpool_la_LDFLAGS = -pthread
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_refcount.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/tunables.h>
|
||||
#include <libzutil.h>
|
||||
|
||||
/*
|
||||
@ -151,97 +151,119 @@ show_pool_stats(spa_t *spa)
|
||||
nvlist_free(config);
|
||||
}
|
||||
|
||||
/* *k_out must be freed by the caller */
|
||||
static int
|
||||
set_global_var_parse_kv(const char *arg, char **k_out, u_longlong_t *v_out)
|
||||
{
|
||||
int err;
|
||||
VERIFY(arg);
|
||||
char *d = strdup(arg);
|
||||
|
||||
char *save = NULL;
|
||||
char *k = strtok_r(d, "=", &save);
|
||||
char *v_str = strtok_r(NULL, "=", &save);
|
||||
char *follow = strtok_r(NULL, "=", &save);
|
||||
if (k == NULL || v_str == NULL || follow != NULL) {
|
||||
err = EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
u_longlong_t val = strtoull(v_str, NULL, 0);
|
||||
if (val > UINT32_MAX) {
|
||||
fprintf(stderr, "Value for global variable '%s' must "
|
||||
"be a 32-bit unsigned integer, got '%s'\n", k, v_str);
|
||||
err = EOVERFLOW;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
*k_out = strdup(k);
|
||||
*v_out = val;
|
||||
free(d);
|
||||
return (0);
|
||||
|
||||
err_free:
|
||||
free(d);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets given global variable in libzpool to given unsigned 32-bit value.
|
||||
* arg: "<variable>=<value>"
|
||||
* Common helper for working with libzpool tunables from the command line.
|
||||
*
|
||||
* Valid inputs:
|
||||
*
|
||||
* <name> show named tunable and value
|
||||
* <name>=<value> set tunable value
|
||||
*
|
||||
* show show all tunables and values
|
||||
* show=<name> show named tunable and value
|
||||
* info show info about all tunables
|
||||
* info=<name> show info about named tunable
|
||||
*/
|
||||
int
|
||||
set_global_var(char const *arg)
|
||||
|
||||
typedef enum { SHOW, INFO, SET } tunable_mode_t;
|
||||
|
||||
static int
|
||||
list_tunables_cb(const zfs_tunable_t *tunable, void *arg)
|
||||
{
|
||||
void *zpoolhdl;
|
||||
char *varname;
|
||||
u_longlong_t val;
|
||||
int ret;
|
||||
const tunable_mode_t *mode = arg;
|
||||
|
||||
#ifndef _ZFS_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");
|
||||
ret = ENOTSUP;
|
||||
goto out_ret;
|
||||
#endif
|
||||
|
||||
if ((ret = set_global_var_parse_kv(arg, &varname, &val)) != 0) {
|
||||
goto out_ret;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = EINVAL;
|
||||
goto out_dlclose;
|
||||
}
|
||||
*var = (uint32_t)val;
|
||||
static const char *type[] = {
|
||||
"int", "uint", "ulong", "u64", "str",
|
||||
};
|
||||
static const char *perm[] = {
|
||||
"rw", "rd",
|
||||
};
|
||||
|
||||
if (*mode == SHOW) {
|
||||
char val[64];
|
||||
int err = zfs_tunable_get(tunable, val, sizeof (val));
|
||||
if (err == 0)
|
||||
printf("%s: %s\n", tunable->zt_name, val);
|
||||
else
|
||||
printf("%s: [error getting tunable value: %s]\n",
|
||||
tunable->zt_name, strerror(err));
|
||||
} else {
|
||||
fprintf(stderr, "Failed to open libzpool.so to set global "
|
||||
"variable\n");
|
||||
ret = EIO;
|
||||
goto out_free;
|
||||
printf("%s [%s %s]: %s\n", tunable->zt_name,
|
||||
type[tunable->zt_type], perm[tunable->zt_perm],
|
||||
tunable->zt_desc);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
return (0);
|
||||
}
|
||||
int
|
||||
handle_tunable_option(const char *_arg, boolean_t quiet)
|
||||
{
|
||||
int err = 0;
|
||||
char *arg = strdup(_arg);
|
||||
char *k, *v;
|
||||
|
||||
out_dlclose:
|
||||
dlclose(zpoolhdl);
|
||||
out_free:
|
||||
free(varname);
|
||||
out_ret:
|
||||
return (ret);
|
||||
v = arg;
|
||||
k = strsep(&v, "=");
|
||||
|
||||
tunable_mode_t mode;
|
||||
|
||||
if (strcmp(k, "show") == 0) {
|
||||
mode = SHOW;
|
||||
k = v;
|
||||
} else if (strcmp(k, "info") == 0) {
|
||||
mode = INFO;
|
||||
k = v;
|
||||
} else if (v == NULL) {
|
||||
mode = SHOW;
|
||||
} else {
|
||||
mode = SET;
|
||||
}
|
||||
|
||||
if (quiet && mode != SET) {
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mode == SET) {
|
||||
const zfs_tunable_t *tunable = zfs_tunable_lookup(k);
|
||||
if (tunable == NULL) {
|
||||
err = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
char vold[256], vnew[256];
|
||||
if (zfs_tunable_get(tunable, vold, sizeof (vold)) != 0)
|
||||
strcpy(vold, "???");
|
||||
err = zfs_tunable_set(tunable, v);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
if (zfs_tunable_get(tunable, vnew, sizeof (vnew)) != 0)
|
||||
strcpy(vnew, "???");
|
||||
|
||||
if (!quiet)
|
||||
printf("%s: %s -> %s\n", k, vold, vnew);
|
||||
} else if (k != NULL) {
|
||||
const zfs_tunable_t *tunable = zfs_tunable_lookup(k);
|
||||
if (tunable == NULL) {
|
||||
err = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
list_tunables_cb(tunable, &mode);
|
||||
} else {
|
||||
zfs_tunable_iter(list_tunables_cb, &mode);
|
||||
}
|
||||
|
||||
out:
|
||||
if (!quiet) {
|
||||
if (err == ENOENT)
|
||||
fprintf(stderr, "no such tunable: %s\n", k);
|
||||
else if (err != 0)
|
||||
fprintf(stderr, "couldn't set tunable '%s': %s\n",
|
||||
k, strerror(err));
|
||||
}
|
||||
|
||||
free(arg);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static nvlist_t *
|
||||
|
||||
@ -188,12 +188,8 @@ i.e. given
|
||||
will be loaded.
|
||||
.It Fl C , -vdev-class-state Ns = Ns Sy on Ns | Ns Sy off Ns | Ns Sy random No (default : Sy random )
|
||||
The vdev allocation class state.
|
||||
.It Fl o , -option Ns = Ns Ar variable Ns = Ns Ar value
|
||||
Set global
|
||||
.Ar variable
|
||||
to an unsigned 32-bit integer
|
||||
.Ar value
|
||||
(little-endian only).
|
||||
.It Fl o , -option Ns = Ns Ar var Ns = Ns Ar value Ns …
|
||||
Set the given tunable to the provided value.
|
||||
.It Fl G , -dump-debug
|
||||
Dump zfs_dbgmsg buffer before exiting due to an error.
|
||||
.It Fl V , -verbose
|
||||
|
||||
@ -474,10 +474,15 @@ as it runs.
|
||||
Exercise extreme caution when using this option in shared or uncontrolled
|
||||
environments.
|
||||
.It Fl o , -option Ns = Ns Ar var Ns = Ns Ar value Ns …
|
||||
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.
|
||||
Set the given tunable to the provided value.
|
||||
.It Fl o , -option Ns = Ns Ar var Ns …
|
||||
Show the value of the given tunable.
|
||||
.It Fl o , -option Ns = Ns show
|
||||
Show all tunables and their values.
|
||||
.It Fl o , -option Ns = Ns info Ns = Ns Ar value Ns …
|
||||
Show info about a tunable, including their name, type and description.
|
||||
.It Fl o , -option Ns = Ns info
|
||||
Show info about all tunables.
|
||||
.It Fl P , -parseable
|
||||
Print numbers in an unscaled form more amenable to parsing, e.g.\&
|
||||
.Sy 1000000
|
||||
|
||||
Loading…
Reference in New Issue
Block a user