diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-02-18 12:35:33 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-02-18 12:35:33 +0000 |
commit | 0c627058c79e5867b47468553d9ec113f2616984 (patch) | |
tree | 073180cc3fca117791230d1d6e9c462da998c395 | |
parent | cf1763c352b1bdac07c225b66e1ca15806929e56 (diff) | |
parent | 2e25d8e1fe9b3743d7dec073fd05a9f95fbca2a7 (diff) | |
download | illumos-joyent-0c627058c79e5867b47468553d9ec113f2616984.tar.gz |
[illumos-gate merge]
commit 2e25d8e1fe9b3743d7dec073fd05a9f95fbca2a7
12225 normalize complex float names across compilers
commit f4b3fdc1b1ec48bd52b545ef80d866244e76d91b
12291 python3.8 fails versioning check
commit 94494656088303cd79a8b970e5535468c5f0117d
12307 Fix markup errors in mtx(3C)
commit c40d33be34d8bd92100aad1cfae8c1aaeee375d6
12309 errors in section 9e of the manual
commit 0dc3799518631a169651844259f4357ece16ffa6
12305 typos in dhcp man pages
commit d7ab8532a7a0f65d1c2b7bc3f45072f665860b20
12236 getmembers_DN doesn't properly handle errors from __ns_ldap_dn2uid
12240 nss_ldap does not properly look up group members by distinguished name
commit f5f3cbec075f8308da054292c7c7d96373c956ee
12288 getfacl and setfacl could stand improvement
commit 5642709df07e9b3a809f898f938aac4fc9903255
12211 loader: build with smatch fixes
commit 8b6e4188cd6fe49ddc2ff1e635b9c1538fbd5d48
12303 nfs/nfs4_drc.h: No such file or directory
commit d3879c39d2a534146eaf46dc510b80678ea24023
12181 zvol tests should avoid grep -w
12281 zvol_swap_003_pos shouldn't use swapadd in cleanup
commit b0daad2a8784078aa662f966577891e83a581d3a
12287 errors in audio utility man pages
commit dd50e0cc4cbe1474096300fe52e9855769c0d478
11682 zpool iostat and status improvements
commit 3df9f0641f28754051d5e82c6457527cf4af1258
12227 libctf incorrectly handles clang anonymous unions
commit 6d9e11ccb59a5d4ea2127e1791163333c4337a08
12224 ctfconvert conv backend error missing newline
commit b40354493afafb9870e25372645af933e189b24f
10931 BUILDPY2TOOLS and BUILDPY3TOOLS need to be documented in illumos.sh
Conflicts:
usr/src/uts/common/fs/zfs/zio.c
usr/src/uts/common/fs/zfs/sys/zio.h
93 files changed, 3637 insertions, 1079 deletions
diff --git a/exception_lists/check_rtime b/exception_lists/check_rtime index 250a02a5f9..611b885214 100644 --- a/exception_lists/check_rtime +++ b/exception_lists/check_rtime @@ -156,7 +156,7 @@ UNREF_OBJ /lib.*\ of\ .*libpq\.so\.4 UNREF_OBJ /lib.*\ of\ .*libpython2\.4\.so\.1\.0 UNREF_OBJ /lib.*\ of\ .*libpython2\.6\.so\.1\.0 UNREF_OBJ /lib.*\ of\ .*libpython2\.7\.so\.1\.0 -UNREF_OBJ /lib.*\ of\ .*libpython3\.[567]m?\.so\.1\.0 +UNREF_OBJ /lib.*\ of\ .*libpython3\.[5678]m?\.so\.1\.0 UNREF_OBJ /libgcc_s.*\ of\ .*libstdc\+\+\.so\.6 UNREF_OBJ /libgcc_s.*\ of\ .*libgmodule-2\.0\.so\.0 diff --git a/exception_lists/interface_check b/exception_lists/interface_check index 2d3bf03b69..78e1c95719 100644 --- a/exception_lists/interface_check +++ b/exception_lists/interface_check @@ -58,7 +58,7 @@ PLUGIN ^usr/lib/mdb PLUGIN ^usr/lib/pci PLUGIN ^usr/lib/picl/plugins PLUGIN ^usr/lib/python2.[467] -PLUGIN ^usr/lib/python3.[567] +PLUGIN ^usr/lib/python3.[5678] PLUGIN ^usr/lib/rcm/modules PLUGIN ^usr/lib/scsi/plugins PLUGIN ^usr/lib/sysevent/modules diff --git a/usr/src/boot/sys/boot/Makefile.inc b/usr/src/boot/sys/boot/Makefile.inc index 4d030cdb59..674d41ce23 100644 --- a/usr/src/boot/sys/boot/Makefile.inc +++ b/usr/src/boot/sys/boot/Makefile.inc @@ -62,9 +62,6 @@ SMATCH_ = SMATCH_on = SMATCH_off = -_smatch=off -# smatch does not define __amd64 and __amd64__ -SMATCH_amd64= -_smatch=-D__amd64 -_smatch=-D__amd64__ - # SMATCH_ARGS will bring in set of -Wno-* options. #CFLAGS += $(SMATCH_ARGS:%=-_smatch=%) CFLAGS += $(SMOFF:%=-_smatch=--disable=%) diff --git a/usr/src/boot/sys/x86/include/frame.h b/usr/src/boot/sys/x86/include/frame.h index fb2285f80f..29ba8961c3 100644 --- a/usr/src/boot/sys/x86/include/frame.h +++ b/usr/src/boot/sys/x86/include/frame.h @@ -40,7 +40,7 @@ * System stack frames. */ -#ifdef __i386__ +#if defined(__i386__) && !defined(__amd64__) /* * Exception/Trap Stack Frame */ diff --git a/usr/src/boot/sys/x86/include/signal.h b/usr/src/boot/sys/x86/include/signal.h index dee908f82b..180b07c75b 100644 --- a/usr/src/boot/sys/x86/include/signal.h +++ b/usr/src/boot/sys/x86/include/signal.h @@ -45,7 +45,7 @@ #include <machine/trap.h> /* codes for SIGILL, SIGFPE */ #endif -#ifdef __i386__ +#if defined(__i386__) && !defined(__amd64__) typedef int sig_atomic_t; #if __BSD_VISIBLE diff --git a/usr/src/cmd/ctfconvert/ctfconvert.c b/usr/src/cmd/ctfconvert/ctfconvert.c index 2633207693..0e37d070f1 100644 --- a/usr/src/cmd/ctfconvert/ctfconvert.c +++ b/usr/src/cmd/ctfconvert/ctfconvert.c @@ -334,7 +334,7 @@ main(int argc, char *argv[]) (void) unlink(infile); if (err == ECTF_CONVBKERR || err == ECTF_CONVNODEBUG) { - ctfconvert_fatal("%s", buf); + ctfconvert_fatal("%s\n", buf); } else { ctfconvert_fatal("CTF conversion failed: %s\n", ctf_errmsg(err)); diff --git a/usr/src/cmd/getfacl/Makefile b/usr/src/cmd/getfacl/Makefile index 8166d04252..77088ad160 100644 --- a/usr/src/cmd/getfacl/Makefile +++ b/usr/src/cmd/getfacl/Makefile @@ -23,22 +23,19 @@ # Copyright (c) 1993,2001 by Sun Microsystems, Inc. # All rights reserved. # +# Copyright 2020 Peter Tribble. +# PROG= getfacl include ../Makefile.cmd -CERRWARN += -_gcc=-Wno-unused-variable -CERRWARN += $(CNOWARN_UNINIT) - .KEEP_STATE: -all: $(PROG) +all: $(PROG) install: all $(ROOTPROG) clean: -lint: lint_PROG - include ../Makefile.targ diff --git a/usr/src/cmd/getfacl/getfacl.c b/usr/src/cmd/getfacl/getfacl.c index 3310274c12..337a09a960 100644 --- a/usr/src/cmd/getfacl/getfacl.c +++ b/usr/src/cmd/getfacl/getfacl.c @@ -21,14 +21,9 @@ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2020 Peter Tribble. */ -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifndef lint -static char sccsid[] = "%Z%%M% %I% %E% SMI"; -#endif - /* * getfacl [-ad] file ... * This command displays discretionary information for a file or files. @@ -73,7 +68,7 @@ main(int argc, char *argv[]) int errflag = 0; int savecnt; int aclcnt; - int mask; + int mask = 0; aclent_t *aclp; aclent_t *tp; char *permp; @@ -116,7 +111,7 @@ main(int argc, char *argv[]) gettext("File system doesn't support " "aclent_t style ACL's.\n" "See acl(5) for more information on " - "Solaris ACL support.\n")); + "POSIX-draft ACL support.\n")); exit(2); } perror(filep); diff --git a/usr/src/cmd/setfacl/Makefile b/usr/src/cmd/setfacl/Makefile index 5f70a8f4de..503676079f 100644 --- a/usr/src/cmd/setfacl/Makefile +++ b/usr/src/cmd/setfacl/Makefile @@ -23,18 +23,12 @@ # Copyright (c) 1993 by Sun Microsystems, Inc. # # Copyright (c) 2018, Joyent, Inc. - +# Copyright 2020 Peter Tribble. +# PROG= setfacl include ../Makefile.cmd -CERRWARN += -_gcc=-Wno-unused-variable -CERRWARN += -_gcc=-Wno-implicit-function-declaration -CERRWARN += $(CNOWARN_UNINIT) - -# not linted -SMATCH=off - LDLIBS += -lsec .KEEP_STATE: @@ -45,6 +39,4 @@ install: all $(ROOTPROG) clean: -lint: lint_PROG - include ../Makefile.targ diff --git a/usr/src/cmd/setfacl/setfacl.c b/usr/src/cmd/setfacl/setfacl.c index 54e7fa6d2c..d069945661 100644 --- a/usr/src/cmd/setfacl/setfacl.c +++ b/usr/src/cmd/setfacl/setfacl.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2020 Peter Tribble. */ /* @@ -41,6 +42,7 @@ #include <sys/types.h> #include <unistd.h> #include <errno.h> +#include <ctype.h> #define ADD 1 #define MODIFY 2 @@ -70,7 +72,7 @@ main(int argc, char *argv[]) int errflag = 0; int aclcnt; /* used by -m -d */ aclent_t *aclp; /* used by -m -d */ - char *aclfilep; /* acl file argument */ + char *aclfilep = NULL; /* acl file argument */ char *d_entryp = NULL; /* ptr to del entry list */ char *m_entryp = NULL; /* ptr to mod entry list */ char *s_entryp = NULL; /* ptr to set entry list */ @@ -198,8 +200,8 @@ get_acl_info(char *filep, aclent_t **aclpp) (void) fprintf(stderr, gettext("File system doesn't support aclent_t " "style ACL's.\n" - "See acl(5) for more information on" - " ACL styles support by Solaris.\n")); + "See acl(5) for more information on " + "POSIX-draft ACL support.\n")); return (-1); } (void) fprintf(stderr, @@ -237,10 +239,8 @@ get_acl_info(char *filep, aclent_t **aclpp) */ static int mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp, - char *fnamep, int rfg) + char *fnamep, int rfg) { - int rc; /* return code */ - /* modify and add: from -m option */ if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1) return (-1); @@ -342,7 +342,6 @@ set_file_entries(char *acl_fnamep, char *fnamep, int rflag) static int set_online_entries(char *setp, char *fnamep, int rflag) { - char *commap; aclent_t *aclp; int aclcnt = 0; @@ -414,17 +413,6 @@ convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode) if (entryp == NULL) return (0); - if (*cntp > 1) - new_aclp = (aclent_t *)realloc(*aclpp, - sizeof (aclent_t) * (*cntp)); - else - new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp)); - if (new_aclp == NULL) { - fprintf(stderr, - gettext("Insufficient memory for acl %d\n"), *cntp); - return (-1); - } - tmpacl.a_id = 0; /* id field needs to be initialized */ if (entryp[0] == 'u') tmpacl.a_id = getuid(); /* id field for user */ @@ -442,6 +430,17 @@ convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode) (tmpacl.a_type == DEF_GROUP_OBJ) || (tmpacl.a_type == DEF_OTHER_OBJ)); + if (*cntp > 1) + new_aclp = (aclent_t *)realloc(*aclpp, + sizeof (aclent_t) * (*cntp)); + else + new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp)); + if (new_aclp == NULL) { + fprintf(stderr, + gettext("Insufficient memory for acl %d\n"), *cntp); + return (-1); + } + cur_cnt = *cntp - 1; switch (mode) { case MODIFY: /* and add */ @@ -520,7 +519,7 @@ convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode) if (centry != NULL && gentry != NULL && trivial == B_TRUE) centry->a_perm = gentry->a_perm; } - *aclpp = new_aclp; /* return new acl entries */ + *aclpp = new_aclp; /* return new acl entries */ return (0); } diff --git a/usr/src/cmd/zpool/Makefile b/usr/src/cmd/zpool/Makefile index 55d8abc80f..4b7e6600c8 100644 --- a/usr/src/cmd/zpool/Makefile +++ b/usr/src/cmd/zpool/Makefile @@ -40,7 +40,8 @@ STAT_COMMON_OBJS = timestamp.o STAT_COMMON_SRCS = $(STAT_COMMON_OBJS:%.o=$(STATCOMMONDIR)/%.c) SRCS += $(STAT_COMMON_SRCS) -LDLIBS += -lzfs -lnvpair -ldevid -lefi -ldiskmgt -luutil -lumem -lzutil +LDLIBS += -lzfs -lnvpair -ldevid -lefi -ldiskmgt -luutil -lumem -lzutil \ + -lm -lzpool INCS += -I../../common/zfs -I../../uts/common/fs/zfs -I$(STATCOMMONDIR) INCS += -I../../lib/libzutil/common diff --git a/usr/src/cmd/zpool/zpool_iter.c b/usr/src/cmd/zpool/zpool_iter.c index c05c665ada..e69f9778e0 100644 --- a/usr/src/cmd/zpool/zpool_iter.c +++ b/usr/src/cmd/zpool/zpool_iter.c @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> #include <strings.h> +#include <sys/sysmacros.h> #include <libzfs.h> #include <libzutil.h> @@ -253,3 +254,69 @@ for_each_pool(int argc, char **argv, boolean_t unavail, return (ret); } + +static int +for_each_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, pool_vdev_iter_f func, + void *data) +{ + nvlist_t **child; + uint_t c, children; + int ret = 0; + int i; + char *type; + + const char *list[] = { + ZPOOL_CONFIG_SPARES, + ZPOOL_CONFIG_L2CACHE, + ZPOOL_CONFIG_CHILDREN + }; + + for (i = 0; i < ARRAY_SIZE(list); i++) { + if (nvlist_lookup_nvlist_array(nv, list[i], &child, + &children) == 0) { + for (c = 0; c < children; c++) { + uint64_t ishole = 0; + + (void) nvlist_lookup_uint64(child[c], + ZPOOL_CONFIG_IS_HOLE, &ishole); + + if (ishole) + continue; + + ret |= for_each_vdev_cb(zhp, child[c], func, + data); + } + } + } + + if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) + return (ret); + + /* Don't run our function on root vdevs */ + if (strcmp(type, VDEV_TYPE_ROOT) != 0) { + ret |= func(zhp, nv, data); + } + + return (ret); +} + +/* + * This is the equivalent of for_each_pool() for vdevs. It iterates thorough + * all vdevs in the pool, ignoring root vdevs and holes, calling func() on + * each one. + * + * @zhp: Zpool handle + * @func: Function to call on each vdev + * @data: Custom data to pass to the function + */ +int +for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data) +{ + nvlist_t *config, *nvroot; + + if ((config = zpool_get_config(zhp, NULL)) != NULL) { + verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, + &nvroot) == 0); + } + return (for_each_vdev_cb(zhp, nvroot, func, data)); +} diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c index 93df0e1772..7242a156c7 100644 --- a/usr/src/cmd/zpool/zpool_main.c +++ b/usr/src/cmd/zpool/zpool_main.c @@ -30,7 +30,7 @@ * Copyright (c) 2017 Datto Inc. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com> - * Copyright 2019 Joyent, Inc. + * Copyright 2020 Joyent, Inc. * Copyright (c) 2012 by Cyril Plisko. All rights reserved. * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ @@ -57,6 +57,9 @@ #include <sys/fs/zfs.h> #include <sys/stat.h> #include <sys/debug.h> +#include <math.h> +#include <sys/sysmacros.h> +#include <sys/termios.h> #include <libzfs.h> #include <libzutil.h> @@ -161,6 +164,85 @@ typedef enum { } zpool_help_t; +/* + * Flags for stats to display with "zpool iostats" + */ +enum iostat_type { + IOS_DEFAULT = 0, + IOS_LATENCY = 1, + IOS_QUEUES = 2, + IOS_L_HISTO = 3, + IOS_RQ_HISTO = 4, + IOS_COUNT, /* always last element */ +}; + +/* iostat_type entries as bitmasks */ +#define IOS_DEFAULT_M (1ULL << IOS_DEFAULT) +#define IOS_LATENCY_M (1ULL << IOS_LATENCY) +#define IOS_QUEUES_M (1ULL << IOS_QUEUES) +#define IOS_L_HISTO_M (1ULL << IOS_L_HISTO) +#define IOS_RQ_HISTO_M (1ULL << IOS_RQ_HISTO) + +/* Mask of all the histo bits */ +#define IOS_ANYHISTO_M (IOS_L_HISTO_M | IOS_RQ_HISTO_M) + +/* + * Lookup table for iostat flags to nvlist names. Basically a list + * of all the nvlists a flag requires. Also specifies the order in + * which data gets printed in zpool iostat. + */ +static const char *vsx_type_to_nvlist[IOS_COUNT][13] = { + [IOS_L_HISTO] = { + ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO, + NULL}, + [IOS_LATENCY] = { + ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO, + NULL}, + [IOS_QUEUES] = { + ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE, + NULL}, + [IOS_RQ_HISTO] = { + ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO, + ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO, + ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO, + ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO, + ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO, + NULL}, +}; + + +/* + * Given a cb->cb_flags with a histogram bit set, return the iostat_type. + * Right now, only one histo bit is ever set at one time, so we can + * just do a highbit64(a) + */ +#define IOS_HISTO_IDX(a) (highbit64(a & IOS_ANYHISTO_M) - 1) + typedef struct zpool_command { const char *name; int (*func)(int, char **); @@ -217,7 +299,7 @@ static zpool_command_t command_table[] = { { "sync", zpool_do_sync, HELP_SYNC }, }; -#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) +#define NCOMMAND (ARRAY_SIZE(command_table)) #define VDEV_ALLOC_CLASS_LOGS "logs" @@ -266,8 +348,10 @@ get_usage(zpool_help_t idx) "[-R root] [-F [-n]] [-t]\n" "\t [--rewind-to-checkpoint] <pool | id> [newpool]\n")); case HELP_IOSTAT: - return (gettext("\tiostat [-gLPv] [-T d|u] [pool] ... " - "[interval [count]]\n")); + return (gettext("\tiostat " + "[[-lq]|[-rw]] [-T d | u] [-ghHLpPvy]\n" + "\t [pool] ..." + " [[-n] interval [count]]\n")); case HELP_LABELCLEAR: return (gettext("\tlabelclear [-f] <vdev>\n")); case HELP_LIST: @@ -295,7 +379,8 @@ get_usage(zpool_help_t idx) return (gettext("\ttrim [-d] [-r <rate>] [-c | -s] <pool> " "[<device> ...]\n")); case HELP_STATUS: - return (gettext("\tstatus [-igLPvxD] [-T d|u] [pool] ... " + return (gettext("\tstatus " + "[-igLpPsvxD] [-T d|u] [pool] ... " "[interval [count]]\n")); case HELP_UPGRADE: return (gettext("\tupgrade\n" @@ -1622,10 +1707,12 @@ typedef struct status_cbdata { int cb_namewidth; boolean_t cb_allpools; boolean_t cb_verbose; + boolean_t cb_literal; boolean_t cb_explain; boolean_t cb_first; boolean_t cb_dedup_stats; boolean_t cb_print_status; + boolean_t cb_print_slow_ios; boolean_t cb_print_vdev_init; boolean_t cb_print_vdev_trim; } status_cbdata_t; @@ -1779,10 +1866,34 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, name, state); if (!isspare) { - zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); - zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); - zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); - (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); + if (cb->cb_literal) { + printf(" %5llu %5llu %5llu", + (u_longlong_t)vs->vs_read_errors, + (u_longlong_t)vs->vs_write_errors, + (u_longlong_t)vs->vs_checksum_errors); + } else { + zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); + zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); + zfs_nicenum(vs->vs_checksum_errors, cbuf, + sizeof (cbuf)); + printf(" %5s %5s %5s", rbuf, wbuf, cbuf); + } + + if (cb->cb_print_slow_ios) { + if (children == 0) { + /* Only leafs vdevs have slow IOs */ + zfs_nicenum(vs->vs_slow_ios, rbuf, + sizeof (rbuf)); + } else { + (void) snprintf(rbuf, sizeof (rbuf), "-"); + } + + if (cb->cb_literal) + printf(" %5llu", (u_longlong_t)vs->vs_slow_ios); + else + printf(" %5s", rbuf); + } + } if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, @@ -2383,7 +2494,8 @@ show_import(nvlist_t *config) (void) printf(gettext(" config:\n\n")); - cb.cb_namewidth = max_width(NULL, nvroot, 0, 0, 0); + cb.cb_namewidth = max_width(NULL, nvroot, 0, strlen(name), + VDEV_NAME_TYPE_ID); if (cb.cb_namewidth < 10) cb.cb_namewidth = 10; @@ -3115,44 +3227,737 @@ zpool_do_sync(int argc, char **argv) } typedef struct iostat_cbdata { - boolean_t cb_verbose; + uint64_t cb_flags; int cb_name_flags; int cb_namewidth; int cb_iteration; + char **cb_vdev_names; /* Only show these vdevs */ + unsigned int cb_vdev_names_count; + boolean_t cb_verbose; + boolean_t cb_literal; boolean_t cb_scripted; zpool_list_t *cb_list; } iostat_cbdata_t; +/* iostat labels */ +typedef struct name_and_columns { + const char *name; /* Column name */ + unsigned int columns; /* Center name to this number of columns */ +} name_and_columns_t; + +#define IOSTAT_MAX_LABELS 13 /* Max number of labels on one line */ + +static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] = +{ + [IOS_DEFAULT] = {{"capacity", 2}, {"operations", 2}, {"bandwidth", 2}, + {NULL}}, + [IOS_LATENCY] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2}, + {"asyncq_wait", 2}, {"scrub"}, {"trim", 1}, {NULL}}, + [IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2}, + {"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2}, + {"trimq_write", 2}, {NULL}}, + [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2}, + {"asyncq_wait", 2}, {NULL}}, + [IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2}, + {"async_read", 2}, {"async_write", 2}, {"scrub", 2}, + {"trim", 2}, {NULL}}, + +}; + +/* Shorthand - if "columns" field not set, default to 1 column */ +static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] = +{ + [IOS_DEFAULT] = {{"alloc"}, {"free"}, {"read"}, {"write"}, {"read"}, + {"write"}, {NULL}}, + [IOS_LATENCY] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"}, + {"write"}, {"read"}, {"write"}, {"wait"}, {"wait"}, {NULL}}, + [IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"}, + {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, + {"pend"}, {"activ"}, {NULL}}, + [IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"}, + {"write"}, {"read"}, {"write"}, {"scrub"}, {"trim"}, {NULL}}, + [IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, + {"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}}, +}; + +static const char *histo_to_title[] = { + [IOS_L_HISTO] = "latency", + [IOS_RQ_HISTO] = "req_size", +}; + +/* + * Return the number of labels in a null-terminated name_and_columns_t + * array. + * + */ +static unsigned int +label_array_len(const name_and_columns_t *labels) +{ + int i = 0; + + while (labels[i].name) + i++; + + return (i); +} + +/* + * Return the number of strings in a null-terminated string array. + * For example: + * + * const char foo[] = {"bar", "baz", NULL} + * + * returns 2 + */ +static uint64_t +str_array_len(const char *array[]) +{ + uint64_t i = 0; + while (array[i]) + i++; + + return (i); +} + + +/* + * Return a default column width for default/latency/queue columns. This does + * not include histograms, which have their columns autosized. + */ +static unsigned int +default_column_width(iostat_cbdata_t *cb, enum iostat_type type) +{ + unsigned long column_width = 5; /* Normal niceprint */ + static unsigned long widths[] = { + /* + * Choose some sane default column sizes for printing the + * raw numbers. + */ + [IOS_DEFAULT] = 15, /* 1PB capacity */ + [IOS_LATENCY] = 10, /* 1B ns = 10sec */ + [IOS_QUEUES] = 6, /* 1M queue entries */ + [IOS_L_HISTO] = 10, /* 1B ns = 10sec */ + [IOS_RQ_HISTO] = 6, /* 1M queue entries */ + }; + + if (cb->cb_literal) + column_width = widths[type]; + + return (column_width); +} + +/* + * Print the column labels, i.e: + * + * capacity operations bandwidth + * alloc free read write read write ... + * + * If force_column_width is set, use it for the column width. If not set, use + * the default column width. + */ +void +print_iostat_labels(iostat_cbdata_t *cb, unsigned int force_column_width, + const name_and_columns_t labels[][IOSTAT_MAX_LABELS]) +{ + int i, idx, s; + int text_start, rw_column_width, spaces_to_end; + uint64_t flags = cb->cb_flags; + uint64_t f; + unsigned int column_width = force_column_width; + + /* For each bit set in flags */ + for (f = flags; f; f &= ~(1ULL << idx)) { + idx = lowbit64(f) - 1; + if (!force_column_width) + column_width = default_column_width(cb, idx); + /* Print our top labels centered over "read write" label. */ + for (i = 0; i < label_array_len(labels[idx]); i++) { + const char *name = labels[idx][i].name; + /* + * We treat labels[][].columns == 0 as shorthand + * for one column. It makes writing out the label + * tables more concise. + */ + unsigned int columns = MAX(1, labels[idx][i].columns); + unsigned int slen = strlen(name); + + rw_column_width = (column_width * columns) + + (2 * (columns - 1)); + + text_start = (int)((rw_column_width) / columns - + slen / columns); + if (text_start < 0) + text_start = 0; + + printf(" "); /* Two spaces between columns */ + + /* Space from beginning of column to label */ + for (s = 0; s < text_start; s++) + printf(" "); + + printf("%s", name); + + /* Print space after label to end of column */ + spaces_to_end = rw_column_width - text_start - slen; + if (spaces_to_end < 0) + spaces_to_end = 0; + + for (s = 0; s < spaces_to_end; s++) + printf(" "); + } + } +} + +/* + * Utility function to print out a line of dashes like: + * + * -------------------------------- ----- ----- ----- ----- ----- + * + * ...or a dashed named-row line like: + * + * logs - - - - - + * + * @cb: iostat data + * + * @force_column_width If non-zero, use the value as the column width. + * Otherwise use the default column widths. + * + * @name: Print a dashed named-row line starting + * with @name. Otherwise, print a regular + * dashed line. + */ +static void +print_iostat_dashes(iostat_cbdata_t *cb, unsigned int force_column_width, + const char *name) +{ + int i; + unsigned int namewidth; + uint64_t flags = cb->cb_flags; + uint64_t f; + int idx; + const name_and_columns_t *labels; + const char *title; + + + if (cb->cb_flags & IOS_ANYHISTO_M) { + title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]; + } else if (cb->cb_vdev_names_count) { + title = "vdev"; + } else { + title = "pool"; + } + + namewidth = MAX(MAX(strlen(title), cb->cb_namewidth), + name ? strlen(name) : 0); + + + if (name) { + printf("%-*s", namewidth, name); + } else { + for (i = 0; i < namewidth; i++) + (void) printf("-"); + } + + /* For each bit in flags */ + for (f = flags; f; f &= ~(1ULL << idx)) { + unsigned int column_width; + idx = lowbit64(f) - 1; + if (force_column_width) + column_width = force_column_width; + else + column_width = default_column_width(cb, idx); + + labels = iostat_bottom_labels[idx]; + for (i = 0; i < label_array_len(labels); i++) { + if (name) + printf(" %*s-", column_width - 1, " "); + else + printf(" %.*s", column_width, + "--------------------"); + } + } +} + + +static void +print_iostat_separator_impl(iostat_cbdata_t *cb, + unsigned int force_column_width) +{ + print_iostat_dashes(cb, force_column_width, NULL); +} + static void print_iostat_separator(iostat_cbdata_t *cb) { - int i = 0; + print_iostat_separator_impl(cb, 0); +} + +static void +print_iostat_header_impl(iostat_cbdata_t *cb, unsigned int force_column_width, + const char *histo_vdev_name) +{ + unsigned int namewidth; + const char *title; + + if (cb->cb_flags & IOS_ANYHISTO_M) { + title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]; + } else if (cb->cb_vdev_names_count) { + title = "vdev"; + } else { + title = "pool"; + } + + namewidth = MAX(MAX(strlen(title), cb->cb_namewidth), + histo_vdev_name ? strlen(histo_vdev_name) : 0); + + if (histo_vdev_name) + printf("%-*s", namewidth, histo_vdev_name); + else + printf("%*s", namewidth, ""); - for (i = 0; i < cb->cb_namewidth; i++) - (void) printf("-"); - (void) printf(" ----- ----- ----- ----- ----- -----\n"); + + print_iostat_labels(cb, force_column_width, iostat_top_labels); + printf("\n"); + + printf("%-*s", namewidth, title); + + print_iostat_labels(cb, force_column_width, iostat_bottom_labels); + + printf("\n"); + + print_iostat_separator_impl(cb, force_column_width); + + printf("\n"); } static void print_iostat_header(iostat_cbdata_t *cb) { - (void) printf("%*s capacity operations bandwidth\n", - cb->cb_namewidth, ""); - (void) printf("%-*s alloc free read write read write\n", - cb->cb_namewidth, "pool"); - print_iostat_separator(cb); + print_iostat_header_impl(cb, 0, NULL); } /* * Display a single statistic. */ static void -print_one_stat(uint64_t value) +print_one_stat(uint64_t value, enum zfs_nicenum_format format, + unsigned int column_size, boolean_t scripted) { char buf[64]; - zfs_nicenum(value, buf, sizeof (buf)); - (void) printf(" %5s", buf); + zfs_nicenum_format(value, buf, sizeof (buf), format); + + if (scripted) + printf("\t%s", buf); + else + printf(" %*s", column_size, buf); +} + +/* + * Calculate the default vdev stats + * + * Subtract oldvs from newvs, apply a scaling factor, and save the resulting + * stats into calcvs. + */ +static void +calc_default_iostats(vdev_stat_t *oldvs, vdev_stat_t *newvs, + vdev_stat_t *calcvs) +{ + int i; + + memcpy(calcvs, newvs, sizeof (*calcvs)); + for (i = 0; i < ARRAY_SIZE(calcvs->vs_ops); i++) + calcvs->vs_ops[i] = (newvs->vs_ops[i] - oldvs->vs_ops[i]); + + for (i = 0; i < ARRAY_SIZE(calcvs->vs_bytes); i++) + calcvs->vs_bytes[i] = (newvs->vs_bytes[i] - oldvs->vs_bytes[i]); +} + +/* + * Internal representation of the extended iostats data. + * + * The extended iostat stats are exported in nvlists as either uint64_t arrays + * or single uint64_t's. We make both look like arrays to make them easier + * to process. In order to make single uint64_t's look like arrays, we set + * __data to the stat data, and then set *data = &__data with count = 1. Then, + * we can just use *data and count. + */ +struct stat_array { + uint64_t *data; + uint_t count; /* Number of entries in data[] */ + uint64_t __data; /* Only used when data is a single uint64_t */ +}; + +static uint64_t +stat_histo_max(struct stat_array *nva, unsigned int len) +{ + uint64_t max = 0; + int i; + for (i = 0; i < len; i++) + max = MAX(max, array64_max(nva[i].data, nva[i].count)); + + return (max); +} + +/* + * Helper function to lookup a uint64_t array or uint64_t value and store its + * data as a stat_array. If the nvpair is a single uint64_t value, then we make + * it look like a one element array to make it easier to process. + */ +static int +nvpair64_to_stat_array(nvlist_t *nvl, const char *name, + struct stat_array *nva) +{ + nvpair_t *tmp; + int ret; + + verify(nvlist_lookup_nvpair(nvl, name, &tmp) == 0); + switch (nvpair_type(tmp)) { + case DATA_TYPE_UINT64_ARRAY: + ret = nvpair_value_uint64_array(tmp, &nva->data, &nva->count); + break; + case DATA_TYPE_UINT64: + ret = nvpair_value_uint64(tmp, &nva->__data); + nva->data = &nva->__data; + nva->count = 1; + break; + default: + /* Not a uint64_t */ + ret = EINVAL; + break; + } + + return (ret); +} + +/* + * Given a list of nvlist names, look up the extended stats in newnv and oldnv, + * subtract them, and return the results in a newly allocated stat_array. + * You must free the returned array after you are done with it with + * free_calc_stats(). + * + * Additionally, you can set "oldnv" to NULL if you simply want the newnv + * values. + */ +static struct stat_array * +calc_and_alloc_stats_ex(const char **names, unsigned int len, nvlist_t *oldnv, + nvlist_t *newnv) +{ + nvlist_t *oldnvx = NULL, *newnvx; + struct stat_array *oldnva, *newnva, *calcnva; + int i, j; + unsigned int alloc_size = (sizeof (struct stat_array)) * len; + + /* Extract our extended stats nvlist from the main list */ + verify(nvlist_lookup_nvlist(newnv, ZPOOL_CONFIG_VDEV_STATS_EX, + &newnvx) == 0); + if (oldnv) { + verify(nvlist_lookup_nvlist(oldnv, ZPOOL_CONFIG_VDEV_STATS_EX, + &oldnvx) == 0); + } + + newnva = safe_malloc(alloc_size); + oldnva = safe_malloc(alloc_size); + calcnva = safe_malloc(alloc_size); + + for (j = 0; j < len; j++) { + verify(nvpair64_to_stat_array(newnvx, names[j], + &newnva[j]) == 0); + calcnva[j].count = newnva[j].count; + alloc_size = calcnva[j].count * sizeof (calcnva[j].data[0]); + calcnva[j].data = safe_malloc(alloc_size); + memcpy(calcnva[j].data, newnva[j].data, alloc_size); + + if (oldnvx) { + verify(nvpair64_to_stat_array(oldnvx, names[j], + &oldnva[j]) == 0); + for (i = 0; i < oldnva[j].count; i++) + calcnva[j].data[i] -= oldnva[j].data[i]; + } + } + free(newnva); + free(oldnva); + return (calcnva); +} + +static void +free_calc_stats(struct stat_array *nva, unsigned int len) +{ + int i; + for (i = 0; i < len; i++) + free(nva[i].data); + + free(nva); +} + +static void +print_iostat_histo(struct stat_array *nva, unsigned int len, + iostat_cbdata_t *cb, unsigned int column_width, unsigned int namewidth, + double scale) +{ + int i, j; + char buf[6]; + uint64_t val; + enum zfs_nicenum_format format; + unsigned int buckets; + unsigned int start_bucket; + + if (cb->cb_literal) + format = ZFS_NICENUM_RAW; + else + format = ZFS_NICENUM_1024; + + /* All these histos are the same size, so just use nva[0].count */ + buckets = nva[0].count; + + if (cb->cb_flags & IOS_RQ_HISTO_M) { + /* Start at 512 - req size should never be lower than this */ + start_bucket = 9; + } else { + start_bucket = 0; + } + + for (j = start_bucket; j < buckets; j++) { + /* Print histogram bucket label */ + if (cb->cb_flags & IOS_L_HISTO_M) { + /* Ending range of this bucket */ + val = (1ULL << (j + 1)) - 1; + zfs_nicetime(val, buf, sizeof (buf)); + } else { + /* Request size (starting range of bucket) */ + val = (1UL << j); + zfs_nicenum(val, buf, sizeof (buf)); + } + + if (cb->cb_scripted) + printf("%llu", (u_longlong_t)val); + else + printf("%-*s", namewidth, buf); + + /* Print the values on the line */ + for (i = 0; i < len; i++) { + print_one_stat(nva[i].data[j] * scale, format, + column_width, cb->cb_scripted); + } + printf("\n"); + } +} + +static void +print_solid_separator(unsigned int length) +{ + while (length--) + printf("-"); + printf("\n"); +} + +static void +print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv, + nvlist_t *newnv, double scale, const char *name) +{ + unsigned int column_width; + unsigned int namewidth; + unsigned int entire_width; + enum iostat_type type; + struct stat_array *nva; + const char **names; + unsigned int names_len; + + /* What type of histo are we? */ + type = IOS_HISTO_IDX(cb->cb_flags); + + /* Get NULL-terminated array of nvlist names for our histo */ + names = vsx_type_to_nvlist[type]; + names_len = str_array_len(names); /* num of names */ + + nva = calc_and_alloc_stats_ex(names, names_len, oldnv, newnv); + + if (cb->cb_literal) { + column_width = MAX(5, + (unsigned int) log10(stat_histo_max(nva, names_len)) + 1); + } else { + column_width = 5; + } + + namewidth = MAX(cb->cb_namewidth, + strlen(histo_to_title[IOS_HISTO_IDX(cb->cb_flags)])); + + /* + * Calculate the entire line width of what we're printing. The + * +2 is for the two spaces between columns: + */ + /* read write */ + /* ----- ----- */ + /* |___| <---------- column_width */ + /* */ + /* |__________| <--- entire_width */ + /* */ + entire_width = namewidth + (column_width + 2) * + label_array_len(iostat_bottom_labels[type]); + + if (cb->cb_scripted) + printf("%s\n", name); + else + print_iostat_header_impl(cb, column_width, name); + + print_iostat_histo(nva, names_len, cb, column_width, + namewidth, scale); + + free_calc_stats(nva, names_len); + if (!cb->cb_scripted) + print_solid_separator(entire_width); +} + +/* + * Calculate the average latency of a power-of-two latency histogram + */ +static uint64_t +single_histo_average(uint64_t *histo, unsigned int buckets) +{ + int i; + uint64_t count = 0, total = 0; + + for (i = 0; i < buckets; i++) { + /* + * Our buckets are power-of-two latency ranges. Use the + * midpoint latency of each bucket to calculate the average. + * For example: + * + * Bucket Midpoint + * 8ns-15ns: 12ns + * 16ns-31ns: 24ns + * ... + */ + if (histo[i] != 0) { + total += histo[i] * (((1UL << i) + ((1UL << i)/2))); + count += histo[i]; + } + } + + /* Prevent divide by zero */ + return (count == 0 ? 0 : total / count); +} + +static void +print_iostat_queues(iostat_cbdata_t *cb, nvlist_t *oldnv, + nvlist_t *newnv) +{ + int i; + uint64_t val; + const char *names[] = { + ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE, + ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE, + }; + + struct stat_array *nva; + + unsigned int column_width = default_column_width(cb, IOS_QUEUES); + enum zfs_nicenum_format format; + + nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), NULL, newnv); + + if (cb->cb_literal) + format = ZFS_NICENUM_RAW; + else + format = ZFS_NICENUM_1024; + + for (i = 0; i < ARRAY_SIZE(names); i++) { + val = nva[i].data[0]; + print_one_stat(val, format, column_width, cb->cb_scripted); + } + + free_calc_stats(nva, ARRAY_SIZE(names)); +} + +static void +print_iostat_latency(iostat_cbdata_t *cb, nvlist_t *oldnv, + nvlist_t *newnv) +{ + int i; + uint64_t val; + const char *names[] = { + ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO, + }; + struct stat_array *nva; + + unsigned int column_width = default_column_width(cb, IOS_LATENCY); + enum zfs_nicenum_format format; + + nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), oldnv, newnv); + + if (cb->cb_literal) + format = ZFS_NICENUM_RAWTIME; + else + format = ZFS_NICENUM_TIME; + + /* Print our avg latencies on the line */ + for (i = 0; i < ARRAY_SIZE(names); i++) { + /* Compute average latency for a latency histo */ + val = single_histo_average(nva[i].data, nva[i].count); + print_one_stat(val, format, column_width, cb->cb_scripted); + } + free_calc_stats(nva, ARRAY_SIZE(names)); +} + +/* + * Print default statistics (capacity/operations/bandwidth) + */ +static void +print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale) +{ + unsigned int column_width = default_column_width(cb, IOS_DEFAULT); + enum zfs_nicenum_format format; + char na; /* char to print for "not applicable" values */ + + if (cb->cb_literal) { + format = ZFS_NICENUM_RAW; + na = '0'; + } else { + format = ZFS_NICENUM_1024; + na = '-'; + } + + /* only toplevel vdevs have capacity stats */ + if (vs->vs_space == 0) { + if (cb->cb_scripted) + printf("\t%c\t%c", na, na); + else + printf(" %*c %*c", column_width, na, column_width, + na); + } else { + print_one_stat(vs->vs_alloc, format, column_width, + cb->cb_scripted); + print_one_stat(vs->vs_space - vs->vs_alloc, format, + column_width, cb->cb_scripted); + } + + print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_READ] * scale), + format, column_width, cb->cb_scripted); + print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_WRITE] * scale), + format, column_width, cb->cb_scripted); + print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_READ] * scale), + format, column_width, cb->cb_scripted); + print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_WRITE] * scale), + format, column_width, cb->cb_scripted); } static const char *class_name[] = { @@ -3165,21 +3970,27 @@ static const char *class_name[] = { * Print out all the statistics for the given vdev. This can either be the * toplevel configuration, or called recursively. If 'name' is NULL, then this * is a verbose output, and we don't want to display the toplevel pool stats. + * + * Returns the number of stat lines printed. */ -static void +unsigned int print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, nvlist_t *newnv, iostat_cbdata_t *cb, int depth) { nvlist_t **oldchild, **newchild; - uint_t c, children; - vdev_stat_t *oldvs, *newvs; + uint_t c, children, oldchildren; + vdev_stat_t *oldvs, *newvs, *calcvs; vdev_stat_t zerovs = { 0 }; char *vname; + int i; + int ret = 0; uint64_t tdelta; double scale; if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) - return; + return (0); + + calcvs = safe_malloc(sizeof (*calcvs)); if (oldnv != NULL) { verify(nvlist_lookup_uint64_array(oldnv, @@ -3188,54 +3999,98 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, oldvs = &zerovs; } + /* Do we only want to see a specific vdev? */ + for (i = 0; i < cb->cb_vdev_names_count; i++) { + /* Yes we do. Is this the vdev? */ + if (strcmp(name, cb->cb_vdev_names[i]) == 0) { + /* + * This is our vdev. Since it is the only vdev we + * will be displaying, make depth = 0 so that it + * doesn't get indented. + */ + depth = 0; + break; + } + } + + if (cb->cb_vdev_names_count && (i == cb->cb_vdev_names_count)) { + /* Couldn't match the name */ + goto children; + } + + verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&newvs, &c) == 0); - if (strlen(name) + depth > cb->cb_namewidth) - (void) printf("%*s%s", depth, "", name); - else - (void) printf("%*s%s%*s", depth, "", name, - (int)(cb->cb_namewidth - strlen(name) - depth), ""); + /* + * Print the vdev name unless it's is a histogram. Histograms + * display the vdev name in the header itself. + */ + if (!(cb->cb_flags & IOS_ANYHISTO_M)) { + if (cb->cb_scripted) { + printf("%s", name); + } else { + if (strlen(name) + depth > cb->cb_namewidth) + (void) printf("%*s%s", depth, "", name); + else + (void) printf("%*s%s%*s", depth, "", name, + (int)(cb->cb_namewidth - strlen(name) - + depth), ""); + } + } + /* Calculate our scaling factor */ tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; - - if (tdelta == 0) - scale = 1.0; - else - scale = (double)NANOSEC / tdelta; - - /* only toplevel vdevs have capacity stats */ - if (newvs->vs_space == 0) { - (void) printf(" - -"); + if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_ANYHISTO_M)) { + /* + * If we specify printing histograms with no time interval, then + * print the histogram numbers over the entire lifetime of the + * vdev. + */ + scale = 1; } else { - print_one_stat(newvs->vs_alloc); - print_one_stat(newvs->vs_space - newvs->vs_alloc); + if (tdelta == 0) + scale = 1.0; + else + scale = (double)NANOSEC / tdelta; } - print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - - oldvs->vs_ops[ZIO_TYPE_READ]))); + if (cb->cb_flags & IOS_DEFAULT_M) { + calc_default_iostats(oldvs, newvs, calcvs); + print_iostat_default(calcvs, cb, scale); + } + if (cb->cb_flags & IOS_LATENCY_M) + print_iostat_latency(cb, oldnv, newnv); + if (cb->cb_flags & IOS_QUEUES_M) + print_iostat_queues(cb, oldnv, newnv); + if (cb->cb_flags & IOS_ANYHISTO_M) { + printf("\n"); + print_iostat_histos(cb, oldnv, newnv, scale, name); + } - print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - - oldvs->vs_ops[ZIO_TYPE_WRITE]))); + if (!(cb->cb_flags & IOS_ANYHISTO_M)) + printf("\n"); - print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - - oldvs->vs_bytes[ZIO_TYPE_READ]))); + ret++; - print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - - oldvs->vs_bytes[ZIO_TYPE_WRITE]))); +children: - (void) printf("\n"); + free(calcvs); if (!cb->cb_verbose) - return; + return (ret); if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, &newchild, &children) != 0) - return; + return (ret); - if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, - &oldchild, &c) != 0) - return; + if (oldnv) { + if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, + &oldchild, &oldchildren) != 0) + return (ret); + + children = MIN(oldchildren, children); + } /* * print normal top-level devices @@ -3257,7 +4112,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, vname = zpool_vdev_name(g_zfs, zhp, newchild[c], cb->cb_name_flags); - print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, + ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2); free(vname); } @@ -3267,6 +4122,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, */ for (uint_t n = 0; n < 3; n++) { boolean_t printed = B_FALSE; + for (c = 0; c < children; c++) { uint64_t islog = B_FALSE; char *bias = NULL; @@ -3288,11 +4144,10 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, continue; if (!printed) { - if (!cb->cb_scripted) { - (void) printf( - "%-*s - - - -" - " - -", - cb->cb_namewidth, class_name[n]); + if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && + !cb->cb_scripted && !cb->cb_vdev_names) { + print_iostat_dashes(cb, 0, + class_name[n]); } printf("\n"); printed = B_TRUE; @@ -3300,7 +4155,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, vname = zpool_vdev_name(g_zfs, zhp, newchild[c], cb->cb_name_flags); - print_vdev_stats(zhp, vname, oldnv ? + ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2); free(vname); } @@ -3312,23 +4167,33 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, */ if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, &newchild, &children) != 0) - return; + return (ret); - if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, - &oldchild, &c) != 0) - return; + if (oldnv) { + if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, + &oldchild, &oldchildren) != 0) + return (ret); + + children = MIN(oldchildren, children); + } if (children > 0) { - (void) printf("%-*s - - - - - " - "-\n", cb->cb_namewidth, "cache"); + if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted && + !cb->cb_vdev_names) { + print_iostat_dashes(cb, 0, "cache"); + } + printf("\n"); + for (c = 0; c < children; c++) { vname = zpool_vdev_name(g_zfs, zhp, newchild[c], cb->cb_name_flags); - print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, - newchild[c], cb, depth + 2); + ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] + : NULL, newchild[c], cb, depth + 2); free(vname); } } + + return (ret); } static int @@ -3358,6 +4223,7 @@ print_iostat(zpool_handle_t *zhp, void *data) iostat_cbdata_t *cb = data; nvlist_t *oldconfig, *newconfig; nvlist_t *oldnvroot, *newnvroot; + int ret; newconfig = zpool_get_config(zhp, &oldconfig); @@ -3373,63 +4239,79 @@ print_iostat(zpool_handle_t *zhp, void *data) verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, &oldnvroot) == 0); - /* - * Print out the statistics for the pool. - */ - print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); - - if (cb->cb_verbose) + ret = print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, + cb, 0); + if ((ret != 0) && !(cb->cb_flags & IOS_ANYHISTO_M) && + !cb->cb_scripted && cb->cb_verbose && !cb->cb_vdev_names_count) { print_iostat_separator(cb); + printf("\n"); + } - return (0); + return (ret); } -int -get_namewidth(zpool_handle_t *zhp, void *data) +static int +get_columns(void) +{ + struct winsize ws; + int columns = 80; + int error; + + if (isatty(STDOUT_FILENO)) { + error = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); + if (error == 0) + columns = ws.ws_col; + } else { + columns = 999; + } + + return (columns); +} + +/* + * Return the required length of the pool/vdev name column. The minimum + * allowed width and output formatting flags must be provided. + */ +static int +get_namewidth(zpool_handle_t *zhp, int min_width, int flags, boolean_t verbose) { - iostat_cbdata_t *cb = data; nvlist_t *config, *nvroot; + int width = min_width; if ((config = zpool_get_config(zhp, NULL)) != NULL) { verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); - if (!cb->cb_verbose) - cb->cb_namewidth = strlen(zpool_get_name(zhp)); - else - cb->cb_namewidth = max_width(zhp, nvroot, 0, - cb->cb_namewidth, cb->cb_name_flags); + unsigned int poolname_len = strlen(zpool_get_name(zhp)); + if (verbose == B_FALSE) { + width = MAX(poolname_len, min_width); + } else { + width = MAX(poolname_len, + max_width(zhp, nvroot, 0, min_width, flags)); + } } - /* - * The width must fall into the range [10,38]. The upper limit is the - * maximum we can have and still fit in 80 columns. - */ - if (cb->cb_namewidth < 10) - cb->cb_namewidth = 10; - if (cb->cb_namewidth > 38) - cb->cb_namewidth = 38; - - return (0); + return (width); } /* * Parse the input string, get the 'interval' and 'count' value if there is one. */ static void -get_interval_count(int *argcp, char **argv, unsigned long *iv, +get_interval_count(int *argcp, char **argv, float *iv, unsigned long *cnt) { - unsigned long interval = 0, count = 0; + float interval = 0; + unsigned long count = 0; int argc = *argcp, errno; /* * Determine if the last argument is an integer or a pool name */ - if (argc > 0 && zfs_isnumber(argv[argc - 1])) { + if (argc > 0 && isnumber(argv[argc - 1])) { char *end; errno = 0; - interval = strtoul(argv[argc - 1], &end, 10); + interval = strtof(argv[argc - 1], &end); if (*end == '\0' && errno == 0) { if (interval == 0) { @@ -3455,12 +4337,12 @@ get_interval_count(int *argcp, char **argv, unsigned long *iv, * If the last argument is also an integer, then we have both a count * and an interval. */ - if (argc > 0 && zfs_isnumber(argv[argc - 1])) { + if (argc > 0 && isnumber(argv[argc - 1])) { char *end; errno = 0; count = interval; - interval = strtoul(argv[argc - 1], &end, 10); + interval = strtof(argv[argc - 1], &end); if (*end == '\0' && errno == 0) { if (interval == 0) { @@ -3495,13 +4377,296 @@ get_timestamp_arg(char c) } /* - * zpool iostat [-gLPv] [-T d|u] [pool] ... [interval [count]] + * Return stat flags that are supported by all pools by both the module and + * zpool iostat. "*data" should be initialized to all 0xFFs before running. + * It will get ANDed down until only the flags that are supported on all pools + * remain. + */ +static int +get_stat_flags_cb(zpool_handle_t *zhp, void *data) +{ + uint64_t *mask = data; + nvlist_t *config, *nvroot, *nvx; + uint64_t flags = 0; + int i, j; + + config = zpool_get_config(zhp, NULL); + verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, + &nvroot) == 0); + + /* Default stats are always supported, but for completeness.. */ + if (nvlist_exists(nvroot, ZPOOL_CONFIG_VDEV_STATS)) + flags |= IOS_DEFAULT_M; + + /* Get our extended stats nvlist from the main list */ + if (nvlist_lookup_nvlist(nvroot, ZPOOL_CONFIG_VDEV_STATS_EX, + &nvx) != 0) { + /* + * No extended stats; they're probably running an older + * module. No big deal, we support that too. + */ + goto end; + } + + /* For each extended stat, make sure all its nvpairs are supported */ + for (j = 0; j < ARRAY_SIZE(vsx_type_to_nvlist); j++) { + if (!vsx_type_to_nvlist[j][0]) + continue; + + /* Start off by assuming the flag is supported, then check */ + flags |= (1ULL << j); + for (i = 0; vsx_type_to_nvlist[j][i]; i++) { + if (!nvlist_exists(nvx, vsx_type_to_nvlist[j][i])) { + /* flag isn't supported */ + flags = flags & ~(1ULL << j); + break; + } + } + } +end: + *mask = *mask & flags; + return (0); +} + +/* + * Return a bitmask of stats that are supported on all pools by both the module + * and zpool iostat. + */ +static uint64_t +get_stat_flags(zpool_list_t *list) +{ + uint64_t mask = -1; + + /* + * get_stat_flags_cb() will lop off bits from "mask" until only the + * flags that are supported on all pools remain. + */ + (void) pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask); + return (mask); +} + +/* + * Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise. + */ +static int +is_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_data) +{ + iostat_cbdata_t *cb = cb_data; + char *name; + + name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags); + + if (strcmp(name, cb->cb_vdev_names[0]) == 0) + return (1); /* match */ + + return (0); +} + +/* + * Returns 1 if cb_data->cb_vdev_names[0] is a vdev name, 0 otherwise. + */ +static int +is_vdev(zpool_handle_t *zhp, void *cb_data) +{ + return (for_each_vdev(zhp, is_vdev_cb, cb_data)); +} + +/* + * Check if vdevs are in a pool + * + * Return 1 if all argv[] strings are vdev names in pool "pool_name". Otherwise + * return 0. If pool_name is NULL, then search all pools. + */ +static int +are_vdevs_in_pool(int argc, char **argv, char *pool_name, + iostat_cbdata_t *cb) +{ + char **tmp_name; + int ret = 0; + int i; + int pool_count = 0; + + if ((argc == 0) || !*argv) + return (0); + + if (pool_name) + pool_count = 1; + + /* Temporarily hijack cb_vdev_names for a second... */ + tmp_name = cb->cb_vdev_names; + + /* Go though our list of prospective vdev names */ + for (i = 0; i < argc; i++) { + cb->cb_vdev_names = argv + i; + + /* Is this name a vdev in our pools? */ + ret = for_each_pool(pool_count, &pool_name, B_TRUE, NULL, + is_vdev, cb); + if (!ret) { + /* No match */ + break; + } + } + + cb->cb_vdev_names = tmp_name; + + return (ret); +} + +static int +is_pool_cb(zpool_handle_t *zhp, void *data) +{ + char *name = data; + if (strcmp(name, zpool_get_name(zhp)) == 0) + return (1); + + return (0); +} + +/* + * Do we have a pool named *name? If so, return 1, otherwise 0. + */ +static int +is_pool(char *name) +{ + return (for_each_pool(0, NULL, B_TRUE, NULL, is_pool_cb, name)); +} + +/* Are all our argv[] strings pool names? If so return 1, 0 otherwise. */ +static int +are_all_pools(int argc, char **argv) +{ + if ((argc == 0) || !*argv) + return (0); + + while (--argc >= 0) + if (!is_pool(argv[argc])) + return (0); + + return (1); +} + +/* + * Helper function to print out vdev/pool names we can't resolve. Used for an + * error message. + */ +static void +error_list_unresolved_vdevs(int argc, char **argv, char *pool_name, + iostat_cbdata_t *cb) +{ + int i; + char *name; + char *str; + for (i = 0; i < argc; i++) { + name = argv[i]; + + if (is_pool(name)) + str = gettext("pool"); + else if (are_vdevs_in_pool(1, &name, pool_name, cb)) + str = gettext("vdev in this pool"); + else if (are_vdevs_in_pool(1, &name, NULL, cb)) + str = gettext("vdev in another pool"); + else + str = gettext("unknown"); + + fprintf(stderr, "\t%s (%s)\n", name, str); + } +} + +/* + * Same as get_interval_count(), but with additional checks to not misinterpret + * guids as interval/count values. Assumes VDEV_NAME_GUID is set in + * cb.cb_name_flags. + */ +static void +get_interval_count_filter_guids(int *argc, char **argv, float *interval, + unsigned long *count, iostat_cbdata_t *cb) +{ + char **tmpargv = argv; + int argc_for_interval = 0; + + /* Is the last arg an interval value? Or a guid? */ + if (*argc >= 1 && !are_vdevs_in_pool(1, &argv[*argc - 1], NULL, cb)) { + /* + * The last arg is not a guid, so it's probably an + * interval value. + */ + argc_for_interval++; + + if (*argc >= 2 && + !are_vdevs_in_pool(1, &argv[*argc - 2], NULL, cb)) { + /* + * The 2nd to last arg is not a guid, so it's probably + * an interval value. + */ + argc_for_interval++; + } + } + + /* Point to our list of possible intervals */ + tmpargv = &argv[*argc - argc_for_interval]; + + *argc = *argc - argc_for_interval; + get_interval_count(&argc_for_interval, tmpargv, + interval, count); +} + +/* + * Floating point sleep(). Allows you to pass in a floating point value for + * seconds. + */ +static void +fsleep(float sec) +{ + struct timespec req; + req.tv_sec = floor(sec); + req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC; + (void) nanosleep(&req, NULL); +} + +/* + * Set the minimum pool/vdev name column width. The width must be at least 10, + * but may be as large as the column width - 42 so it still fits on one line. + */ +static int +get_namewidth_iostat(zpool_handle_t *zhp, void *data) +{ + iostat_cbdata_t *cb = data; + int width, columns; + + width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags, + cb->cb_verbose); + columns = get_columns(); + + if (width < 10) + width = 10; + if (width > columns - 42) + width = columns - 42; + + cb->cb_namewidth = width; + + return (0); +} + +/* + * zpool iostat [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u] + * [[ pool ...]|[pool vdev ...]|[vdev ...]] + * [interval [count]] * * -g Display guid for individual vdev name. * -L Follow links when resolving vdev path name. * -P Display full path for vdev name. * -v Display statistics for individual vdevs + * -h Display help + * -p Display values in parsable (exact) format. + * -H Scripted mode. Don't display headers, and separate properties + * by a single tab. + * -l Display average latency + * -q Display queue depths + * -w Display latency histograms + * -r Display request size histogram * -T Display a timestamp in date(1) or Unix format + * -n Only print headers once * * This command can be tricky because we want to be able to deal with pool * creation/destruction as well as vdev configuration changes. The bulk of this @@ -3515,16 +4680,29 @@ zpool_do_iostat(int argc, char **argv) int c; int ret; int npools; - unsigned long interval = 0, count = 0; + float interval = 0; + unsigned long count = 0; + int winheight = 24; + struct winsize win; zpool_list_t *list; boolean_t verbose = B_FALSE; + boolean_t latency = B_FALSE, l_histo = B_FALSE, rq_histo = B_FALSE; + boolean_t queues = B_FALSE, parseable = B_FALSE, scripted = B_FALSE; + boolean_t omit_since_boot = B_FALSE; boolean_t guid = B_FALSE; boolean_t follow_links = B_FALSE; boolean_t full_name = B_FALSE; + boolean_t headers_once = B_FALSE; iostat_cbdata_t cb = { 0 }; + /* Used for printing error message */ + const char flag_to_arg[] = {[IOS_LATENCY] = 'l', [IOS_QUEUES] = 'q', + [IOS_L_HISTO] = 'w', [IOS_RQ_HISTO] = 'r'}; + + uint64_t unsupported_flags; + /* check options */ - while ((c = getopt(argc, argv, "gLPT:v")) != -1) { + while ((c = getopt(argc, argv, "gLPT:vyhplqrwnH")) != -1) { switch (c) { case 'g': guid = B_TRUE; @@ -3541,6 +4719,33 @@ zpool_do_iostat(int argc, char **argv) case 'v': verbose = B_TRUE; break; + case 'p': + parseable = B_TRUE; + break; + case 'l': + latency = B_TRUE; + break; + case 'q': + queues = B_TRUE; + break; + case 'H': + scripted = B_TRUE; + break; + case 'w': + l_histo = B_TRUE; + break; + case 'r': + rq_histo = B_TRUE; + break; + case 'y': + omit_since_boot = B_TRUE; + break; + case 'n': + headers_once = B_TRUE; + break; + case 'h': + usage(B_FALSE); + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -3551,7 +4756,70 @@ zpool_do_iostat(int argc, char **argv) argc -= optind; argv += optind; - get_interval_count(&argc, argv, &interval, &count); + cb.cb_literal = parseable; + cb.cb_scripted = scripted; + + if (guid) + cb.cb_name_flags |= VDEV_NAME_GUID; + if (follow_links) + cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS; + if (full_name) + cb.cb_name_flags |= VDEV_NAME_PATH; + cb.cb_iteration = 0; + cb.cb_namewidth = 0; + cb.cb_verbose = verbose; + + /* Get our interval and count values (if any) */ + if (guid) { + get_interval_count_filter_guids(&argc, argv, &interval, + &count, &cb); + } else { + get_interval_count(&argc, argv, &interval, &count); + } + + if (argc == 0) { + /* No args, so just print the defaults. */ + } else if (are_all_pools(argc, argv)) { + /* All the args are pool names */ + } else if (are_vdevs_in_pool(argc, argv, NULL, &cb)) { + /* All the args are vdevs */ + cb.cb_vdev_names = argv; + cb.cb_vdev_names_count = argc; + argc = 0; /* No pools to process */ + } else if (are_all_pools(1, argv)) { + /* The first arg is a pool name */ + if (are_vdevs_in_pool(argc - 1, argv + 1, argv[0], &cb)) { + /* ...and the rest are vdev names */ + cb.cb_vdev_names = argv + 1; + cb.cb_vdev_names_count = argc - 1; + argc = 1; /* One pool to process */ + } else { + fprintf(stderr, gettext("Expected either a list of ")); + fprintf(stderr, gettext("pools, or list of vdevs in")); + fprintf(stderr, " \"%s\", ", argv[0]); + fprintf(stderr, gettext("but got:\n")); + error_list_unresolved_vdevs(argc - 1, argv + 1, + argv[0], &cb); + fprintf(stderr, "\n"); + usage(B_FALSE); + return (1); + } + } else { + /* + * The args don't make sense. The first arg isn't a pool name, + * nor are all the args vdevs. + */ + fprintf(stderr, gettext("Unable to parse pools/vdevs list.\n")); + fprintf(stderr, "\n"); + return (1); + } + + if (cb.cb_vdev_names_count != 0) { + /* + * If user specified vdevs, it implies verbose. + */ + cb.cb_verbose = B_TRUE; + } /* * Construct the list of all interesting pools. @@ -3571,60 +4839,156 @@ zpool_do_iostat(int argc, char **argv) return (1); } + if ((l_histo || rq_histo) && (queues || latency)) { + pool_list_free(list); + (void) fprintf(stderr, + gettext("[-r|-w] isn't allowed with [-q|-l]\n")); + usage(B_FALSE); + return (1); + } + + if (l_histo && rq_histo) { + pool_list_free(list); + (void) fprintf(stderr, + gettext("Only one of [-r|-w] can be passed at a time\n")); + usage(B_FALSE); + return (1); + } + /* * Enter the main iostat loop. */ cb.cb_list = list; - cb.cb_verbose = verbose; - if (guid) - cb.cb_name_flags |= VDEV_NAME_GUID; - if (follow_links) - cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS; - if (full_name) - cb.cb_name_flags |= VDEV_NAME_PATH; - cb.cb_iteration = 0; - cb.cb_namewidth = 0; - for (;;) { - pool_list_update(list); + if (l_histo) { + /* + * Histograms tables look out of place when you try to display + * them with the other stats, so make a rule that you can only + * print histograms by themselves. + */ + cb.cb_flags = IOS_L_HISTO_M; + } else if (rq_histo) { + cb.cb_flags = IOS_RQ_HISTO_M; + } else { + cb.cb_flags = IOS_DEFAULT_M; + if (latency) + cb.cb_flags |= IOS_LATENCY_M; + if (queues) + cb.cb_flags |= IOS_QUEUES_M; + } + /* + * See if the module supports all the stats we want to display. + */ + unsupported_flags = cb.cb_flags & ~get_stat_flags(list); + if (unsupported_flags) { + uint64_t f; + int idx; + fprintf(stderr, + gettext("The loaded zfs module doesn't support:")); + + /* for each bit set in unsupported_flags */ + for (f = unsupported_flags; f; f &= ~(1ULL << idx)) { + idx = lowbit64(f) - 1; + fprintf(stderr, " -%c", flag_to_arg[idx]); + } + + fprintf(stderr, ". Try running a newer module.\n"), + pool_list_free(list); + + return (1); + } + + for (;;) { if ((npools = pool_list_count(list)) == 0) - break; + (void) fprintf(stderr, gettext("no pools available\n")); + else { + /* + * If this is the first iteration and -y was supplied + * we skip any printing. + */ + boolean_t skip = (omit_since_boot && + cb.cb_iteration == 0); - /* - * Refresh all statistics. This is done as an explicit step - * before calculating the maximum name width, so that any - * configuration changes are properly accounted for. - */ - (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); + /* + * Refresh all statistics. This is done as an + * explicit step before calculating the maximum name + * width, so that any configuration changes are + * properly accounted for. + */ + (void) pool_list_iter(list, B_FALSE, refresh_iostat, + &cb); - /* - * Iterate over all pools to determine the maximum width - * for the pool / device name column across all pools. - */ - cb.cb_namewidth = 0; - (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); + /* + * Iterate over all pools to determine the maximum width + * for the pool / device name column across all pools. + */ + cb.cb_namewidth = 0; + (void) pool_list_iter(list, B_FALSE, + get_namewidth_iostat, &cb); - if (timestamp_fmt != NODATE) - print_timestamp(timestamp_fmt); + if (timestamp_fmt != NODATE) + print_timestamp(timestamp_fmt); - /* - * If it's the first time, or verbose mode, print the header. - */ - if (++cb.cb_iteration == 1 || verbose) - print_iostat_header(&cb); + /* + * Check terminal size so we can print headers + * even when terminal window has its height + * changed. + */ + if (headers_once == B_FALSE) { + if (ioctl(1, TIOCGWINSZ, &win) != -1) { + if (win.ws_row <= 0) { + headers_once = B_TRUE; + } else { + winheight = win.ws_row; + } + } + } + /* + * Are we connected to TTY? If not, headers_once + * should be true, to avoid breaking scripts. + */ + if (isatty(fileno(stdout)) == 0) + headers_once = B_TRUE; - (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); + /* + * If it's the first time and we're not skipping it, + * or either skip or verbose mode, print the header. + * + * The histogram code explicitly prints its header on + * every vdev, so skip this for histograms. + */ + if (((++cb.cb_iteration == 1 && !skip) || + (skip != verbose) || + (!headers_once && + (cb.cb_iteration % winheight) == 0)) && + (!(cb.cb_flags & IOS_ANYHISTO_M)) && + !cb.cb_scripted) + print_iostat_header(&cb); + + if (skip) { + (void) fsleep(interval); + continue; + } - /* - * If there's more than one pool, and we're not in verbose mode - * (which prints a separator for us), then print a separator. - */ - if (npools > 1 && !verbose) - print_iostat_separator(&cb); + (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); - if (verbose) - (void) printf("\n"); + /* + * If there's more than one pool, and we're not in + * verbose mode (which prints a separator for us), + * then print a separator. + * + * In addition, if we're printing specific vdevs then + * we also want an ending separator. + */ + if (((npools > 1 && !verbose && + !(cb.cb_flags & IOS_ANYHISTO_M)) || + (!(cb.cb_flags & IOS_ANYHISTO_M) && + cb.cb_vdev_names_count)) && + !cb.cb_scripted) { + print_iostat_separator(&cb); + } + } /* * Flush the output so that redirection to a file isn't buffered @@ -3638,7 +5002,7 @@ zpool_do_iostat(int argc, char **argv) if (count != 0 && --count == 0) break; - (void) sleep(interval); + (void) fsleep(interval); } pool_list_free(list); @@ -3995,6 +5359,27 @@ list_callback(zpool_handle_t *zhp, void *data) } /* + * Set the minimum pool/vdev name column width. The width must be at least 9, + * but may be as large as needed. + */ +static int +get_namewidth_list(zpool_handle_t *zhp, void *data) +{ + list_cbdata_t *cb = data; + int width; + + width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags, + cb->cb_verbose); + + if (width < 9) + width = 9; + + cb->cb_namewidth = width; + + return (0); +} + +/* * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] * * -g Display guid for individual vdev name. @@ -4021,7 +5406,8 @@ zpool_do_list(int argc, char **argv) "name,size,allocated,free,checkpoint,expandsize,fragmentation," "capacity,dedupratio,health,altroot"; char *props = default_props; - unsigned long interval = 0, count = 0; + float interval = 0; + unsigned long count = 0; zpool_list_t *list; boolean_t first = B_TRUE; @@ -4082,7 +5468,7 @@ zpool_do_list(int argc, char **argv) break; cb.cb_namewidth = 0; - (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); + (void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb); if (timestamp_fmt != NODATE) print_timestamp(timestamp_fmt); @@ -4100,7 +5486,7 @@ zpool_do_list(int argc, char **argv) break; pool_list_free(list); - (void) sleep(interval); + (void) fsleep(interval); } if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { @@ -5945,6 +7331,9 @@ status_callback(zpool_handle_t *zhp, void *data) cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE", "CKSUM"); + if (cbp->cb_print_slow_ios) + (void) printf(" %5s", gettext("SLOW")); + print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0, B_FALSE); @@ -6006,12 +7395,14 @@ status_callback(zpool_handle_t *zhp, void *data) } /* - * zpool status [-igLPtvx] [-T d|u] [pool] ... [interval [count]] + * zpool status [-igLpPstvx] [-T d|u] [pool] ... [interval [count]] * * -i Display vdev initialization status. * -g Display guid for individual vdev name. * -L Follow links when resolving vdev path name. + * -p Display values in parsable (exact) format. * -P Display full path for vdev name. + * -s Display slow IOs column. * -v Display complete error logs * -x Display only pools with potential problems * -D Display dedup status (undocumented) @@ -6025,11 +7416,12 @@ zpool_do_status(int argc, char **argv) { int c; int ret; - unsigned long interval = 0, count = 0; + float interval = 0; + unsigned long count = 0; status_cbdata_t cb = { 0 }; /* check options */ - while ((c = getopt(argc, argv, "igLPvxDtT:")) != -1) { + while ((c = getopt(argc, argv, "igLpPsvxDtT:")) != -1) { switch (c) { case 'i': cb.cb_print_vdev_init = B_TRUE; @@ -6040,9 +7432,15 @@ zpool_do_status(int argc, char **argv) case 'L': cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS; break; + case 'p': + cb.cb_literal = B_TRUE; + break; case 'P': cb.cb_name_flags |= VDEV_NAME_PATH; break; + case 's': + cb.cb_print_slow_ios = B_TRUE; + break; case 'v': cb.cb_verbose = B_TRUE; break; @@ -6097,7 +7495,7 @@ zpool_do_status(int argc, char **argv) if (count != 0 && --count == 0) break; - (void) sleep(interval); + (void) fsleep(interval); } return (0); diff --git a/usr/src/cmd/zpool/zpool_util.c b/usr/src/cmd/zpool/zpool_util.c index c7a002efb1..e4281af210 100644 --- a/usr/src/cmd/zpool/zpool_util.c +++ b/usr/src/cmd/zpool/zpool_util.c @@ -29,6 +29,8 @@ #include <stdio.h> #include <stdlib.h> #include <strings.h> +#include <ctype.h> +#include <sys/sysmacros.h> #include "zpool_util.h" @@ -84,3 +86,29 @@ num_logs(nvlist_t *nv) } return (nlogs); } + +/* Find the max element in an array of uint64_t values */ +uint64_t +array64_max(uint64_t array[], unsigned int len) +{ + uint64_t max = 0; + int i; + for (i = 0; i < len; i++) + max = MAX(max, array[i]); + + return (max); +} + +/* + * Return 1 if "str" is a number string, 0 otherwise. Works for integer and + * floating point numbers. + */ +int +isnumber(char *str) +{ + for (; *str; str++) + if (!(isdigit(*str) || (*str == '.'))) + return (0); + + return (1); +} diff --git a/usr/src/cmd/zpool/zpool_util.h b/usr/src/cmd/zpool/zpool_util.h index 3aeb9b5431..e4c93acf39 100644 --- a/usr/src/cmd/zpool/zpool_util.h +++ b/usr/src/cmd/zpool/zpool_util.h @@ -38,6 +38,10 @@ extern "C" { void *safe_malloc(size_t); void zpool_no_memory(void); uint_t num_logs(nvlist_t *nv); +uint64_t array64_max(uint64_t array[], unsigned int len); +int highbit64(uint64_t i); +int lowbit64(uint64_t i); +int isnumber(char *str); /* * Virtual device functions @@ -55,6 +59,10 @@ nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname, int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **, zpool_iter_f, void *); +/* Vdev list functions */ +typedef int (*pool_vdev_iter_f)(zpool_handle_t *, nvlist_t *, void *); +int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data); + typedef struct zpool_list zpool_list_t; zpool_list_t *pool_list_get(int, char **, zprop_list_t **, int *); diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c index 1aa0f2e5e1..2f501a2334 100644 --- a/usr/src/lib/libctf/common/ctf_dwarf.c +++ b/usr/src/lib/libctf/common/ctf_dwarf.c @@ -29,6 +29,7 @@ /* * Copyright 2020 Joyent, Inc. + * Copyright 2020 Robert Mustacchi */ /* @@ -800,6 +801,40 @@ static const ctf_dwarf_fpmap_t ctf_dwarf_fpmaps[] = { { EM_NONE } }; +/* + * We want to normalize the type names that are used between compilers in the + * case of complex. gcc prefixes things with types like 'long complex' where as + * clang only calls them 'complex' in the dwarf even if in the C they are long + * complex or similar. + */ +static int +ctf_dwarf_fixup_complex(ctf_cu_t *cup, ctf_encoding_t *enc, char **namep) +{ + const char *name; + *namep = NULL; + + switch (enc->cte_format) { + case CTF_FP_CPLX: + name = "complex float"; + break; + case CTF_FP_DCPLX: + name = "complex double"; + break; + case CTF_FP_LDCPLX: + name = "complex long double"; + break; + default: + return (0); + } + + *namep = ctf_strdup(name); + if (*namep == NULL) { + return (ENOMEM); + } + + return (0); +} + static int ctf_dwarf_float_base(ctf_cu_t *cup, Dwarf_Signed type, ctf_encoding_t *enc) { @@ -896,7 +931,7 @@ ctf_dwarf_dwarf_base(ctf_cu_t *cup, Dwarf_Die die, int *kindp, * back to using the DWARF itself. */ static int -ctf_dwarf_parse_base(const char *name, int *kindp, ctf_encoding_t *enc, +ctf_dwarf_parse_int(const char *name, int *kindp, ctf_encoding_t *enc, char **newnamep) { char buf[256]; @@ -974,7 +1009,7 @@ ctf_dwarf_create_base(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot, Dwarf_Off off) { int ret; - char *name, *nname; + char *name, *nname = NULL; Dwarf_Unsigned sz; int kind; ctf_encoding_t enc; @@ -990,15 +1025,25 @@ ctf_dwarf_create_base(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot, bzero(&enc, sizeof (ctf_encoding_t)); enc.cte_bits = sz * 8; - if ((ret = ctf_dwarf_parse_base(name, &kind, &enc, &nname)) == 0) { + if ((ret = ctf_dwarf_parse_int(name, &kind, &enc, &nname)) == 0) { ctf_free(name, strlen(name) + 1); name = nname; } else { - if (ret != EINVAL) - return (ret); + if (ret != EINVAL) { + goto out; + } ctf_dprintf("falling back to dwarf for base type %s\n", name); - if ((ret = ctf_dwarf_dwarf_base(cup, die, &kind, &enc)) != 0) - return (ret); + if ((ret = ctf_dwarf_dwarf_base(cup, die, &kind, &enc)) != 0) { + goto out; + } + + if (kind == CTF_K_FLOAT && (ret = ctf_dwarf_fixup_complex(cup, + &enc, &nname)) != 0) { + goto out; + } else if (nname != NULL) { + ctf_free(name, strlen(name) + 1); + name = nname; + } } id = ctf_add_encoded(cup->cu_ctfp, isroot, name, &enc, kind); @@ -1238,7 +1283,7 @@ ctf_dwarf_fixup_sou(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t base, boolean_t add) return (ret); if (tag != DW_TAG_member) - continue; + goto next; if ((ret = ctf_dwarf_refdie(cup, memb, DW_AT_type, &tdie)) != 0) return (ret); @@ -1373,12 +1418,39 @@ ctf_dwarf_create_sou(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, return (ret); /* - * Members are in children. However, gcc also allows empty ones. + * The children of a structure or union are generally members. However, + * some compilers actually insert structs and unions there and not as a + * top-level die. Therefore, to make sure we honor our pass 1 contract + * of having all the base types, but not members, we need to walk this + * for instances of a DW_TAG_union_type. */ if ((ret = ctf_dwarf_child(cup, die, &child)) != 0) return (ret); - if (child == NULL) - return (0); + + while (child != NULL) { + Dwarf_Half tag; + Dwarf_Die sib; + + if ((ret = ctf_dwarf_tag(cup, child, &tag)) != 0) + return (ret); + + switch (tag) { + case DW_TAG_union_type: + case DW_TAG_structure_type: + ret = ctf_dwarf_convert_type(cup, child, NULL, + CTF_ADD_NONROOT); + if (ret != 0) { + return (ret); + } + break; + default: + break; + } + + if ((ret = ctf_dwarf_sib(cup, child, &sib)) != 0) + return (ret); + child = sib; + } return (0); } diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h index 9a7e076c5a..f6fb0f0bb0 100644 --- a/usr/src/lib/libsldap/common/ns_internal.h +++ b/usr/src/lib/libsldap/common/ns_internal.h @@ -22,6 +22,7 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Joyent, Inc. */ @@ -67,8 +68,7 @@ extern "C" { #define UIDNUMFILTER_SSD "(&(%%s)(uidnumber=%s))" #define UIDFILTER "(&(objectclass=posixAccount)(uid=%s))" #define UIDFILTER_SSD "(&(%%s)(uid=%s))" -#define UIDDNFILTER "(&(objectclass=posixAccount)(distinguishedName=%s))" -#define UIDDNFILTER_SSD "(&(%%s)(distinguishedName=%s))" +#define UIDDNFILTER "(objectclass=posixAccount)" #define HOSTFILTER "(&(objectclass=ipHost)(cn=%s))" #define HOSTFILTER_SSD "(&(%%s)(cn=%s))" @@ -765,6 +765,7 @@ int __s_api_requestServer(const char *request, const char *server, /* ************ internal sldap-api functions *********** */ void __ns_ldap_freeEntry(ns_ldap_entry_t *ep); +void __ns_ldap_freeASearchDesc(ns_ldap_search_desc_t *); void __s_api_split_key_value(char *buffer, char **name, char **value); int __s_api_printResult(ns_ldap_result_t *); int __s_api_getSearchScope(int *, ns_ldap_error_t **); @@ -856,25 +857,16 @@ ns_ldap_error_t *__ns_ldap_print_config(int); void __ns_ldap_default_config(); int __ns_ldap_download(const char *, char *, char *, ns_ldap_error_t **); -int -__ns_ldap_check_dns_preq(int foreground, - int mode_verbose, - int mode_quiet, - const char *fname, - ns_ldap_self_gssapi_config_t config, - ns_ldap_error_t **errpp); -int -__ns_ldap_check_gssapi_preq(int foreground, - int mode_verbose, - int mode_quiet, - ns_ldap_self_gssapi_config_t config, - ns_ldap_error_t **errpp); -int -__ns_ldap_check_all_preq(int foreground, - int mode_verbose, - int mode_quiet, - ns_ldap_self_gssapi_config_t config, - ns_ldap_error_t **errpp); +int __ns_ldap_check_dns_preq(int foreground, int mode_verbose, int mode_quiet, + const char *fname, ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); + +int __ns_ldap_check_gssapi_preq(int foreground, int mode_verbose, + int mode_quiet, ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); + +int __ns_ldap_check_all_preq(int foreground, int mode_verbose, int mode_quiet, + ns_ldap_self_gssapi_config_t config, ns_ldap_error_t **errpp); /* internal un-exposed APIs */ ns_cred_t *__ns_ldap_dupAuth(const ns_cred_t *authp); diff --git a/usr/src/lib/libsldap/common/ns_mapping.c b/usr/src/lib/libsldap/common/ns_mapping.c index 7a30a090f0..af41831d41 100644 --- a/usr/src/lib/libsldap/common/ns_mapping.c +++ b/usr/src/lib/libsldap/common/ns_mapping.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2020 Joyent, Inc. */ #include <stdlib.h> @@ -201,7 +202,7 @@ __s_api_add_map2hash(ns_config_t *config, ns_hashtype_t type, * Assume space is the only legal whitespace. * attributeMap syntax: * attributeMap = serviceId ":" origAttribute "=" - * attributes + * attributes * origAttribute = attribute * attributes = wattribute *( space wattribute ) * wattribute = whsp newAttribute whsp @@ -210,7 +211,7 @@ __s_api_add_map2hash(ns_config_t *config, ns_hashtype_t type, * * objectclassMap syntax: * objectclassMap = serviceId ":" origObjectclass "=" - * objectclass + * objectclass * origObjectclass = objectclass * objectclass = keystring */ @@ -295,7 +296,7 @@ __s_api_parse_map(char *cp, char **sid, char **origA, char ***mapA) } -static void +void __ns_ldap_freeASearchDesc(ns_ldap_search_desc_t *ptr) { if (ptr == NULL) @@ -662,7 +663,7 @@ int __ns_ldap_getSearchDescriptors( int cnt, max; int vers; ns_config_t *cfg; - ns_ldap_search_desc_t *ret; + ns_ldap_search_desc_t *ret; if ((desc == NULL) || (errorp == NULL)) return (NS_LDAP_INVALID_PARAM); diff --git a/usr/src/lib/libsldap/common/ns_reads.c b/usr/src/lib/libsldap/common/ns_reads.c index 0d112955d9..da987fd81a 100644 --- a/usr/src/lib/libsldap/common/ns_reads.c +++ b/usr/src/lib/libsldap/common/ns_reads.c @@ -21,6 +21,7 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Joyent, Inc. */ #include <stdio.h> @@ -3595,103 +3596,172 @@ __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch) return (rc); } +typedef struct lookup_data { + const char *lkd_dn; + const char *lkd_service; + const char *lkd_filter; + const ns_cred_t *lkd_cred; + ns_conn_user_t *lkd_user; +} lookup_data_t; + /* - * find_domainname performs one or more LDAP searches to - * find the value of the nisdomain attribute associated with - * the input DN (with no retry). + * This creates a service search descriptor that can be used to + * retrieve a specific DN by using the DN as the basedn with a search + * scope of 'base'. We don't use any service SSDs in this instance since + * they are intended to search specific locations/subtrees and filter the + * results, while here we are wanting to retrieve a specific entry. */ - static int -find_domainname(const char *dn, char **domainname, const ns_cred_t *cred, - ns_ldap_error_t **errorp, ns_conn_user_t *conn_user) +lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp) { + ns_ldap_search_desc_t *dptr; + + *descpp = NULL; + dptr = calloc(1, sizeof (ns_ldap_search_desc_t)); + if (dptr == NULL) + return (NS_LDAP_MEMORY); + + dptr->basedn = strdup(dn_data->lkd_dn); + dptr->scope = NS_LDAP_SCOPE_BASE; + dptr->filter = strdup(dn_data->lkd_filter); + + if (dptr->basedn == NULL || dptr->filter == NULL) { + __ns_ldap_freeASearchDesc(dptr); + return (NS_LDAP_MEMORY); + } + + *descpp = dptr; + return (NS_LDAP_SUCCESS); +} + +static int +lookup_dn(lookup_data_t *dn_data, const char **attrs, + ns_ldap_result_t **resultp, ns_ldap_error_t **errorp) +{ ns_ldap_cookie_t *cookie; - ns_ldap_search_desc_t **sdlist; - ns_ldap_search_desc_t *dptr; - int rc; - char **value; + int rc = 0; int flags = 0; - *domainname = NULL; *errorp = NULL; + *resultp = NULL; + + if (dn_data == NULL || dn_data->lkd_dn == NULL || + dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL) + return (NS_LDAP_INVALID_PARAM); - /* Initialize State machine cookie */ cookie = init_search_state_machine(); - if (cookie == NULL) { + if (cookie == NULL) return (NS_LDAP_MEMORY); - } - cookie->conn_user = conn_user; - /* see if need to follow referrals */ - rc = __s_api_toFollowReferrals(flags, - &cookie->followRef, errorp); - if (rc != NS_LDAP_SUCCESS) { - delete_search_cookie(cookie); - return (rc); - } + rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp); + if (rc != NS_LDAP_SUCCESS) + goto out; - /* Create default service Desc */ - sdlist = (ns_ldap_search_desc_t **)calloc(2, - sizeof (ns_ldap_search_desc_t *)); - if (sdlist == NULL) { - delete_search_cookie(cookie); - cookie = NULL; - return (NS_LDAP_MEMORY); - } - dptr = (ns_ldap_search_desc_t *) - calloc(1, sizeof (ns_ldap_search_desc_t)); - if (dptr == NULL) { - free(sdlist); - delete_search_cookie(cookie); - cookie = NULL; - return (NS_LDAP_MEMORY); + /* 1 for SSD, 1 for terminating NULL */ + cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *)); + if (cookie->sdlist == NULL) { + rc = NS_LDAP_MEMORY; + goto out; } - sdlist[0] = dptr; - /* search base is dn */ - dptr->basedn = strdup(dn); - - /* search scope is base */ - dptr->scope = NS_LDAP_SCOPE_BASE; + rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]); + if (rc != NS_LDAP_SUCCESS) + goto out; - /* search filter is "nisdomain=*" */ - dptr->filter = strdup(_NIS_FILTER); + if (dn_data->lkd_service != NULL) { + /* + * If a service was specified, set that on the cookie so + * that search_state_machine() will properly map + * attributes and objectclasses. + */ + cookie->service = strdup(dn_data->lkd_service); + if (cookie->service == NULL) { + rc = NS_LDAP_MEMORY; + goto out; + } + } - cookie->sdlist = sdlist; - cookie->i_filter = strdup(dptr->filter); - cookie->i_attr = nis_domain_attrs; - cookie->i_auth = cred; + cookie->i_attr = attrs; + cookie->i_auth = dn_data->lkd_cred; cookie->i_flags = 0; + cookie->i_filter = strdup(dn_data->lkd_filter); + if (cookie->i_filter == NULL) { + rc = NS_LDAP_MEMORY; + goto out; + } - /* Process search */ - rc = search_state_machine(cookie, INIT, 0); - - /* Copy domain name if found */ + /* + * Actually perform the search. The return value is only used when + * iterating through multiple results. Since we are searching with + * a scope of base, we will always get at most one result entry, + * we ignore the return value and look at err_rc to determine if + * there were any errors. + */ + (void) search_state_machine(cookie, INIT, 0); rc = cookie->err_rc; + if (rc != NS_LDAP_SUCCESS) { - if (conn_user != NULL && conn_user->ns_error != NULL) { - *errorp = conn_user->ns_error; - conn_user->ns_error = NULL; + ns_conn_user_t *user = dn_data->lkd_user; + + if (user != NULL && user->ns_error != NULL) { + *errorp = user->ns_error; + user->ns_error = NULL; } else { *errorp = cookie->errorp; + cookie->errorp = NULL; } - } - if (cookie->result == NULL) + } else if (cookie->result != NULL) { + *resultp = cookie->result; + cookie->result = NULL; + } else { rc = NS_LDAP_NOTFOUND; - if (rc == NS_LDAP_SUCCESS) { - value = __ns_ldap_getAttr(cookie->result->entry, - _NIS_DOMAIN); - if (value[0]) - *domainname = strdup(value[0]); - else - rc = NS_LDAP_NOTFOUND; } - if (cookie->result != NULL) - (void) __ns_ldap_freeResult(&cookie->result); - cookie->errorp = NULL; + +out: delete_search_cookie(cookie); - cookie = NULL; + return (rc); +} + +/* + * find_domainname performs one or more LDAP searches to + * find the value of the nisdomain attribute associated with + * the input DN (with no retry). + */ + +static int +find_domainname(const char *dn, char **domainname, const ns_cred_t *cred, + ns_ldap_error_t **errorp, ns_conn_user_t *conn_user) +{ + lookup_data_t ldata; + ns_ldap_result_t *result; + char **value; + int rc; + + *domainname = NULL; + *errorp = NULL; + + ldata.lkd_dn = dn; + ldata.lkd_service = NULL; + ldata.lkd_filter = _NIS_FILTER; + ldata.lkd_cred = cred; + ldata.lkd_user = conn_user; + + rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp); + if (rc != NS_LDAP_SUCCESS) + return (rc); + + value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN); + + if (value != NULL && value[0] != NULL) { + *domainname = strdup(value[0]); + if (*domainname == NULL) + rc = NS_LDAP_MEMORY; + } else { + rc = NS_LDAP_NOTFOUND; + } + + (void) __ns_ldap_freeResult(&result); return (rc); } @@ -4239,73 +4309,51 @@ static const char *dn2uid_attrs[] = { }; int -__ns_ldap_dn2uid(const char *dn, char **userID, const ns_cred_t *cred, +__ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred, ns_ldap_error_t **errorp) { - ns_ldap_result_t *result = NULL; - char *filter, *userdata; - char errstr[MAXERROR]; - char **value; - int rc = 0; - size_t len; + lookup_data_t ldata; + ns_ldap_result_t *result; + char **value; + int rc; *errorp = NULL; - *userID = NULL; + *userIDp = NULL; if ((dn == NULL) || (dn[0] == '\0')) return (NS_LDAP_INVALID_PARAM); - len = strlen(UIDDNFILTER) + strlen(dn) + 1; - filter = malloc(len); - if (filter == NULL) { - return (NS_LDAP_MEMORY); - } - (void) snprintf(filter, len, UIDDNFILTER, dn); - - len = strlen(UIDDNFILTER_SSD) + strlen(dn) + 1; - userdata = malloc(len); - if (userdata == NULL) { - free(filter); - return (NS_LDAP_MEMORY); - } - (void) snprintf(userdata, len, UIDDNFILTER_SSD, dn); + /* + * Many LDAP servers do not support using the dn in a search + * filter. As a result, we unfortunately cannot use __ns_ldap_list() + * to lookup the DN. Instead we perform a search with the baseDN + * being the DN we are looking for with a scope of 'base' to + * return the entry, as this should be supported by all LDAP servers. + */ + ldata.lkd_dn = dn; /* - * Unlike uid2dn, we DO want attribute mapping, so that - * "uid" is mapped to/from samAccountName, for example. + * Since we are looking up a user account by its DN, use the attribute + * and objectclass mappings (if present) for the passwd service. */ - rc = __ns_ldap_list("passwd", filter, - __s_api_merge_SSD_filter, - dn2uid_attrs, cred, 0, - &result, errorp, NULL, - userdata); - free(filter); - filter = NULL; - free(userdata); - userdata = NULL; - if (rc != NS_LDAP_SUCCESS) - goto out; + ldata.lkd_service = "passwd"; + ldata.lkd_filter = UIDDNFILTER; + ldata.lkd_cred = cred; + ldata.lkd_user = NULL; - if (result->entries_count > 1) { - (void) sprintf(errstr, - gettext("Too many entries are returned for %s"), dn); - MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr), - NS_LDAP_MEMORY); - rc = NS_LDAP_INTERNAL; - goto out; - } + rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp); + if (rc != NS_LDAP_SUCCESS) + return (rc); value = __ns_ldap_getAttr(result->entry, _P_UID); - if (value == NULL || value[0] == NULL) { + if (value != NULL && value[0] != NULL) { + *userIDp = strdup(value[0]); + if (*userIDp == NULL) + rc = NS_LDAP_MEMORY; + } else { rc = NS_LDAP_NOTFOUND; - goto out; } - *userID = strdup(value[0]); - rc = NS_LDAP_SUCCESS; - -out: (void) __ns_ldap_freeResult(&result); - result = NULL; return (rc); } diff --git a/usr/src/lib/libzfs/common/libzfs_config.c b/usr/src/lib/libzfs/common/libzfs_config.c index b33d86432d..e6c7ae025d 100644 --- a/usr/src/lib/libzfs/common/libzfs_config.c +++ b/usr/src/lib/libzfs/common/libzfs_config.c @@ -312,21 +312,9 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) zhp->zpool_config_size = zc.zc_nvlist_dst_size; if (zhp->zpool_config != NULL) { - uint64_t oldtxg, newtxg; - - verify(nvlist_lookup_uint64(zhp->zpool_config, - ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0); - verify(nvlist_lookup_uint64(config, - ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0); - nvlist_free(zhp->zpool_old_config); - if (oldtxg != newtxg) { - nvlist_free(zhp->zpool_config); - zhp->zpool_old_config = NULL; - } else { - zhp->zpool_old_config = zhp->zpool_config; - } + zhp->zpool_old_config = zhp->zpool_config; } zhp->zpool_config = config; diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index c5b8b60f0d..aa6bf358b8 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -3949,10 +3949,18 @@ char * zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, int name_flags) { - char *path, *env; + char *path, *type, *env; uint64_t value; char buf[64]; + /* + * vdev_name will be "root"/"root-0" for the root vdev, but it is the + * zpool name that will be displayed to the user. + */ + verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); + if (zhp != NULL && strcmp(type, "root") == 0) + return (zfs_strdup(hdl, zpool_get_name(zhp))); + env = getenv("ZPOOL_VDEV_NAME_PATH"); if (env && (strtoul(env, NULL, 0) > 0 || !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2))) @@ -4070,7 +4078,7 @@ after_open: return (tmp); } } else { - verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); + path = type; /* * If it's a raidz device, we need to stick in the parity level. diff --git a/usr/src/lib/libzpool/common/kernel.c b/usr/src/lib/libzpool/common/kernel.c index 0d43302861..d26955d83d 100644 --- a/usr/src/lib/libzpool/common/kernel.c +++ b/usr/src/lib/libzpool/common/kernel.c @@ -422,6 +422,83 @@ kobj_get_filesize(struct _buf *file, uint64_t *size) /* * ========================================================================= + * misc routines + * ========================================================================= + */ + +/* + * Find lowest one bit set. + * Returns bit number + 1 of lowest bit that is set, otherwise returns 0. + * This is basically a reimplementation of ffsll(), which is GNU specific. + */ +int +lowbit64(uint64_t i) +{ + register int h = 64; + if (i == 0) + return (0); + + if (i & 0x00000000ffffffffULL) + h -= 32; + else + i >>= 32; + + if (i & 0x0000ffff) + h -= 16; + else + i >>= 16; + + if (i & 0x00ff) + h -= 8; + else + i >>= 8; + + if (i & 0x0f) + h -= 4; + else + i >>= 4; + + if (i & 0x3) + h -= 2; + else + i >>= 2; + + if (i & 0x1) + h -= 1; + + return (h); +} + +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); +} + +/* + * ========================================================================= * kernel emulation setup & teardown * ========================================================================= */ diff --git a/usr/src/lib/libzpool/common/util.c b/usr/src/lib/libzpool/common/util.c index 8525b5f299..65ffa91ebb 100644 --- a/usr/src/lib/libzpool/common/util.c +++ b/usr/src/lib/libzpool/common/util.c @@ -23,6 +23,7 @@ * Copyright (c) 2016 by Delphix. All rights reserved. * Copyright 2017 RackTop Systems. * Copyright (c) 2017, Intel Corporation. + * Copyright 2020 Joyent, Inc. */ #include <assert.h> @@ -48,7 +49,7 @@ static void show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent) { vdev_stat_t *vs; - vdev_stat_t v0 = { 0 }; + vdev_stat_t *v0 = { 0 }; uint64_t sec; uint64_t is_log = 0; nvlist_t **child; @@ -56,6 +57,8 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent) char used[6], avail[6]; char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6]; + v0 = umem_zalloc(sizeof (*v0), UMEM_NOFAIL); + if (indent == 0 && desc != NULL) { (void) printf(" " " capacity operations bandwidth ---- errors ----\n"); @@ -72,7 +75,7 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent) &bias); if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c) != 0) - vs = &v0; + vs = v0; if (bias != NULL) { (void) snprintf(bias_suffix, sizeof (bias_suffix), @@ -105,6 +108,7 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent) vs->vs_space ? 6 : 0, vs->vs_space ? avail : "", rops, wops, rbytes, wbytes, rerr, werr, cerr); } + umem_free(v0, sizeof (*v0)); if (nvlist_lookup_nvlist_array(nv, ctype, &child, &children) != 0) return; diff --git a/usr/src/lib/nsswitch/ldap/common/getgrent.c b/usr/src/lib/nsswitch/ldap/common/getgrent.c index 184891c9d3..765059e86a 100644 --- a/usr/src/lib/nsswitch/ldap/common/getgrent.c +++ b/usr/src/lib/nsswitch/ldap/common/getgrent.c @@ -23,6 +23,7 @@ * Use is subject to license terms. * * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 Joyent, Inc. */ #include <grp.h> @@ -239,7 +240,7 @@ getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members) char *buffer; int buflen; int i, len; - int nss_result = 0; + int nss_result = 0; /* used by TEST_AND_ADJUST macro */ int firsttime; buffer = *bufpp; @@ -263,9 +264,8 @@ getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members) if (member_dn[0] == '\0') continue; - nss_result = __ns_ldap_dn2uid(member_dn, - &member_uid, NULL, &error); - if (nss_result != NS_LDAP_SUCCESS) { + if (__ns_ldap_dn2uid(member_dn, + &member_uid, NULL, &error) != NS_LDAP_SUCCESS) { (void) __ns_ldap_freeError(&error); error = NULL; continue; diff --git a/usr/src/man/man1/audioconvert.1 b/usr/src/man/man1/audioconvert.1 index 3e674ce292..8dd302761c 100644 --- a/usr/src/man/man1/audioconvert.1 +++ b/usr/src/man/man1/audioconvert.1 @@ -3,23 +3,20 @@ .\" 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] -.TH AUDIOCONVERT 1 "Feb 16, 2001" +.TH AUDIOCONVERT 1 "Feb 8, 2020" .SH NAME audioconvert \- convert audio file formats .SH SYNOPSIS -.LP .nf \fBaudioconvert\fR [\fB-pF\fR] [\fB-f\fR \fIoutfmt\fR] [\fB-o\fR \fIoutfile\fR] [ [\fB-i\fR \fIinfmt\fR] [\fIfile\fR]...] ... .fi .SH DESCRIPTION -.sp -.LP \fBaudioconvert\fR converts audio data between a set of supported audio encodings and file formats. It can be used to compress and decompress audio data, to add audio file headers to raw audio data files, and to convert between -standard data encodings, such as -law and linear PCM. +standard data encodings, such as u-law and linear PCM. .sp .LP If no filenames are present, \fBaudioconvert\fR reads the data from the @@ -50,8 +47,6 @@ overwritten with the converted data. The \fBfile\fR(1) command decodes and prints the audio data format of Sun audio files. .SH OPTIONS -.sp -.LP The following options are supported: .sp .ne 2 @@ -141,8 +136,6 @@ input. .RE .SS "Format Specification" -.sp -.LP The syntax for the input and output format specification is: .sp .LP @@ -190,7 +183,7 @@ values are: \fB\fBulaw\fR\fR .ad .RS 13n -\fBCCITT G.711\fR -law encoding. This is an 8-bit format primarily used for +\fBCCITT G.711\fR u-law encoding. This is an 8-bit format primarily used for telephone quality speech. .RE @@ -240,7 +233,7 @@ Same as \fBlinear16\fR. .RS 13n \fBCCITT G.721\fR compression format. This encoding uses Adaptive Delta Pulse Code Modulation (ADPCM) with 4-bit precision. It is primarily used for -compressing -law voice data (achieving a 2:1 compression ratio). +compressing u-law voice data (achieving a 2:1 compression ratio). .RE .sp @@ -251,7 +244,7 @@ compressing -law voice data (achieving a 2:1 compression ratio). .RS 13n \fBCCITT G.723\fR compression format. This encoding uses Adaptive Delta Pulse Code Modulation (ADPCM) with 3-bit precision. It is primarily used for -compressing -law voice data (achieving an 8:3 compression ratio). The audio +compressing u-law voice data (achieving an 8:3 compression ratio). The audio quality is similar to \fBG.721,\fR but may result in lower quality when used for non-speech data. .RE @@ -327,13 +320,10 @@ unrecognized file header. .RE .SH USAGE -.sp -.LP See \fBlargefile\fR(5) for the description of the behavior of -\fBaudioconvert\fR when encountering files greater than or equal to 2 Gbyte ( -2^31 bytes). +\fBaudioconvert\fR when encountering files greater than or equal to 2 Gbyte +(2^31 bytes). .SH EXAMPLES -.LP \fBExample 1 \fRRecording and compressing voice data before storing it .sp .LP @@ -377,32 +367,10 @@ example% \fBaudioconvert -p -i voice -f sun *.au\fR .in -2 .sp -.SH ATTRIBUTES -.sp -.LP -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Architecture SPARC, x86 -_ -Interface Stability Evolving -.TE - .SH SEE ALSO -.sp -.LP -\fBaudioplay\fR(1), \fBaudiorecord\fR(1), \fBfile\fR(1), \fBattributes\fR(5), +\fBaudioplay\fR(1), \fBaudiorecord\fR(1), \fBfile\fR(1), \fBlargefile\fR(5) .SH NOTES -.sp -.LP The algorithm used for converting multi-channel data to mono is implemented by simply summing the channels together. If the input data is perfectly in phase (as would be the case if a mono file is converted to stereo and back to mono), diff --git a/usr/src/man/man1/audioctl.1 b/usr/src/man/man1/audioctl.1 index a26bce598e..1916b82ed7 100644 --- a/usr/src/man/man1/audioctl.1 +++ b/usr/src/man/man1/audioctl.1 @@ -11,8 +11,9 @@ .\" .\" .\" Copyright 2011 Nexenta Systems, Inc. All rights reserved. +.\" Copyright 2020 Peter Tribble. .\" -.TH AUDIOCTL 1 "Mar 18, 2011" +.TH AUDIOCTL 1 "Feb 8, 2020" .SH NAME audioctl - audio device control command line interface .SH SYNOPSIS @@ -27,22 +28,27 @@ audioctl - audio device control command line interface .LP .nf -\fBaudioctl\fR \fBshow-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fB] [\fIcontrol\fR ...] +\fBaudioctl\fR \fBshow-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] [\fIcontrol\fR ...] .fi .LP .nf -\fBaudioctl\fR \fBset-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fB] \fIcontrol\fR \fIvalue\fR +\fBaudioctl\fR \fBset-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] \fIcontrol\fR \fIvalue\fR .fi .LP .nf -\fBaudioctl\fR \fBsave-controls\fR [\fB-d\fR \fIdevice\fB] [\fB-f\fR] \fIfile\fR +\fBaudioctl\fR \fBsave-controls\fR [\fB-d\fR \fIdevice\fR] [\fB-f\fR] \fIfile\fR .fi .LP .nf -\fBaudioctl\fR \fBload-controls\fR [\fB-d\fR \fIdevice\fB] \fIfile\fR +\fBaudioctl\fR \fBload-controls\fR [\fB-d\fR \fIdevice\fR] \fIfile\fR +.fi + +.LP +.nf +\fBaudioctl\fR \fBhelp\fR .fi .SH DESCRIPTION @@ -64,7 +70,7 @@ List all the audio devices on the system. .sp .ne 2 .na -\fBshow-device\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] [\fBcontrol\fR ... ] +\fBshow-device\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] .ad .sp .6 .RS 4n @@ -76,7 +82,7 @@ will be displayed. .sp .ne 2 .na -\fBshow-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] +\fBshow-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] [\fBcontrol\fR ... ] .ad .sp .6 .RS 4n @@ -89,7 +95,7 @@ the \fB-v\fR option is specified, then more detail will be displayed. .sp .ne 2 .na -\fBset-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fB] \fIcontrol\fR \fIvalue\fR +\fBset-control\fR [\fB-v\fR] [\fB-d\fR \fIdevice\fR] \fIcontrol\fR \fIvalue\fR .ad .sp .6 .RS 4n @@ -101,7 +107,7 @@ option is specified, then more verbose output be displayed. .sp .ne 2 .na -\fBsave-controls\fR [\fB-f\fR] [\fB-d\fR \fIdevice\fB] \fIfile\fR +\fBsave-controls\fR [\fB-f\fR] [\fB-d\fR \fIdevice\fR] \fIfile\fR .ad .sp .6 .RS 4n @@ -113,7 +119,7 @@ or modify an existing file unless \fB-f\fR (force) is specified. .sp .ne 2 .na -\fBload-controls\fR [\fB-d\fR \fIdevice\fB] \fIfile\fR +\fBload-controls\fR [\fB-d\fR \fIdevice\fR] \fIfile\fR .ad .sp .6 .RS 4n @@ -122,6 +128,16 @@ into a \fIdevice\fR (or all audio devices if not specified). .RE +.sp +.ne 2 +.na +\fBhelp\fR +.ad +.sp .6 +.RS 4n +Display the usage message. +.RE + .SH ENVIRONMENT VARIABLES .ne 2 .na @@ -133,21 +149,7 @@ is not specified on the command line. If this variable is not set, \fB/dev/audio\fR is used. .RE - .SH ATTRIBUTES -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Interface Stability See below. -.TE -.LP The \fBaudioctl\fR command and its subcommands are Committed. The names of controls, their values, and device names are Uncommitted. The display output is intended for human consumption, and is Not An @@ -156,4 +158,4 @@ Interface. The format of the state files used by the Private. .SH SEE ALSO \fBaudioplay\fR(1), \fBaudiorecord\fR(1), \fBdsp\fR(7I), -\fBmixer\fR(7I), \fBattributes\fR(5) +\fBmixer\fR(7I) diff --git a/usr/src/man/man1/audioplay.1 b/usr/src/man/man1/audioplay.1 index 324e26940b..64f6115201 100644 --- a/usr/src/man/man1/audioplay.1 +++ b/usr/src/man/man1/audioplay.1 @@ -3,17 +3,15 @@ .\" 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] -.TH AUDIOPLAY 1 "May 13, 2017" +.TH AUDIOPLAY 1 "Feb 8, 2020" .SH NAME audioplay \- play audio files .SH SYNOPSIS -.LP .nf \fBaudioplay\fR [\fB-iV\fR] [\fB-v\fR \fIvol\fR] [\fB-d\fR \fIdev\fR] [\fIfile\fR]... .fi .SH DESCRIPTION -.LP The \fBaudioplay\fR utility copies the named audio files (or the standard input if no filenames are present) to the audio device. If no input file is specified and standard input is a tty, the program exits with an error message. @@ -31,7 +29,6 @@ ignored. This allows, for instance, data sampled at 8012 Hz to be played on an audio device that only supports 8000 Hz. If the \fB-V\fR option is present, such deviations are flagged with warning messages. .SH OPTIONS -.LP The following options are supported: .sp .ne 2 @@ -84,7 +81,7 @@ the audio device or when sample rate deviations are detected. .sp .ne 2 .na -\fB\fB\(mi\e?\fR\fR +\fB\fB-?\fR\fR .ad .RS 11n \fIHelp\fR: Prints a command line usage message. @@ -105,9 +102,8 @@ variable is consulted (see below). .RE .SH USAGE -.LP See \fBlargefile\fR(5) for the description of the behavior of \fBaudioplay\fR -when encountering files greater than or equal to 2 Gbyte ( 2^31 bytes). +when encountering files greater than or equal to 2 Gbyte (2^31 bytes). .SH ENVIRONMENT VARIABLES .ne 2 .na @@ -130,29 +126,10 @@ specified explicitly in the search path. If the \fBAUDIOPATH\fR variable is not set, only the current directory is searched. .RE -.SH ATTRIBUTES -.LP -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Architecture SPARC, x86 -_ -Interface Stability Committed -.TE - .SH SEE ALSO -.LP \fBaudioconvert\fR(1), \fBaudiorecord\fR(1), -\fBattributes\fR(5), \fBlargefile\fR(5), \fBaudio\fR(7I) +\fBlargefile\fR(5), \fBaudio\fR(7I) .SH BUGS -.LP \fBaudioplay\fR currently supports a limited set of audio format conversions. If the audio file is not in a format supported by the audio device, it must first be converted. For example, to convert to voice format on the fly, use the diff --git a/usr/src/man/man1/audiorecord.1 b/usr/src/man/man1/audiorecord.1 index 8f4354a524..7ffedbd976 100644 --- a/usr/src/man/man1/audiorecord.1 +++ b/usr/src/man/man1/audiorecord.1 @@ -1,28 +1,27 @@ '\" te .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright 2020 Peter Tribble. .\" 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] -.TH AUDIORECORD 1 "May 13, 2017" +.TH AUDIORECORD 1 "Feb 8, 2020" .SH NAME audiorecord \- record an audio file .SH SYNOPSIS -.LP .nf -\fBaudiorecord\fR [\fB-af\fR] [\fB-v\fR \fIvol\fR] [\fB-c\fR \fIchannels\fR] [\fI-s\fR \fIrate\fR] +\fBaudiorecord\fR [\fB-af\fR] [\fB-v\fR \fIvol\fR] [\fB-c\fR \fIchannels\fR] [\fB-s\fR \fIrate\fR] [\fB-e\fR \fIencoding\fR] [\fB-t\fR \fItime\fR] [\fB-i\fR \fIinfo\fR] [\fB-d\fR \fIdev\fR] - [\fB-T\fR \fBau\fR | \fBaif\fR[\fBf\fR] | \fBwav\fR] [\fIfile\fR[.\fBau\fR|.\fBaif\fR[\fBf\fR]]|.\fBwav\fR] + [\fB-T\fR \fBau\fR|\fBaif\fR[\fBf\fR]|\fBwav\fR] [\fIfile\fR[.\fBau\fR|.\fBaif\fR[\fBf\fR]|.\fBwav\fR]] .fi .SH DESCRIPTION -.LP The \fBaudiorecord\fR utility copies audio data from the audio device to a named audio file, or to the standard output if no filename is present. If no output file is specified and standard output is a tty, the program exits with an error message. .sp .LP -By default, monaural audio data is recorded at 8 kHz and encoded in \fB-law\fR +By default, monaural audio data is recorded at 8 kHz and encoded in \fBu-law\fR format. If the audio device supports additional configurations, the \fB-c\fR, \fB-s\fR, and \fB-e\fR options may be used to specify the data format. The output file is prefixed by an audio file header that identifies the format of @@ -37,12 +36,11 @@ example, Control-c) is received. If the \fB-t\fR option is specified, If the audio device is unavailable, that is, if another process currently has read access, \fBaudiorecord\fR prints an error message and exits immediately. .SH OPTIONS -.LP The following options are supported: .sp .ne 2 .na -\fB\fB-\e?\fR\fR +\fB\fB-?\fR\fR .ad .RS 24n \fIHelp\fR: Prints a command line usage message. @@ -165,7 +163,7 @@ set by any process. .SH OPERANDS .ne 2 .na -\fB\fIfile\fR[\fB\&.au\fR|\fB\&.aif\fR[\fBf\fR]]|\fB\&.wav\fR\fR +\fIfile\fR[\fB\&.au\fR|\fB\&.aif\fR[\fBf\fR]|\fB\&.wav\fR] .ad .sp .6 .RS 4n @@ -181,9 +179,8 @@ file suffix. .RE .SH USAGE -.LP See \fBlargefile\fR(5) for the description of the behavior of \fBaudiorecord\fR -when encountering files greater than or equal to 2 Gbyte ( 2^31 bytes). +when encountering files greater than or equal to 2 Gbyte (2^31 bytes). .SH ENVIRONMENT VARIABLES .ne 2 .na @@ -195,24 +192,6 @@ is supplied. If the \fBAUDIODEV\fR variable is not set, \fB/dev/audio\fR is used. .RE -.SH ATTRIBUTES -.LP -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Architecture SPARC, x86 -_ -Interface Stability Committed -.TE - .SH SEE ALSO -.LP \fBaudioconvert\fR(1), \fBaudioplay\fR(1), -\fBattributes\fR(5), \fBlargefile\fR(5), \fBaudio\fR(7I) +\fBlargefile\fR(5), \fBaudio\fR(7I) diff --git a/usr/src/man/man1/audiotest.1 b/usr/src/man/man1/audiotest.1 index 8c122094df..67e6a77b6e 100644 --- a/usr/src/man/man1/audiotest.1 +++ b/usr/src/man/man1/audiotest.1 @@ -1,30 +1,28 @@ '\" te .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright 2020 Peter Tribble. .\" 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] -.TH AUDIOTEST 1 "May 13, 2017" +.TH AUDIOTEST 1 "Feb 8, 2020" .SH NAME audiotest \- test audio device .SH SYNOPSIS -.LP .nf -\fBaudiotest\fR [\fB-24571\fR] [\fIdev\fR] ... +\fBaudiotest\fR [\fB-2457\fR] [\fB-l\fR] [\fB-r\fR \fIrate\fR] [\fIdev\fR] ... .fi .SH DESCRIPTION -.LP The \fBaudiotest\fR utility runs a test for the named audio device (or all audio devices found on the system if none is given). The test includes playing an audio sample over each channel and measuring the rate of playback for clock drift. .SH OPTIONS -.LP The following options are supported: .sp .ne 2 .na -\fB\fB-1\fR\fR +\fB-l\fR .ad .RS 6n Loop mode. The test is run in an infinite loop. @@ -33,7 +31,16 @@ Loop mode. The test is run in an infinite loop. .sp .ne 2 .na -\fB\fB-2\fR\fR +\fB-r\fR \fIrate\fR +.ad +.RS 6n +Sample rate. By default 48000Hz is used. +.RE + +.sp +.ne 2 +.na +\fB-2\fR .ad .RS 6n Stereo (2-channel) mode. This is the default mode. Playback assumes 2 channels @@ -43,7 +50,7 @@ are present. .sp .ne 2 .na -\fB\fB-4\fR\fR +\fB-4\fR .ad .RS 6n Quadraphonic mode (4-channel surround). The test assumes that four surround @@ -53,7 +60,7 @@ channels are present. .sp .ne 2 .na -\fB\fB-5\fR\fR +\fB-5\fR .ad .RS 6n Surround sound mode (5.1). The test checks the left, right, surround left, @@ -64,7 +71,7 @@ tested. .sp .ne 2 .na -\fB\fB-7\fR\fR +\fB-7\fR .ad .RS 6n Surround sound mode (7.1). The test checks the left, right, surround left, @@ -72,38 +79,23 @@ surround right, back surround left, back surround right, and center channels. The low frequency effects channel is not tested. .RE +.sp +.LP +If multiple modes are specified, the last one specified is used. + .SH OPERANDS .ne 2 .na -\fB\fIdev\fR\fR +\fIdev\fR .ad .RS 7n -The path the device to test, for example, \fB/dev/dsp0\fR. +The path to the device to test, for example, \fB/dev/dsp0\fR. .RE -.SH ATTRIBUTES -.LP -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Architecture SPARC, x86 -_ -Interface Stability Committed -.TE - .SH SEE ALSO -.LP \fBaudioconvert\fR(1), \fBaudiorecord\fR(1), -\fBattributes\fR(5), \fBaudio\fR(7I) +\fBaudio\fR(7I) .SH BUGS -.LP \fBaudiotest\fR has no way to detect the number of actual audio channels supported by the physical device. .sp diff --git a/usr/src/man/man1/dhcpinfo.1 b/usr/src/man/man1/dhcpinfo.1 index 24b8918a8b..7222ffeb60 100644 --- a/usr/src/man/man1/dhcpinfo.1 +++ b/usr/src/man/man1/dhcpinfo.1 @@ -1,14 +1,14 @@ '\" te .\" Copyright (c) 1992-1996 Competitive Automation, Inc. .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved. +.\" Copyright (c) 2020 Peter Tribble .\" 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] -.TH DHCPINFO 1 "May 15, 2009" +.TH DHCPINFO 1 "Feb 13, 2020" .SH NAME dhcpinfo \- display values of parameters received through DHCP .SH SYNOPSIS -.LP .nf \fBdhcpinfo\fR [\fB-c\fR] [\fB-i\fR \fIinterface\fR] [\fB-n\fR \fIlimit\fR] [\fB-v 4|6\fR] \fIcode\fR .fi @@ -19,14 +19,11 @@ dhcpinfo \- display values of parameters received through DHCP .fi .SH DESCRIPTION -.sp -.LP The \fBdhcpinfo\fR utility prints the \fBDHCP\fR-supplied value(s) of the parameter requested on the command line. The parameter can be identified either by its numeric code in the \fBDHCP\fR specification, or by its mnemonic identifier, as listed in \fBdhcp_inittab\fR(4). This command is intended to be -used in command substitutions in the shell scripts invoked by \fBinit\fR(1M) at -system boot. It first contacts the \fBDHCP\fR client daemon at system boot or +used in command substitutions in the shell scripts invoked at system boot or in event scripts as described in \fBdhcpagent\fR(1M). It first contacts the DHCP client daemon \fBdhcpagent\fR(1M) to verify that \fBDHCP\fR has successfully completed on the requested interface. If \fBDHCP\fR has @@ -41,8 +38,6 @@ Extensions\fR for more details on DHCPv4 parameters, and RFC 3315, Dynamic Host Configuration Protocol for IPv6 (DHCPv6), for more details on DHCPv6 parameters. .SS "Output Format" -.sp -.LP The output from \fBdhcpinfo\fR consists of one or more lines of \fBASCII\fR text; the format of the output depends upon the requested parameter. The number of values returned per line and the total number of lines output for a given @@ -81,8 +76,6 @@ T} \fBDOMAIN\fR .TE .SH OPTIONS -.sp -.LP The following options are supported: .sp .ne 2 @@ -130,16 +123,14 @@ Limits the list of values displayed to \fIlimit\fR lines. .sp .ne 2 .na -\fB\fB-v\fR\fB4 | 6\fR\fR +\fB\fB-v 4|6\fR\fR .ad .RS 16n -Specifies the DHCP version to query. Use \fB-v4\fRfor DHCPv4 and \fB-v6\fR for -DHCPv6. +Specifies the DHCP version to query. Use \fB-v 4\fR for DHCPv4 and \fB-v 6\fR +for DHCPv6. .RE .SH OPERANDS -.sp -.LP The following operands are supported: .sp .ne 2 @@ -163,8 +154,6 @@ Mnemonic symbol for the requested \fBDHCP\fR parameter, as listed in .RE .SH EXIT STATUS -.sp -.LP The following exit values are returned: .sp .ne 2 @@ -214,8 +203,6 @@ System error (should never occur). .RE .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -230,9 +217,7 @@ Interface Stability Committed .TE .SH SEE ALSO -.sp -.LP -\fBdhcpagent\fR(1M), \fBifconfig\fR(1M), \fBinit\fR(1M), \fBdhcp_inittab\fR(4), +\fBdhcpagent\fR(1M), \fBifconfig\fR(1M), \fBdhcp_inittab\fR(4), \fBattributes\fR(5) .sp .LP diff --git a/usr/src/man/man1/getfacl.1 b/usr/src/man/man1/getfacl.1 index a90b61deff..8eca23b106 100644 --- a/usr/src/man/man1/getfacl.1 +++ b/usr/src/man/man1/getfacl.1 @@ -1,20 +1,18 @@ '\" te .\" \&.Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright (c) 2020 Peter Tribble. .\" 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] -.TH GETFACL 1 "Nov 5, 1994" +.TH GETFACL 1 "Feb 8, 2020" .SH NAME getfacl \- display discretionary file information .SH SYNOPSIS -.LP .nf \fBgetfacl\fR [\fB-ad\fR] \fIfile\fR... .fi .SH DESCRIPTION -.sp -.LP For each argument that is a regular file, special file, or named pipe, the \fBgetfacl\fR utility displays the owner, the group, and the Access Control List (\fBACL\fR). For each directory argument, \fBgetfacl\fR displays the @@ -22,6 +20,13 @@ owner, the group, and the \fBACL\fR and/or the default \fBACL\fR. Only directories contain default \fBACL\fRs. .sp .LP +The \fBgetfacl\fR utility will fail if executed on a file system that supports +NFSv4 \fBACL\fRs. See \fBacl\fR(5) for a description of the difference +between the older POSIX-draft \fBACL\fRs and the newer NFSv4 \fBACL\fRs. The +\fBls\fR(1) utility, when used with the \fB-v\fR or \fB-V\fR options, will +display \fBACL\fRs on all types of file system. +.sp +.LP The \fBgetfacl\fR utility may be executed on a file system that does not support \fBACL\fRs. It reports the \fBACL\fR based on the base permission bits. .sp @@ -30,8 +35,6 @@ With no options specified, \fBgetfacl\fR displays the filename, the file owner, the file group owner, and both the \fBACL\fR and the default \fBACL\fR, if it exists. .SH OPTIONS -.sp -.LP The following options are supported: .sp .ne 2 @@ -54,8 +57,6 @@ Displays the filename, the file owner, the file group owner, and the default .RE .SH OPERANDS -.sp -.LP The following operands are supported: .sp .ne 2 @@ -67,26 +68,24 @@ The path name of a regular file, special file, or named pipe. .RE .SH OUTPUT -.sp -.LP The format for \fBACL\fR output is as follows: .sp .in +2 .nf -# file: filename -# owner: uid -# group: gid -user::perm -user:uid:perm -group::perm -group:gid:perm -mask:perm -other:perm -default:user::perm -default:user:uid:perm -default:group::perm -default:group:gid:perm -default:mask:perm +# file: filename +# owner: uid +# group: gid +user::perm +user:uid:perm +group::perm +group:gid:perm +mask:perm +other:perm +default:user::perm +default:user:uid:perm +default:group::perm +default:group:gid:perm +default:mask:perm default:other:perm .fi .in -2 @@ -115,7 +114,7 @@ permissions that are granted to the specified users. .LP The \fBgroup\fR entry without a group \fBID\fR indicates the permissions that are granted to the file group owner. One or more additional group entries -indicate the permissions that are granted to the specified groups. +indicate the permissions that are granted to the specified groups. .sp .LP The \fBmask\fR entry indicates the \fBACL\fR mask permissions. These are the @@ -143,18 +142,17 @@ character \fB\(mi\fR\&. The \fBperm\fR is displayed in the following order: holder character appears. .sp .LP -If you use the \fBchmod\fR(1) command to change the file group owner +If you use the \fBchmod\fR(1) command to change the file group owner permissions on a file with \fBACL\fR entries, both the file group owner permissions and the \fBACL\fR mask are changed to the new permissions. Be aware that the new \fBACL\fR mask permissions may change the effective permissions for additional users and groups who have \fBACL\fR entries on the file. .sp .LP -In order to indicate that the \fBACL\fR mask restricts an \fBACL\fR entry, +In order to indicate that the \fBACL\fR mask restricts an \fBACL\fR entry, \fBgetfacl\fR displays an additional tab character, pound sign (\fB#\fR), and the actual permissions granted, following the entry. .SH EXAMPLES -.LP \fBExample 1 \fRDisplaying file information .sp .LP @@ -258,7 +256,6 @@ default:other::\|\(mi\|\(mi\|\(mi .sp .SH FILES -.sp .ne 2 .na \fB\fB/etc/passwd\fR\fR @@ -277,8 +274,6 @@ group file .RE .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -293,13 +288,10 @@ Interface Stability Evolving .TE .SH SEE ALSO -.sp -.LP \fBchmod\fR(1), \fBls\fR(1), \fBsetfacl\fR(1), \fBacl\fR(2), -\fBaclsort\fR(3SEC), \fBgroup\fR(4), \fBpasswd\fR(4), \fBattributes\fR(5) +\fBaclsort\fR(3SEC), \fBgroup\fR(4), \fBpasswd\fR(4), \fBacl\fR(5), +\fBattributes\fR(5) .SH NOTES -.sp -.LP The output from \fBgetfacl\fR is in the correct format for input to the \fBsetfacl\fR \fB-f\fR command. If the output from \fBgetfacl\fR is redirected to a file, the file may be used as input to \fBsetfacl\fR. In this way, a user diff --git a/usr/src/man/man1/setfacl.1 b/usr/src/man/man1/setfacl.1 index 11c7b644f3..526e2c0321 100644 --- a/usr/src/man/man1/setfacl.1 +++ b/usr/src/man/man1/setfacl.1 @@ -1,13 +1,13 @@ '\" te .\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright (c) 2020 Peter Tribble. .\" 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] -.TH SETFACL 1 "Dec 19, 2006" +.TH SETFACL 1 "Feb 8, 2020" .SH NAME setfacl \- modify the Access Control List (ACL) for a file or files .SH SYNOPSIS -.LP .nf \fBsetfacl\fR [\fB-r\fR] \fB-s\fR \fIacl_entries\fR \fIfile\fR .fi @@ -23,14 +23,18 @@ setfacl \- modify the Access Control List (ACL) for a file or files .fi .SH DESCRIPTION -.sp -.LP For each file specified, \fBsetfacl\fR either replaces its entire \fBACL\fR, including the default \fBACL\fR on a directory, or it adds, modifies, or deletes one or more \fBACL\fR entries, including default entries on directories. .sp .LP +The \fBsetfacl\fR utility can only manipulate POSIX-draft \fBACL\fRs. See +\fBacl\fR(5) for a description of the difference between the older POSIX-draft +\fBACL\fRs and the newer NFSv4 \fBACL\fRs. The \fBchmod\fR(1) utility can +be used to manipulate \fBACL\fRs on all types of file system. +.sp +.LP When the \fBsetfacl\fR command is used, it can result in changes to the file permission bits. When the user \fBACL\fR entry for the file owner is changed, the file owner class permission bits are modified. When the group \fBACL\fR @@ -63,8 +67,6 @@ supports POSIX-draft ACLS (or \fBaclent_t\fR style ACLs). Use the \fBchmod\fR command to set ACLs on files in a ZFS file system, which supports NFSv4-style ACLS (or \fBace_t\fR style ACLs). .SS "\fIacl_entries\fR Syntax" -.sp -.LP For the \fB-m\fR and \fB-s\fR options, \fIacl_entries\fR are one or more comma-separated \fBACL\fR entries. .sp @@ -114,12 +116,12 @@ c c l l . \fBACL\fR Entry Description _ -u[ser]::\fIperms\fR File owner permissions. -g[roup]::\fIperms\fR File group owner permissions. -o[ther]:\fIperms\fR T{ +u[ser]::\fIperms\fR File owner permissions. +g[roup]::\fIperms\fR File group owner permissions. +o[ther]:\fIperms\fR T{ Permissions for users other than the file owner or members of file group owner. T} -m[ask]:\fIperms\fR T{ +m[ask]:\fIperms\fR T{ The \fBACL\fR mask. The mask entry indicates the maximum permissions allowed for users (other than the owner) and for groups. The mask is a quick way to change permissions on all the users and groups. T} u[ser]:\fIuid:perms\fR T{ @@ -128,12 +130,12 @@ T} g[roup]:\fIgid:perms\fR T{ Permissions for a specific group. For \fIgid\fR, you can specify either a group name or a numeric GID. T} -d[efault]:u[ser]::\fIperms\fR Default file owner permissions. -d[efault]:g[roup]::\fIperms\fR Default file group owner permissions. -d[efault]:o[ther]:\fIperms\fR T{ +d[efault]:u[ser]::\fIperms\fR Default file owner permissions. +d[efault]:g[roup]::\fIperms\fR Default file group owner permissions. +d[efault]:o[ther]:\fIperms\fR T{ Default permissions for users other than the file owner or members of the file group owner. T} -d[efault]:m[ask]:\fIperms\fR Default \fBACL\fR mask. +d[efault]:m[ask]:\fIperms\fR Default \fBACL\fR mask. d[efault]:u[ser]:\fIuid\fR:\fIperms\fR T{ Default permissions for a specific user. For \fIuid\fR, you can specify either a user name or a numeric UID. T} @@ -148,8 +150,6 @@ For the \fB-d\fR option, \fIacl_entries\fR are one or more comma-separated \fBACL\fR entries without permissions. Notice that the entries for file owner, file group owner, \fBACL\fR mask, and others can not be deleted. .SH OPTIONS -.sp -.LP The options have the following meaning: .sp .ne 2 @@ -293,7 +293,6 @@ group\fR entries with the same \fIgid\fR. .RE .SH EXAMPLES -.LP \fBExample 1 \fRAdding read permission only .sp .LP @@ -353,7 +352,6 @@ The following example sets the same \fBACL\fR on file \fBabc\fR as the file .sp .SH FILES -.sp .ne 2 .na \fB\fB/etc/passwd\fR\fR @@ -372,7 +370,6 @@ group file .RE .SH SEE ALSO -.sp -.LP \fBchmod\fR(1), \fBgetfacl\fR(1), \fBumask\fR(1), \fBaclcheck\fR(3SEC), -\fBaclsort\fR(3SEC), \fBgroup\fR(4), \fBpasswd\fR(4), \fBattributes\fR(5) +\fBaclsort\fR(3SEC), \fBgroup\fR(4), \fBpasswd\fR(4), \fBacl\fR(5), +\fBattributes\fR(5) diff --git a/usr/src/man/man1m/dhcpagent.1m b/usr/src/man/man1m/dhcpagent.1m index 90cc77e321..780af863ee 100644 --- a/usr/src/man/man1m/dhcpagent.1m +++ b/usr/src/man/man1m/dhcpagent.1m @@ -4,17 +4,15 @@ .\" 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] -.TH DHCPAGENT 1M "Jun 30, 2017" +.TH DHCPAGENT 1M "Feb 13, 2020" .SH NAME dhcpagent \- Dynamic Host Configuration Protocol (DHCP) client daemon .SH SYNOPSIS -.LP .nf \fBdhcpagent\fR [\fB-a\fR] [ \fB-d\fR \fIn\fR] [\fB-f\fR] [\fB-v\fR] .fi .SH DESCRIPTION -.LP \fBdhcpagent\fR implements the client half of the Dynamic Host Configuration Protocol \fB(DHCP)\fR for machines running illumos software. .sp @@ -141,7 +139,6 @@ If the name does not start with a stock symbol and a comma, it is automatically prefixed with \fBSUNW\fR. .RE .SS "Messages" -.LP The \fBdhcpagent\fR daemon writes information and error messages in five categories: .sp @@ -211,7 +208,6 @@ to the system logger \fBsyslog\fR(3C) at the appropriate matching priority and with a facility identifier \fBLOG_DAEMON\fR. When \fBdhcpagent\fR is run with the \fB-f\fR option, all messages are directed to standard error. .SS "DHCP Events and User-Defined Actions" -.LP If an executable (binary or script) is placed at \fB/etc/dhcp/eventhook\fR, the \fBdhcpagent\fR daemon will automatically run that program when any of the following events occur: @@ -351,7 +347,6 @@ is terminated by a \fBSIGKILL\fR signal. .LP See EXAMPLES for an example event program. .SH OPTIONS -.LP The following options are supported: .sp .ne 2 @@ -426,7 +421,6 @@ Provide verbose output useful for debugging site configuration problems. .RE .SH EXAMPLES -.LP \fBExample 1 \fRExample Event Program .sp .LP @@ -454,7 +448,7 @@ case $2 in ;; "EXTEND") echo "Lease extended for " \e - `sbin/dhcpinfo -i $1 LeaseTim`" seconds" + `/sbin/dhcpinfo -i $1 LeaseTim`" seconds" ;; "EXTEND6") echo "New lease information obtained on $i" @@ -823,7 +817,6 @@ Location of a DHCP event program. .RE .SH ATTRIBUTES -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -838,7 +831,6 @@ Interface Stability Committed .TE .SH SEE ALSO -.LP \fBdhcpinfo\fR(1), \fBifconfig\fR(1M), \fBinit\fR(1M), \fBin.mpathd\fR(1M), \fBin.ndpd\fR(1M), \fBipadm\fR(1M), \fBnwamcfg\fR(1M), \fBsyslog\fR(3C), \fBnodename\fR(4), \fBresolv.conf\fR(4), \fBattributes\fR(5), \fBdhcp\fR(5) @@ -863,7 +855,6 @@ Microsystems. February 2006. Droms, R. \fIRFC 3315, Dynamic Host Configuration Protocol for IPv6 (DHCPv6)\fR. Cisco Systems. July 2003. .SH NOTES -.LP The \fBdhcpagent\fR daemon can be used on IPv4 logical interfaces, just as with physical interfaces. When used on a logical interface, the daemon automatically constructs a Client ID value based on the DUID and IAID values, according to diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m index b5d20e9ee7..5a793062f2 100644 --- a/usr/src/man/man1m/zpool.1m +++ b/usr/src/man/man1m/zpool.1m @@ -24,8 +24,8 @@ .\" Copyright (c) 2012, 2017 by Delphix. All rights reserved. .\" Copyright 2017 Nexenta Systems, Inc. .\" Copyright (c) 2017 Datto Inc. -.\" Copyright (c) 2017 George Melikov. All Rights Reserved. -.\" Copyright 2019 Joyent, Inc. +.\" Copyright (c) 2018 George Melikov. All Rights Reserved. +.\" Copyright 2020 Joyent, Inc. .\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved. .\" .Dd August 30, 2019 @@ -117,10 +117,10 @@ .Op Ar device Ns ... .Nm .Cm iostat -.Op Fl v +.Op Oo Fl lq Oc | Ns Fl rw .Op Fl T Sy u Ns | Ns Sy d -.Op Fl gLP -.Oo Ar pool Oc Ns ... +.Op Fl ghHLnpPvy +.Oo Oo Ar pool Ns ... Oc Ns | Ns Oo Ar pool vdev Ns ... Oc Ns | Ns Oo Ar vdev Ns ... Oc Oc .Op Ar interval Op Ar count .Nm .Cm labelclear @@ -185,7 +185,7 @@ .Ar pool newpool .Nm .Cm status -.Op Fl DigLPtvx +.Op Fl DigLpPstvx .Op Fl T Sy u Ns | Ns Sy d .Oo Ar pool Oc Ns ... .Op Ar interval Op Ar count @@ -1607,25 +1607,48 @@ with no flags on the relevant target devices. .It Xo .Nm .Cm iostat +.Op Oo Fl lq Oc | Ns Fl rw .Op Fl T Sy u Ns | Ns Sy d -.Op Fl gLPv -.Oo Ar pool Oc Ns ... +.Op Fl ghHLnpPvy +.Oo Oo Ar pool Ns ... Oc Ns | Ns Oo Ar pool vdev Ns ... Oc Ns | Ns Oo Ar vdev Ns ... Oc Oc .Op Ar interval Op Ar count .Xc -Displays I/O statistics for the given pools. +Displays I/O statistics for the given pools/vdevs. +Physical I/Os may be observed via +.Xr iostat 1 . +If writes are located nearby, they may be merged into a single larger operation. +Additional I/O may be generated depending on the level of vdev redundancy. +To filter output, you may pass in a list of pools, a pool and list of vdevs +in that pool, or a list of any vdevs from any pool. +If no items are specified, statistics for every pool in the system are shown. When given an .Ar interval , the statistics are printed every .Ar interval seconds until ^C is pressed. -If no -.Ar pool Ns s -are specified, statistics for every pool in the system is shown. +If +.Fl n +flag is specified the headers are displayed only once, otherwise they are +displayed periodically. If .Ar count is specified, the command exits after .Ar count reports are printed. +The first report printed is always the statistics since boot regardless of +whether +.Ar interval +and +.Ar count +are passed. +Also note that the units of +.Sy K , +.Sy M , +.Sy G ... +that are printed in the report are in base 1024. +To get the raw values, use the +.Fl p +flag. .Bl -tag -width Ds .It Fl T Sy u Ns | Ns Sy d Display a time stamp. @@ -1645,20 +1668,99 @@ Display vdev initialization status. Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands. +.It Fl H +Scripted mode. +Do not display headers, and separate fields by a single tab instead of +arbitrary space. .It Fl L Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the -.Pa /dev/disk/ +.Pa /dev/dsk/ path used to open it. +.It Fl n +Print headers only once when passed. +.It Fl p +Display numbers in parsable (exact) values. +Time values are in nanoseconds. .It Fl P Display full paths for vdevs instead of only the last component of the path. This can be used in conjunction with the .Fl L flag. +.It Fl r +Print request size histograms for the leaf vdev's IO +This includes histograms of individual IOs (ind) and aggregate IOs (agg). +These stats can be useful for observing how well IO aggregation is working. +Note that TRIM IOs may exceed 16M, but will be counted as 16M. .It Fl v Verbose statistics Reports usage statistics for individual vdevs within the pool, in addition to the pool-wide statistics. +.It Fl y +Omit statistics since boot. +Normally the first line of output reports the statistics since boot. +This option suppresses that first line of output. +.Ar interval +.It Fl w +Display latency histograms: +.Pp +.Ar total_wait : +Total IO time (queuing + disk IO time). +.Ar disk_wait : +Disk IO time (time reading/writing the disk). +.Ar syncq_wait : +Amount of time IO spent in synchronous priority queues. +Does not include disk time. +.Ar asyncq_wait : +Amount of time IO spent in asynchronous priority queues. +Does not include disk time. +.Ar scrub : +Amount of time IO spent in scrub queue. +Does not include disk time. +.It Fl l +Include average latency statistics: +.Pp +.Ar total_wait : +Average total IO time (queuing + disk IO time). +.Ar disk_wait : +Average disk IO time (time reading/writing the disk). +.Ar syncq_wait : +Average amount of time IO spent in synchronous priority queues. +Does not include disk time. +.Ar asyncq_wait : +Average amount of time IO spent in asynchronous priority queues. +Does not include disk time. +.Ar scrub : +Average queuing time in scrub queue. +Does not include disk time. +.Ar trim : +Average queuing time in trim queue. +Does not include disk time. +.It Fl q +Include active queue statistics. +Each priority queue has both pending ( +.Ar pend ) +and active ( +.Ar activ ) +IOs. +Pending IOs are waiting to be issued to the disk, and active IOs have been +issued to disk and are waiting for completion. +These stats are broken out by priority queue: +.Pp +.Ar syncq_read/write : +Current number of entries in synchronous priority +queues. +.Ar asyncq_read/write : +Current number of entries in asynchronous priority queues. +.Ar scrubq_read : +Current number of entries in scrub queue. +.Ar trimq_write : +Current number of entries in trim queue. +.Pp +All queue statistics are instantaneous measurements of the number of +entries in the queues. +If you specify an interval, the measurements will be sampled from the end of +the interval. .El .It Xo .Nm @@ -1732,12 +1834,12 @@ flag. .It Fl T Sy u Ns | Ns Sy d Display a time stamp. Specify -.Fl u +.Sy u for a printed representation of the internal representation of time. See .Xr time 2 . Specify -.Fl d +.Sy d for standard date format. See .Xr date 1 . @@ -2022,7 +2124,7 @@ and automatically import it. .It Xo .Nm .Cm status -.Op Fl DigLPtvx +.Op Fl DigLpPstvx .Op Fl T Sy u Ns | Ns Sy d .Oo Ar pool Oc Ns ... .Op Ar interval Op Ar count @@ -2055,23 +2157,33 @@ Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the .Pa /dev/disk/ path used to open it. +.It Fl p +Display numbers in parsable (exact) values. .It Fl P Display full paths for vdevs instead of only the last component of the path. This can be used in conjunction with the .Fl L flag. +.It Fl s +Display the number of leaf VDEV slow IOs. +This is the number of IOs that didn't complete in +.Sy zio_slow_io_ms +milliseconds (default 30 seconds). +This does not necessarily mean the IOs failed to complete, just took an +unreasonably long amount of time. +This may indicate a problem with the underlying storage. .It Fl t Display vdev TRIM status. .It Fl T Sy u Ns | Ns Sy d Display a time stamp. Specify -.Fl u +.Sy u for a printed representation of the internal representation of time. See .Xr time 2 . Specify -.Fl d +.Sy d for standard date format. See .Xr date 1 . diff --git a/usr/src/man/man3c/cond_init.3c b/usr/src/man/man3c/cond_init.3c index f54704de56..d90296e420 100644 --- a/usr/src/man/man3c/cond_init.3c +++ b/usr/src/man/man3c/cond_init.3c @@ -44,12 +44,11 @@ .\" Copyright (c) 2001, The IEEE and The Open Group. All Rights Reserved. .\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved. .\" -.TH COND_INIT 3C "Jun 5, 2007" +.TH COND_INIT 3C "February 15, 2020" .SH NAME cond_init, cond_wait, cond_timedwait, cond_reltimedwait, cond_signal, cond_broadcast, cond_destroy \- condition variables .SH SYNOPSIS -.LP .nf cc -mt [ \fIflag\fR... ] \fIfile\fR... [ \fIlibrary\fR... ] #include <thread.h> @@ -92,8 +91,6 @@ cc -mt [ \fIflag\fR... ] \fIfile\fR... [ \fIlibrary\fR... ] .SH DESCRIPTION .SS "Initialize" -.sp -.LP Condition variables and mutexes should be global. Condition variables that are allocated in writable memory can synchronize threads among processes if they are shared by the cooperating processes (see \fBmmap\fR(2)) and are initialized @@ -119,7 +116,7 @@ initialization. .LP The \fBcond_init()\fR function initializes the condition variable pointed to by \fIcvp\fR. A condition variable can have several different types of behavior, -specified by \fItype\fR. No current type uses \fIarg\fR although a future type +specified by \fItype\fR. No current type uses \fIarg\fR although a future type may specify additional behavior parameters with \fIarg\fR. The \fItype\fR argument c take one of the following values: .sp @@ -128,7 +125,7 @@ argument c take one of the following values: \fB\fBUSYNC_THREAD\fR\fR .ad .RS 17n -The condition variable can synchronize threads only in this process. This is +The condition variable can synchronize threads only in this process. This is the default. .RE @@ -199,8 +196,6 @@ cond_init(&cvp, USYNC_PROCESS, NULL); /* initialize cv with .in -2 .SS "Condition Wait" -.sp -.LP The condition wait interface allows a thread to wait for a condition and atomically release the associated mutex that it needs to hold to check the condition. The thread waits for another thread to make the condition true and @@ -211,7 +206,7 @@ The \fBcond_wait()\fR function atomically releases the mutex pointed to by \fImp\fR and causes the calling thread to block on the condition variable pointed to by \fIcvp\fR. The blocked thread may be awakened by \fBcond_signal()\fR, \fBcond_broadcast()\fR, or when interrupted by delivery of -a \fBUNIX\fR signal or a \fBfork()\fR. +a \fBUNIX\fR signal or a \fBfork()\fR. .sp .LP The \fBcond_wait()\fR, \fBcond_timedwait()\fR, and \fBcond_reltimedwait()\fR @@ -222,8 +217,6 @@ attribute and has been left irrecoverable by the mutex's last owner. The functions return the appropriate error value if they fail to internally reacquire the mutex. .SS "Condition Signaling" -.sp -.LP A condition signal allows a thread to unblock a single thread waiting on the condition variable, whereas a condition broadcast allows a thread to unblock all threads waiting on the condition variable. @@ -248,8 +241,6 @@ associated with the condition variable during their waits. If, however, predictable scheduling behavior is required, then that mutex should be locked by the thread prior to calling \fBcond_signal()\fR or \fBcond_broadcast()\fR. .SS "Destroy" -.sp -.LP The condition destroy functions destroy any state, but not the space, associated with the condition variable. .sp @@ -258,13 +249,9 @@ The \fBcond_destroy()\fR function destroys any state associated with the condition variable pointed to by \fIcvp\fR. The space for storing the condition variable is not freed. .SH RETURN VALUES -.sp -.LP Upon successful completion, these functions return \fB0\fR. Otherwise, a non-zero value is returned to indicate the error. .SH ERRORS -.sp -.LP The \fBcond_timedwait()\fR and \fBcond_reltimedwait()\fR functions will fail if: .sp @@ -313,7 +300,7 @@ mutex has not been acquired. \fB\fBEOWNERDEAD\fR\fR .ad .RS 19n -The last owner of the mutex died while holding the mutex, possibly leaving the +The last owner of the mutex died while holding the mutex, possibly leaving the state it was protecting inconsistent. The mutex is now owned by the caller. .RE @@ -342,11 +329,10 @@ to 1,000,000,000. .RE .SH EXAMPLES -.LP \fBExample 1 \fRUse \fBcond_wait()\fR in a loop to test some condition. .sp .LP -The \fBcond_wait()\fR functin is normally used in a loop testing some +The \fBcond_wait()\fR function is normally used in a loop testing some condition, as follows: .sp @@ -413,8 +399,6 @@ while (cond == FALSE) { .in -2 .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -429,14 +413,10 @@ MT-Level MT-Safe .TE .SH SEE ALSO -.sp -.LP \fBfork\fR(2), \fBmmap\fR(2), \fBsetitimer\fR(2), \fBshmop\fR(2), \fBmutex_init\fR(3C), \fBsignal\fR(3C), \fBattributes\fR(5), \fBcondition\fR(5), \fBmutex\fR(5), \fBstandards\fR(5) .SH NOTES -.sp -.LP If more than one thread is blocked on a condition variable, the order in which threads are unblocked is determined by the scheduling policy. When each thread, unblocked as a result of a \fBcond_signal()\fR or \fBcond_broadcast()\fR, diff --git a/usr/src/man/man3c/mtx.3c b/usr/src/man/man3c/mtx.3c index 677bee08e0..a303adc211 100644 --- a/usr/src/man/man3c/mtx.3c +++ b/usr/src/man/man3c/mtx.3c @@ -11,7 +11,7 @@ .\" .\" Copyright 2016 Joyent, Inc. .\" -.Dd "Jan 11, 2015" +.Dd "February 14, 2020" .Dt MTX 3C .Os .Sh NAME @@ -69,15 +69,15 @@ The following types of mutexes are valid and may be specified by the .Fa type argument: .Bl -tag -width Dv -.It Sy mtx_plain +.It Dv mtx_plain A simple, intra-process mutex. -.It Sy mtx_timed +.It Dv mtx_timed A simple, intra-process mutex, which allows timed locking operations. -.It Sy mtx_plain | mtx_recursive +.It Dv mtx_plain | mtx_recursive An intra-process mutex that may be acquired recursively by the same thread. It must be unlocked an equal number of times that it is locked. -.It Sy mtx_timed | mtx_recursive +.It Dv mtx_timed | mtx_recursive An intra-process mutex that supports timed locking operations and may be acquired recursively by the same thread. It must be unlocked an equal number of times that it is locked. @@ -112,16 +112,16 @@ When they finally return, then they will have obtained the mutex .Fa mtx . .Pp Unless a lock of type -.Sy mtx_recursive +.Dv mtx_recursive was created, a thread calling .Fn mtx_lock when it already holds .Fa mtx will cause the thread to deadlock. -Othewrise, the lock will be successfully taken again. +Otherwise, the lock will be successfully taken again. However, a thread must call .Fn mtx_unlock -for each time that it has acquried +for each time that it has acquired .Fa mtx . .Pp The @@ -135,7 +135,7 @@ if is locked, then it will not block and wait for .Fa mtx and instead return -.Sy thrd_busy +.Dv thrd_busy to indicate that the lock is currently held. .Pp The @@ -149,7 +149,7 @@ The timeout in .Fa ts is treated as an absolute time in UTC to block until, measured based on the -.Sy CLOCK_REALTIME +.Dv CLOCK_REALTIME clock. .Pp The @@ -164,44 +164,46 @@ It is an error to call on a mutex which the calling thread does not currently own. .Sh RETURN VALUES Upon successful completion, the function -.Fn mtx_init returns -.Sy thrd_success. +.Fn mtx_init +returns +.Dv thrd_success . If there was insufficient memory to create the thread, it instead returns -.Sy thrd_nomem . +.Dv thrd_nomem . If any other error occurred, it returns -.Sy thrd_error . +.Dv thrd_error . .Pp The functions .Fn mtx_lock , and .Fn mtx_unlock return -.Sy thrd_success . +.Dv thrd_success . If they were unable to successfully complete the operation, they instead return -.Sy thrd_error . +.Dv thrd_error . .Pp Upon successful completion, the .Fn mtx_timedlock function returns -.Sy thrd_success . +.Dv thrd_success . If the timeout is reached and the calling thread is unable to obtain the mutex, then -.Sy thrd_timedout -is returned . +.Dv thrd_timedout +is returned. If any other error occurs, then -.Sy thrd_error is returned. +.Dv thrd_error +is returned. .Pp Upon successful completion, the .Fn mtx_trylock function returns -.Sy thrd_success . +.Dv thrd_success . If the thread was unable to obtain the mutex because another thread owns it, then it returns -.Sy thrd_busy . +.Dv thrd_busy . Otherwise, an error will have occurred and -.Sy thrd_error +.Dv thrd_error is returned. .Sh INTERFACE STABILITY .Sy Standard diff --git a/usr/src/man/man3sec/acl_totext.3sec b/usr/src/man/man3sec/acl_totext.3sec index 6e55c2323c..8524d144e5 100644 --- a/usr/src/man/man3sec/acl_totext.3sec +++ b/usr/src/man/man3sec/acl_totext.3sec @@ -8,7 +8,6 @@ acl_totext, acl_fromtext \- convert internal representation to or from external representation .SH SYNOPSIS -.LP .nf cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lsec\fR [ \fIlibrary\fR\&.\|.\|. ] #include <sys/acl.h> @@ -22,8 +21,6 @@ cc [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lsec\fR [ \fIlibrary\fR\&.\|. .fi .SH DESCRIPTION -.sp -.LP The \fBacl_totext()\fR function converts an internal ACL representation pointed to by \fIaclp\fR into an external ACL representation. The memory for the external text string is obtained using \fBmalloc\fR(3C). The caller is @@ -50,7 +47,7 @@ detailed in \fBls\fR(1) for the \fB-V\fR option. .ad .RS 19n Append the \fBuid\fR or \fBgid\fR for additional user or group entries. This -flag is used to construt ACL entries in a manner that is suitable for archive +flag is used to construct ACL entries in a manner that is suitable for archive utilities such as \fBtar\fR(1). When the ACL is translated from the external format to internal representation using \fBacl_fromtext()\fR, the appended ID will be used to populate the \fBuid\fR or \fBgid\fR field of the ACL entry when @@ -611,8 +608,6 @@ The mask specified in field three should be denied. .RE .SH RETURN VALUES -.sp -.LP Upon successful completion, the \fBacl_totext()\fR function returns a pointer to a text string. Otherwise, it returns \fINULL\fR. .sp @@ -701,7 +696,6 @@ Unknown data was found in the ACL. .RE .SH EXAMPLES -.LP \fBExample 1 \fRExamples of permissions when \fBACL_COMPACT_FMT\fR is not specified. .sp @@ -740,8 +734,6 @@ owner@:----------c---:------allow,user:tom:r-------------:f-i---:deny .sp .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -758,7 +750,5 @@ MT-Level Safe .TE .SH SEE ALSO -.sp -.LP \fBls\fR(1), \fBtar\fR(1), \fBacl\fR(2), \fBmalloc\fR(3C), \fBaclfromtext\fR(3SEC), \fBacl\fR(5), \fBattributes\fR(5) diff --git a/usr/src/man/man3sec/aclcheck.3sec b/usr/src/man/man3sec/aclcheck.3sec index 85c3aba921..61cf6db1fa 100644 --- a/usr/src/man/man3sec/aclcheck.3sec +++ b/usr/src/man/man3sec/aclcheck.3sec @@ -7,7 +7,6 @@ .SH NAME aclcheck \- check the validity of an ACL .SH SYNOPSIS -.LP .nf \fBcc\fR [ \fIflag\fR... ] \fIfile\fR... \fB-lsec\fR [ \fIlibrary\fR... ] #include <sys/acl.h> @@ -16,8 +15,6 @@ aclcheck \- check the validity of an ACL .fi .SH DESCRIPTION -.sp -.LP The \fBaclcheck()\fR function checks the validity of an \fBACL\fR pointed to by \fIaclbufp.\fR The \fInentries\fR argument is the number of entries contained in the buffer. The \fIwhich\fR parameter returns the index of the first entry @@ -115,13 +112,11 @@ exactly one \fBDEF_CLASS_OBJ\fR (default \fBACL\fR mask) entry. .ie t \(bu .el o If any of the above rules are violated, then the function fails with -\fBerrno\fR set to \fBEINVAL\fR. +\fBerrno\fR set to \fBEINVAL\fR. .RE .SH RETURN VALUES -.sp -.LP -If the \fBACL\fR is valid, \fBalcheck()\fR will return \fB0\fR. Otherwise -\fBerrno\fR is set to \fBEINVAL\fR and return code is set to one of the +If the \fBACL\fR is valid, \fBaclcheck()\fR will return \fB0\fR. Otherwise +\fBerrno\fR is set to \fBEINVAL\fR and \fBaclcheck()\fR will return one of the following: .sp .ne 2 @@ -199,8 +194,6 @@ The system cannot allocate any memory. The \fBwhich\fR parameter returns .RE .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -217,6 +210,4 @@ MT-Level Unsafe .TE .SH SEE ALSO -.sp -.LP \fBacl\fR(2), \fBaclsort\fR(3SEC), \fBattributes\fR(5) diff --git a/usr/src/man/man3sec/acltotext.3sec b/usr/src/man/man3sec/acltotext.3sec index 23dea4c0d8..06bf4def79 100644 --- a/usr/src/man/man3sec/acltotext.3sec +++ b/usr/src/man/man3sec/acltotext.3sec @@ -8,7 +8,6 @@ acltotext, aclfromtext \- convert internal representation to or from external representation .SH SYNOPSIS -.LP .nf \fBcc\fR [ \fIflag\fR... ] \fIfile\fR... \fB-lsec\fR [ \fIlibrary\fR... ] #include <sys/acl.h> @@ -22,12 +21,10 @@ representation .fi .SH DESCRIPTION -.sp -.LP The \fBacltotext()\fR function converts an internal \fBACL\fR representation pointed to by \fIaclbufp\fR into an external \fBACL\fR representation. The space for the external text string is obtained using \fBmalloc\fR(3C). The -caller is responsible for freeing the space upon completion.. +caller is responsible for freeing the space upon completion. .sp .LP The \fBaclfromtext()\fR function converts an external \fBACL\fR representation @@ -206,8 +203,6 @@ no access .RE .SH RETURN VALUES -.sp -.LP Upon successful completion, the \fBacltotext()\fR function returns a pointer to a text string. Otherwise, it returns \fBNULL\fR. .sp @@ -215,8 +210,6 @@ a text string. Otherwise, it returns \fBNULL\fR. Upon successful completion, the \fBaclfromtext()\fR function returns a pointer to a list of \fBACL\fR entries. Otherwise, it returns \fBNULL\fR. .SH ATTRIBUTES -.sp -.LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -233,6 +226,4 @@ MT-Level Unsafe .TE .SH SEE ALSO -.sp -.LP \fBacl\fR(2), \fBmalloc\fR(3C), \fBattributes\fR(5) diff --git a/usr/src/man/man5/acl.5 b/usr/src/man/man5/acl.5 index b1db6df1ae..cc42c5d4df 100644 --- a/usr/src/man/man5/acl.5 +++ b/usr/src/man/man5/acl.5 @@ -1,17 +1,17 @@ '\" te +.\" Copyright (c) 2020 Peter Tribble. .\" Copyright 2014 Nexenta Systems, Inc. All rights reserved. .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved. .\" 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] -.TH ACL 5 "Nov 24, 2014" +.TH ACL 5 "Feb 8, 2020" .SH NAME acl \- Access Control Lists .SH DESCRIPTION -.LP Access control lists (ACLs) are discretionary access control mechanisms that grant and deny access to files and directories. Two different ACL models are -supported in the Solaris release: POSIX-draft ACLs and NFSv4 ACLs. +supported in this release: POSIX-draft ACLs and NFSv4 ACLs. .sp .LP The older, POSIX-draft model is supported by the UFS file system. This model is @@ -23,10 +23,9 @@ The other model is based on the standards of the NFSv4 working group and is an approved standard from the Internet Engineering Task Force (IETF). The ZFS file system uses the NFSv4 model, and provides richer semantics and finer grained permission capabilities than the POSIX-draft model. -.SS "\fBPOSIX\fR-draft \fBACL\fRs" -.LP +.SS "POSIX-draft ACLs" POSIX-draft ACLs provide an alternative security mechanism to basic UNIX file -permissions in the Solaris release. Their purpose is to further restrict access +permissions. Their purpose is to further restrict access to files and directories or to extend permissions to a particular user. ACLs can be used to change the permissions for the standard owner, group and other class bits of a file's mode. ACLs can give additional users and groups access @@ -104,9 +103,8 @@ user:joe:rw- .in -2 .sp -.SS "\fBNFS\fRv4 \fBACL\fRs" -.LP -NFSv4 ACL model is based loosely on the Windows NT ACL model. NFSv4 ACLs +.SS "NFSv4 ACLs" +The NFSv4 ACL model is based loosely on the Windows NT ACL model. NFSv4 ACLs provide a much richer ACL model than POSIX-draft ACLs. .sp .LP @@ -151,7 +149,7 @@ subdirectories of the directory. .ie t \(bu .el o NFSv4 ACLs provide a mechanism for hooking into a system's audit trail. -Currently, Solaris does not support this mechanism. +Currently, illumos does not support this mechanism. .RE .RS +4 .TP @@ -540,10 +538,9 @@ user:fred:rwR:f------:allow .in -2 .sp -.SS "Shell-level Solaris \fBAPI\fR" -.LP -The Solaris command interface supports the manipulation of ACLs. The following -Solaris utilities accommodate both ACL models: +.SS "Shell-level API" +Several utilities support the manipulation of ACLs. The following +utilities accommodate both ACL models: .sp .ne 2 .na @@ -656,12 +653,11 @@ When a file with an ACL is unpacked, the unpacked file retains the ACL information. .RE -.SS "Application-level \fBAPI\fR" -.LP +.SS "Application-level API" The primary interfaces required to access file system ACLs at the programmatic level are the \fBacl_get()\fR and \fBacl_set()\fR functions. These functions -support both POSIX draft ACLs and NFSv4 ACLs. -.SS "Retrieving a file's \fBACL\fR" +support both POSIX-draft ACLs and NFSv4 ACLs. +.SS "Retrieving a file's ACL" .in +2 .nf int acl_get(const char *path, int flag, acl_t **aclp); @@ -671,23 +667,23 @@ int facl_get(int fd, int flag, acl_t **aclp); .sp .LP -The \fBacl_get\fR(3SEC) and \fBfacl_get\fR(3SEC) functions retrieves an ACL on +The \fBacl_get\fR(3SEC) and \fBfacl_get\fR(3SEC) functions retrieve an ACL on a file whose name is given by path or referenced by the open file descriptor fd. The flag argument specifies whether a trivial ACL should be retrieved. When -the flag argument equals \fBACL_NO_TRIVIAL\fR then only ACLs that are not +the flag argument equals \fBACL_NO_TRIVIAL\fR only ACLs that are not trivial are retrieved. The ACL is returned in the \fBaclp\fR argument. -.SS "Freeing \fBACL\fR structure" +.SS "Freeing ACL structure" .in +2 .nf -void acl_free(acl_t *aclp)s; +void acl_free(acl_t *aclp); .fi .in -2 .sp .LP The \fBacl_free()\fR function frees up memory allocated for the argument -\fBaclp;\fR. -.SS "Setting an \fBACL\fR on a file" +\fBaclp\fR. +.SS "Setting an ACL on a file" .in +2 .nf int acl_set(const char *path, acl_t *aclp); @@ -700,10 +696,10 @@ int facl_set(int fd, acl_t *aclp); The \fBacl_set\fR(3SEC) and \fBfacl_get\fR(3SEC) functions are used for setting an ACL on a file whose name is given by path or referenced by the open file descriptor \fBfd\fR. The \fBaclp\fR argument specifies the ACL to set. The -\fBacl_set\fR(3SEC) translates an POSIX-draft ACL into a NFSv4 ACL when the -target file systems supports NFSv4 ACLs. No translation is performed when +\fBacl_set\fR(3SEC) function translates a POSIX-draft ACL into a NFSv4 ACL when +the target file system supports NFSv4 ACLs. No translation is performed when trying to set an NFSv4 ACL on a POSIX-draft ACL supported file system. -.SS "Determining an \fBACL\fR's trivialness" +.SS "Determining an ACL's trivialness" .in +2 .nf int acl_trivial(const char *path); @@ -714,7 +710,7 @@ int acl_trivial(const char *path); .LP The \fBacl_trivial()\fR function is used to determine whether a file has a trivial ACL. -.SS "Removing all \fBACL\fRs from a file" +.SS "Removing all ACLs from a file" .in +2 .nf int acl_strip(const char *path, uid_t uid, gid_t gid, mode_t mode); @@ -727,7 +723,7 @@ The \fBacl_strip()\fR function removes all ACLs from a file and replaces them with a trivial ACL based off of the passed in argument mode. After replacing the ACL the owner and group of the file are set to the values specified in the uid and gid parameters. -.SS "Converting \fBACL\fRs to/from external representation" +.SS "Converting ACLs to/from external representation" .in +2 .nf int acl_fromtext(const char *path, acl_t **aclp); @@ -742,11 +738,10 @@ to by aclp into an external representation. See \fBDESCRIPTION\fR for details about external representation. .sp .LP -The \fBacl_fromtext()\fR functions converts and external representation into an +The \fBacl_fromtext()\fR function converts an external representation into an internal representation. See \fBDESCRIPTION\fR for details about external representation. .SH EXAMPLES -.LP The following examples demonstrate how the API can be used to perform basic operations on ACLs. .LP @@ -831,7 +826,6 @@ error = acl_strip("file", 10, 100, 0644); .in -2 .SH SEE ALSO -.LP \fBchgrp\fR(1), \fBchmod\fR(1), \fBchown\fR(1), \fBcp\fR(1), \fBcpio\fR(1), \fBfind\fR(1), \fBls\fR(1), \fBmv\fR(1), \fBtar\fR(1), \fBsetfacl\fR(1), \fBchmod\fR(2), \fBacl\fR(2), \fBstat\fR(2), \fBacl_get\fR(3SEC), diff --git a/usr/src/man/man5/dhcp.5 b/usr/src/man/man5/dhcp.5 index 6a662bd6b1..33b8707449 100644 --- a/usr/src/man/man5/dhcp.5 +++ b/usr/src/man/man5/dhcp.5 @@ -4,11 +4,10 @@ .\" 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] -.TH DHCP 5 "Aug 15, 2014" +.TH DHCP 5 "Feb 13, 2020" .SH NAME dhcp \- Dynamic Host Configuration Protocol .SH DESCRIPTION -.LP Dynamic Host Configuration Protocol (\fBDHCP\fR) enables host systems in a \fBTCP/IP\fR network to be configured automatically for the network as they boot. \fBDHCP\fR uses a client/server mechanism: servers store configuration @@ -19,7 +18,6 @@ network services available to the client. This manual page provides a brief summary of the \fBDHCP\fR implementation. .SS "DHCP Client" -.LP The DHCP client is implemented as background daemon, \fBdhcpagent\fR(1M). .LP @@ -40,13 +38,11 @@ changing the tunables in the \fB/etc/default/dhcpagent\fR file. The daemon is controlled by the \fBifconfig\fR(1M) utility. Check the status of the daemon using the \fBnetstat\fR(1M) and \fBifconfig\fR(1M) commands. .SH SEE ALSO -.LP \fBdhcpinfo\fR(1), \fBdhcpagent\fR(1M), \fBifconfig\fR(1M), \fBin.ndpd\fR(1M), \fBnetstat\fR(1M), \fBsyslog\fR(3C), -\fBdhcp_network\fR(4), \fBdhcptab\fR(4), \fBdhcpsvc.conf\fR(4), -\fBdhcp_inittab\fR(4), \fBndpd.conf\fR(4), \fBdhcp_modules\fR(5) +\fBdhcp_inittab\fR(4), \fBndpd.conf\fR(4) .LP Alexander, S., and R. Droms. \fIRFC 2132, DHCP Options and BOOTP Vendor Extensions\fR. Silicon Graphics, Inc. Bucknell University. March 1997. diff --git a/usr/src/man/man9e/awrite.9e b/usr/src/man/man9e/awrite.9e index c3ac9b6032..17752ab754 100644 --- a/usr/src/man/man9e/awrite.9e +++ b/usr/src/man/man9e/awrite.9e @@ -4,11 +4,10 @@ .\" 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] -.TH AWRITE 9E "Mar 28, 1997" +.TH AWRITE 9E "February 15, 2020" .SH NAME awrite \- asynchronous write to a device .SH SYNOPSIS -.LP .nf #include <sys/uio.h> #include <sys/aio_req.h> @@ -16,17 +15,14 @@ awrite \- asynchronous write to a device #include <sys/ddi.h> #include <sys/sunddi.h> -\fBintprefix\fR\fBawrite\fR(\fBdev_t\fR \fIdev\fR, \fBstruct aio_req *\fR\fIaio_reqp\fR, +\fBint prefix\fR\fBawrite\fR(\fBdev_t\fR \fIdev\fR, \fBstruct aio_req *\fR\fIaio_reqp\fR, \fBcred_t *\fR\fIcred_p\fR); .fi .SH INTERFACE LEVEL -.sp -.LP Solaris \fBDDI \fRspecific (Solaris DDI). This entry point is optional. Drivers -that do not support an \fBawrite()\fR entry point should use \fBnodev\fR(9F) +that do not support an \fBawrite()\fR entry point should use \fBnodev\fR(9F) .SH PARAMETERS -.sp .ne 2 .na \fB\fIdev\fR\fR @@ -41,7 +37,7 @@ Device number. \fB\fIaio_reqp\fR\fR .ad .RS 12n -Pointer to the \fBaio_req\fR(9S) structure that describes where the data is +Pointer to the \fBaio_req\fR(9S) structure that describes where the data is stored. .RE @@ -51,18 +47,16 @@ stored. \fB\fIcred_p\fR\fR .ad .RS 12n -Pointer to the credential structure. +Pointer to the credential structure. .RE .SH DESCRIPTION -.sp -.LP The driver's \fBawrite()\fR routine is called to perform an asynchronous write. -\fBgetminor\fR(9F) can be used to access the minor number component of the -\fIdev\fR argument. \fBawrite()\fR may use the credential structure pointed to -by \fIcred_p\fR to check for superuser access by calling \fBdrv_priv\fR(9F). -The \fBawrite()\fR routine may also examine the \fBuio\fR(9S) structure -through the \fBaio_req\fR structure pointer, \fBaio_reqp\fR. \fBawrite()\fR +\fBgetminor\fR(9F) can be used to access the minor number component of the +\fIdev\fR argument. \fBawrite()\fR may use the credential structure pointed to +by \fIcred_p\fR to check for superuser access by calling \fBdrv_priv\fR(9F). +The \fBawrite()\fR routine may also examine the \fBuio\fR(9S) structure +through the \fBaio_req\fR structure pointer, \fBaio_reqp\fR. \fBawrite()\fR must call \fBaphysio\fR(9F) with the \fBaio_req\fR pointer and a pointer to the driver's \fBstrategy\fR(9E) routine. .sp @@ -71,20 +65,15 @@ No fields of the \fBuio\fR(9S) structure pointed to by \fBaio_req\fR, other than \fBuio_offset\fR or \fBuio_loffset\fR, may be modified for non-seekable devices. .SH RETURN VALUES -.sp -.LP -The \fBawrite()\fR routine should return \fB0\fR for success, or the +The \fBawrite()\fR routine should return \fB0\fR for success, or the appropriate error number. .SH CONTEXT -.sp -.LP This function is called from user context only. .SH EXAMPLES -.LP \fBExample 1 \fRUsing the \fBawrite()\fR routine: .sp .LP -The following is an example of an \fBawrite()\fR routine: +The following is an example of an \fBawrite()\fR routine: .sp .in +2 @@ -107,8 +96,6 @@ xxawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p) .in -2 .SH SEE ALSO -.sp -.LP \fBwrite\fR(2), \fBaiowrite\fR(3C), \fBaread\fR(9E), \fBread\fR(9E), \fBstrategy\fR(9E), \fBwrite\fR(9E), \fBanocancel\fR(9F), \fBaphysio\fR(9F), \fBddi_get_soft_state\fR(9F), \fBdrv_priv\fR(9F), \fBgetminor\fR(9F), @@ -118,7 +105,5 @@ xxawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p) .LP \fIWriting Device Drivers\fR .SH BUGS -.sp -.LP There is no way other than calling \fBaphysio\fR(9F) to accomplish an asynchronous write. diff --git a/usr/src/man/man9e/ddi_ufm.9e b/usr/src/man/man9e/ddi_ufm.9e index 62e49893f8..911d7cfd78 100644 --- a/usr/src/man/man9e/ddi_ufm.9e +++ b/usr/src/man/man9e/ddi_ufm.9e @@ -11,7 +11,7 @@ .\" .\" Copyright 2019 Joyent, Inc. .\" -.Dd Apr 30, 2019 +.Dd February 15, 2020 .Dt DDI_UFM 9E .Os .Sh NAME @@ -368,7 +368,7 @@ Common values are: .Bl -tag -width Er -offset width .It Er EIO An error occurred talking to the device while trying to discover firmware -capabilties. +capabilities. .It Er ENOMEM The driver was unable to allocate memory. .El diff --git a/usr/src/man/man9e/mac_capab_transceiver.9e b/usr/src/man/man9e/mac_capab_transceiver.9e index 2dc6f17fe1..b2faff6c65 100644 --- a/usr/src/man/man9e/mac_capab_transceiver.9e +++ b/usr/src/man/man9e/mac_capab_transceiver.9e @@ -11,7 +11,7 @@ .\" .\" Copyright (c) 2017, Joyent, Inc. .\" -.Dd Nov 26, 2017 +.Dd February 15, 2020 .Dt MAC_CAPAB_TRANSCEIVER 9E .Os .Sh NAME @@ -156,7 +156,7 @@ then the value of the capability structure is the following structure: .Bd -literal -offset indent typedef struct mac_capab_transceiver { uint_t mct_flags; - uint_t mct_ntransceiveres; + uint_t mct_ntransceivers; int (*mct_info)(void *driver, uint_t id, mac_transceiver_info_t *infop), int (*mct_read)(void *driver, uint_t id, uint_t page, @@ -185,7 +185,7 @@ member to .It Sy mct_ntransceivers The value of .Sy mct_ntransceivers -indicates that the number of transceivers present in the device. +indicates the number of transceivers present in the device. For most devices, it is expected that this value will be set to one. However, some devices do support multiple transceivers and PHYs that show up behind a single logical MAC. @@ -231,7 +231,7 @@ the functions described in the section After successfully calling all of the functions, the driver should return .Sy 0 . -Othewrise, it should return the appropriate error number. +Otherwise, it should return the appropriate error number. For a full list of error numbers, see .Xr Intro 2 . Common values are: diff --git a/usr/src/man/man9e/mc_getprop.9e b/usr/src/man/man9e/mc_getprop.9e index d14bcd77b5..11a942a22b 100644 --- a/usr/src/man/man9e/mc_getprop.9e +++ b/usr/src/man/man9e/mc_getprop.9e @@ -11,7 +11,7 @@ .\" .\" Copyright 2016 Joyent, Inc. .\" -.Dd November 15, 2016 +.Dd February 15, 2020 .Dt MC_GETPROP 9E .Os .Sh NAME @@ -145,7 +145,7 @@ example_m_getprop_private(example_t *ep, const char *pr_name, uint_t pr_valsize, ASSERT(MUTEX_HELD(&ep->ep_lock)); if (strcmp(pr_name, example_priv_props[0] == 0) { val = ep->ep_rx_itr; - } else if (strcmp(pr_name, exampe_priv_props[1] == 0) { + } else if (strcmp(pr_name, example_priv_props[1] == 0) { val = ep->ep_tx_itr; } else { return (ENOTSUP); diff --git a/usr/src/man/man9e/mc_setprop.9e b/usr/src/man/man9e/mc_setprop.9e index b6d8a9a371..fdd8aca49a 100644 --- a/usr/src/man/man9e/mc_setprop.9e +++ b/usr/src/man/man9e/mc_setprop.9e @@ -11,7 +11,7 @@ .\" .\" Copyright 2016 Joyent, Inc. .\" -.Dd June 02, 2016 +.Dd February 15, 2020 .Dt MC_SETPROP 9E .Os .Sh NAME @@ -113,7 +113,7 @@ and return Otherwise, a positive error should be returned to indicate failure. .Sh EXAMPLES The following examples shows how a device driver might structure its -.Fn mc_setporp +.Fn mc_setprop entry point. .Bd -literal #include <sys/mac_provider.h> @@ -129,7 +129,7 @@ entry point. */ static int -exmple_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, +example_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, uint_t pr_valsize, const void *pr_val) { uint32_t new_mtu; diff --git a/usr/src/man/man9e/probe.9e b/usr/src/man/man9e/probe.9e index d7c6e352bb..7152609ce2 100644 --- a/usr/src/man/man9e/probe.9e +++ b/usr/src/man/man9e/probe.9e @@ -4,11 +4,10 @@ .\" 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] -.TH PROBE 9E "Nov 18, 1992" +.TH PROBE 9E "February 15, 2020" .SH NAME probe \- determine if a non-self-identifying device is present .SH SYNOPSIS -.LP .nf #include <sys/conf.h> #include <sys/ddi.h> @@ -16,29 +15,24 @@ probe \- determine if a non-self-identifying device is present -\fBstatic intprefix\fR\fBprobe\fR(\fBdev_info_t *\fR\fIdip\fR); +\fBstatic int prefix\fR\fBprobe\fR(\fBdev_info_t *\fR\fIdip\fR); .fi .SH INTERFACE LEVEL -.sp -.LP Solaris DDI specific (Solaris DDI). This entry point is required for non-self-identifying devices. You must write it for such devices. For -self-identifying devices, \fBnulldev\fR(9F) should be specified in the +self-identifying devices, \fBnulldev\fR(9F) should be specified in the \fBdev_ops\fR(9S) structure if a probe routine is not necessary. .SH ARGUMENTS -.sp .ne 2 .na \fB\fIdip\fR \fR .ad .RS 8n -Pointer to the device's \fBdev_info\fR structure. +Pointer to the device's \fBdev_info\fR structure. .RE .SH DESCRIPTION -.sp -.LP \fBprobe()\fR determines whether the device corresponding to \fIdip\fR actually exists and is a valid device for this driver. \fBprobe()\fR is called after \fBidentify\fR(9E) and before \fBattach\fR(9E) for a given \fIdip\fR. For @@ -64,10 +58,9 @@ done in \fBattach\fR(9E). For a self-identifying device, this entry point is not necessary. However, if a device exists in both self-identifying and non-self-identifying forms, a \fBprobe()\fR routine can be provided to simplify the driver. -\fBddi_dev_is_sid\fR(9F) can then be used to determine whether \fBprobe()\fR +\fBddi_dev_is_sid\fR(9F) can then be used to determine whether \fBprobe()\fR needs to do any work. See \fBddi_dev_is_sid\fR(9F) for an example. .SH RETURN VALUES -.sp .ne 2 .na \fB\fBDDI_PROBE_SUCCESS\fR \fR @@ -104,8 +97,6 @@ If the instance is not present now, but may be present in the future. .RE .SH SEE ALSO -.sp -.LP \fBattach\fR(9E), \fBidentify\fR(9E), \fBddi_dev_is_sid\fR(9F), \fBddi_map_regs\fR(9F), \fBddi_peek\fR(9F), \fBddi_poke\fR(9F), \fBnulldev\fR(9F), \fBdev_ops\fR(9S) diff --git a/usr/src/man/man9e/usba_hcdi_hub_update.9e b/usr/src/man/man9e/usba_hcdi_hub_update.9e index d9dca82f9b..d0944f701e 100644 --- a/usr/src/man/man9e/usba_hcdi_hub_update.9e +++ b/usr/src/man/man9e/usba_hcdi_hub_update.9e @@ -11,7 +11,7 @@ .\" .\" Copyright 2016 Joyent, Inc. .\" -.Dd Dec 20, 2016 +.Dd February 15, 2020 .Dt USBA_HCDI_HUB_UPDATE 9E .Os .Sh NAME @@ -75,7 +75,7 @@ If this function fails, the enumeration of this device will fail, the hub driver will not attach to this USB device, and all devices plugged into this hub will not be detected by the system. .Sh CONTEXT -This functin is called from kernel context only. +This function is called from kernel context only. .Sh RETURN VALUES Upon successful completion, the .Fn usba_hcdi_hub_update diff --git a/usr/src/man/man9e/usba_hcdi_pipe_open.9e b/usr/src/man/man9e/usba_hcdi_pipe_open.9e index c174300525..04b0b9f54c 100644 --- a/usr/src/man/man9e/usba_hcdi_pipe_open.9e +++ b/usr/src/man/man9e/usba_hcdi_pipe_open.9e @@ -11,7 +11,7 @@ .\" .\" Copyright 2016 Joyent, Inc. .\" -.Dd Nov 26, 2017 +.Dd February 15, 2020 .Dt USBA_HCDI_PIPE_OPEN 9E .Os .Sh NAME @@ -125,7 +125,7 @@ closed. .Ss Pipe close specifics When a pipe is closed, the driver must clean up all of the resources that it allocated when opening the pipe. -For non-periodic transfers, the host controller driver may assueme that there +For non-periodic transfers, the host controller driver may assume that there are no outstanding transfers that need to be cleaned up. However, the same is not true for periodic pipes. .Pp diff --git a/usr/src/man/man9f/gld.9f b/usr/src/man/man9f/gld.9f index 073f27f3d6..b7eadc7177 100644 --- a/usr/src/man/man9f/gld.9f +++ b/usr/src/man/man9f/gld.9f @@ -4,12 +4,11 @@ .\" 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] -.TH GLD 9F "Aug 28, 2003" +.TH GLD 9F "February 15, 2020" .SH NAME gld, gld_mac_alloc, gld_mac_free, gld_register, gld_unregister, gld_recv, gld_sched, gld_intr \- Generic LAN Driver service routines .SH SYNOPSIS -.LP .nf #include <sys/gld.h> @@ -52,11 +51,8 @@ gld_sched, gld_intr \- Generic LAN Driver service routines .fi .SH INTERFACE LEVEL -.sp -.LP Solaris architecture specific (Solaris DDI). .SH PARAMETERS -.sp .ne 2 .na \fB\fImacinfo\fR \fR @@ -102,8 +98,6 @@ Media link state. .RE .SH DESCRIPTION -.sp -.LP \fBgld_mac_alloc\fR(\|) allocates a new \fBgld_mac_info\fR(9S) structure and returns a pointer to it. Some of the GLD-private elements of the structure may be initialized before \fBgld_mac_alloc\fR(\|) returns; all other elements are @@ -264,10 +258,8 @@ The status of the media link is unknown. .sp .LP If a driver calls \fBgld_linkstate()\fR, it must also set the GLD_CAP_LINKSTATE -bit in the gldm_capabilties field of the \fBgld_mac_info\fR(9S) structure. +bit in the gldm_capabilities field of the \fBgld_mac_info\fR(9S) structure. .SH RETURN VALUES -.sp -.LP \fBgld_mac_alloc\fR(\|) returns a pointer to a new \fBgld_mac_info\fR(9S) structure. .sp @@ -295,8 +287,6 @@ on failure. .LP \fBgld_intr\fR(\|) returns a value appropriate for an interrupt handler. .SH SEE ALSO -.sp -.LP \fBgld\fR(7D), \fBgld\fR(9E), \fBgld_mac_info\fR(9S), \fBgld_stats\fR(9S), \fBdlpi\fR(7P), \fBattach\fR(9E), \fBddi_add_intr\fR(9F) .sp diff --git a/usr/src/man/man9f/mac_register.9f b/usr/src/man/man9f/mac_register.9f index 96e4a90fd0..6be8e59c2a 100644 --- a/usr/src/man/man9f/mac_register.9f +++ b/usr/src/man/man9f/mac_register.9f @@ -11,7 +11,7 @@ .\" .\" Copyright (c) 2017, Joyent, Inc. .\" -.Dd September 22, 2017 +.Dd February 15, 2020 .Dt MAC_REGISTER 9F .Os .Sh NAME @@ -170,7 +170,7 @@ static char *example_priv_props[] = { }; static mac_callbacks_t example_m_callbacks = { - .mc_callbacsk = MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO | + .mc_callbacks = MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO | MC_IOCTL, .mc_start = example_m_start, .mc_stop = example_m_stop, @@ -203,7 +203,7 @@ example_register_mac(example_t *ep) mac->m_min_sdu = 0; mac->m_max_sdu = ep->ep_sdu; mac->m_margin = VLAN_TAGSZ; - mac->m_priv_props = exmple_priv_props; + mac->m_priv_props = example_priv_props; status = mac_register(mac, &ep->ep_mac_hdl); mac_free(mac); diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf index 797bd1d79c..10436a8fdf 100644 --- a/usr/src/pkg/manifests/system-test-zfstest.mf +++ b/usr/src/pkg/manifests/system-test-zfstest.mf @@ -112,6 +112,7 @@ dir path=opt/zfs-tests/tests/functional/ctime dir path=opt/zfs-tests/tests/functional/delegate dir path=opt/zfs-tests/tests/functional/devices dir path=opt/zfs-tests/tests/functional/exec +dir path=opt/zfs-tests/tests/functional/fault dir path=opt/zfs-tests/tests/functional/features dir path=opt/zfs-tests/tests/functional/features/async_destroy dir path=opt/zfs-tests/tests/functional/grow_pool @@ -209,6 +210,7 @@ file path=opt/zfs-tests/include/default.cfg mode=0444 file path=opt/zfs-tests/include/libtest.shlib mode=0444 file path=opt/zfs-tests/include/math.shlib mode=0444 file path=opt/zfs-tests/include/properties.shlib mode=0444 +file path=opt/zfs-tests/include/zpool_script.shlib mode=0444 file path=opt/zfs-tests/runfiles/delphix.run mode=0444 file path=opt/zfs-tests/runfiles/longevity.run mode=0444 file path=opt/zfs-tests/runfiles/omnios.run mode=0444 @@ -2377,6 +2379,9 @@ file \ file \ path=opt/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg \ mode=0555 +file \ + path=opt/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos \ + mode=0555 file path=opt/zfs-tests/tests/functional/cli_user/zpool_list/cleanup mode=0555 file path=opt/zfs-tests/tests/functional/cli_user/zpool_list/setup mode=0555 file \ @@ -2445,6 +2450,10 @@ file path=opt/zfs-tests/tests/functional/exec/exec_001_pos mode=0555 file path=opt/zfs-tests/tests/functional/exec/exec_002_neg mode=0555 file path=opt/zfs-tests/tests/functional/exec/mmap_exec mode=0555 file path=opt/zfs-tests/tests/functional/exec/setup mode=0555 +file path=opt/zfs-tests/tests/functional/fault/cleanup mode=0555 +file path=opt/zfs-tests/tests/functional/fault/fault.cfg mode=0444 +file path=opt/zfs-tests/tests/functional/fault/setup mode=0555 +file path=opt/zfs-tests/tests/functional/fault/zpool_status_-s mode=0555 file \ path=opt/zfs-tests/tests/functional/features/async_destroy/async_destroy_001_pos \ mode=0555 diff --git a/usr/src/test/zfs-tests/include/libtest.shlib b/usr/src/test/zfs-tests/include/libtest.shlib index 725c971a4c..2edf9123ab 100644 --- a/usr/src/test/zfs-tests/include/libtest.shlib +++ b/usr/src/test/zfs-tests/include/libtest.shlib @@ -26,7 +26,7 @@ # Copyright (c) 2017 by Tim Chase. All rights reserved. # Copyright (c) 2017 by Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2017 Datto Inc. -# Copyright 2019 Joyent, Inc. +# Copyright 2020 Joyent, Inc. # . ${STF_TOOLS}/contrib/include/logapi.shlib @@ -1568,7 +1568,7 @@ function get_disklist # pool disklist=$(zpool iostat -v $1 | nawk '(NR >4) {print $1}' | \ grep -v "\-\-\-\-\-" | \ - egrep -v -e "^(mirror|raidz1|raidz2|spare|log|cache)$") + egrep -v -e "^(mirror|raidz[1-3]|spare|log|cache|special|dedup)$") echo $disklist } diff --git a/usr/src/test/zfs-tests/include/zpool_script.shlib b/usr/src/test/zfs-tests/include/zpool_script.shlib new file mode 100644 index 0000000000..25daa3f06a --- /dev/null +++ b/usr/src/test/zfs-tests/include/zpool_script.shlib @@ -0,0 +1,49 @@ +# +# Common functions used by the zpool_status and zpool_iostat tests for running +# scripts with the -c option. +# +# Copyright (c) 2017 Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib + +function test_zpool_script { + script="$1" + testpool="$2" + cmd="$3" + wholecmd="$cmd $script $testpool" + out="$($wholecmd)" + + # Default number of columns that get printed without -c + if echo "$cmd" | grep -q iostat ; then + # iostat + dcols=7 + else + + # status + dcols=5 + fi + + # Get the new column name that the script created + col="$(echo "$out" | \ + awk '/^pool +alloc +free +read +write +/ {print $8} \ + /NAME +STATE +READ +WRITE +CKSUM/ {print $6}')" + + if [ -z "$col" ] ; then + log_fail "'$wholecmd' created no new columns" + fi + + # Count the number of columns for each vdev. Each script should produce + # at least one new column value. Even if scripts return blank, zpool + # will convert the blank to a '-' to make things awk-able. Normal + # zpool iostat -v output is 7 columns, so if the script ran correctly + # we should see more than that. + if ! newcols=$(echo "$out" | \ + awk '/\/dev/{print NF-'$dcols'; if (NF <= '$dcols') {exit 1}}' | \ + head -n 1) ; \ + then + log_fail "'$wholecmd' didn't create a new column value" + else + log_note "'$wholecmd' passed ($newcols new columns)" + fi +} diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run index 025c8919c9..01705fb5f4 100644 --- a/usr/src/test/zfs-tests/runfiles/delphix.run +++ b/usr/src/test/zfs-tests/runfiles/delphix.run @@ -430,7 +430,7 @@ user = [/opt/zfs-tests/tests/functional/cli_user/zpool_iostat] tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos', - 'zpool_iostat_003_neg'] + 'zpool_iostat_003_neg', 'zpool_iostat_004_pos'] user = [/opt/zfs-tests/tests/functional/cli_user/zpool_list] @@ -459,6 +459,9 @@ tests = ['devices_001_pos', 'devices_002_neg', 'devices_003_pos'] [/opt/zfs-tests/tests/functional/exec] tests = ['exec_001_pos', 'exec_002_neg'] +[/opt/zfs-tests/tests/functional/fault] +tests = ['zpool_status_-s'] + [/opt/zfs-tests/tests/functional/features/async_destroy] tests = ['async_destroy_001_pos'] diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run index 01a69576cc..17107c6efc 100644 --- a/usr/src/test/zfs-tests/runfiles/omnios.run +++ b/usr/src/test/zfs-tests/runfiles/omnios.run @@ -430,7 +430,7 @@ user = [/opt/zfs-tests/tests/functional/cli_user/zpool_iostat] tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos', - 'zpool_iostat_003_neg'] + 'zpool_iostat_003_neg', 'zpool_iostat_004_pos'] user = [/opt/zfs-tests/tests/functional/cli_user/zpool_list] @@ -459,6 +459,9 @@ tests = ['devices_001_pos', 'devices_002_neg', 'devices_003_pos'] [/opt/zfs-tests/tests/functional/exec] tests = ['exec_001_pos', 'exec_002_neg'] +[/opt/zfs-tests/tests/functional/fault] +tests = ['zpool_status_-s'] + [/opt/zfs-tests/tests/functional/features/async_destroy] tests = ['async_destroy_001_pos'] diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run index 161b71e22d..2f12f5de58 100644 --- a/usr/src/test/zfs-tests/runfiles/openindiana.run +++ b/usr/src/test/zfs-tests/runfiles/openindiana.run @@ -430,7 +430,7 @@ user = [/opt/zfs-tests/tests/functional/cli_user/zpool_iostat] tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos', - 'zpool_iostat_003_neg'] + 'zpool_iostat_003_neg', 'zpool_iostat_004_pos'] user = [/opt/zfs-tests/tests/functional/cli_user/zpool_list] @@ -462,6 +462,9 @@ tests = ['exec_001_pos', 'exec_002_neg'] [/opt/zfs-tests/tests/functional/features/async_destroy] tests = ['async_destroy_001_pos'] +[/opt/zfs-tests/tests/functional/fault] +tests = ['zpool_status_-s'] + [/opt/zfs-tests/tests/functional/grow_pool] tests = ['grow_pool_001_pos'] diff --git a/usr/src/test/zfs-tests/runfiles/smartos.run b/usr/src/test/zfs-tests/runfiles/smartos.run index a9ce4c13d1..f8c81e5865 100644 --- a/usr/src/test/zfs-tests/runfiles/smartos.run +++ b/usr/src/test/zfs-tests/runfiles/smartos.run @@ -378,7 +378,7 @@ user = [/opt/zfs-tests/tests/functional/cli_user/zpool_iostat] tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos', - 'zpool_iostat_003_neg'] + 'zpool_iostat_003_neg', 'zpool_iostat_004_pos'] user = [/opt/zfs-tests/tests/functional/cli_user/zpool_list] @@ -398,6 +398,9 @@ tests = ['devices_003_pos'] [/opt/zfs-tests/tests/functional/exec] tests = ['exec_001_pos', 'exec_002_neg'] +[/opt/zfs-tests/tests/functional/fault] +tests = ['zpool_status_-s'] + [/opt/zfs-tests/tests/functional/features/async_destroy] tests = ['async_destroy_001_pos'] diff --git a/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_003_pos.ksh b/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_003_pos.ksh index 0c631e0eea..78d40ce56d 100755 --- a/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_003_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_003_pos.ksh @@ -14,7 +14,6 @@ # # Copyright (c) 2017, Intel Corporation. # Copyright (c) 2018 by Delphix. All rights reserved. -# Copyright 2019 Joyent, Inc. # . $STF_SUITE/tests/functional/alloc_class/alloc_class.kshlib @@ -39,17 +38,17 @@ do if [ "$type" = "mirror" ]; then log_must zpool add $TESTPOOL special mirror \ $CLASS_DISK0 $CLASS_DISK1 $CLASS_DISK2 - log_must zpool clear $TESTPOOL $CLASS_DISK0 - log_must zpool clear $TESTPOOL $CLASS_DISK1 - log_must zpool clear $TESTPOOL $CLASS_DISK2 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK0 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK1 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK2 elif [ "$type" = "raidz" ]; then log_must zpool add $TESTPOOL special mirror \ $CLASS_DISK0 $CLASS_DISK1 - log_must zpool clear $TESTPOOL $CLASS_DISK0 - log_must zpool clear $TESTPOOL $CLASS_DISK1 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK0 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK1 else log_must zpool add $TESTPOOL special $CLASS_DISK0 - log_must zpool clear $TESTPOOL $CLASS_DISK0 + log_must zpool iostat -H $TESTPOOL $CLASS_DISK0 fi log_must zpool destroy -f $TESTPOOL diff --git a/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_007_pos.ksh b/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_007_pos.ksh index b871034394..106a6d933a 100755 --- a/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_007_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/alloc_class/alloc_class_007_pos.ksh @@ -14,7 +14,6 @@ # # Copyright (c) 2017, Intel Corporation. # Copyright (c) 2018 by Delphix. All rights reserved. -# Copyright 2019 Joyent, Inc. # . $STF_SUITE/tests/functional/alloc_class/alloc_class.kshlib @@ -36,8 +35,7 @@ log_must zpool create $TESTPOOL raidz $ZPOOL_DISKS \ special mirror $CLASS_DISK0 $CLASS_DISK1 log_must zpool replace $TESTPOOL $CLASS_DISK1 $CLASS_DISK2 log_must sleep 10 -log_must zpool status $TESTPOOL | nawk -v dev=$CLASS_DISK2 \ - 'BEGIN {res=1} {if ($1 == dev) res=0} END {exit res}' +log_must zpool iostat -H $TESTPOOL $CLASS_DISK2 log_must zpool destroy -f $TESTPOOL log_pass $claim diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.kshlib b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.kshlib index c32f72b504..ff06248588 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.kshlib +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.kshlib @@ -343,6 +343,14 @@ function get_last_txg_synced { typeset pool=$1 + if is_linux; then + txg=$(tail "/proc/spl/kstat/zfs/$pool/txgs" | + awk '$3=="C" {print $1}' | tail -1) + [[ "$txg" ]] || txg=0 + echo $txg + return 0 + fi + typeset spas spas=$(mdb -k -e "::spa") [[ $? -ne 0 ]] && return 1 diff --git a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh index 9c2fb74ed4..b605ceb8ee 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh @@ -33,4 +33,4 @@ DISK=${DISKS%% *} -default_setup $DISK +default_raidz_setup $DISKS diff --git a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh index 903ea1c5f7..c67031780b 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh @@ -33,13 +33,13 @@ # # DESCRIPTION: -# Verify that 'zpool iostat [interval [count]' can be executed as non-root. +# Verify that 'zpool iostat [interval [count]]' can be executed as non-root. # # STRATEGY: # 1. Set the interval to 1 and count to 4. # 2. Sleep for 4 seconds. # 3. Verify that the output has 4 records. -# +# 4. Set interval to 0.5 and count to 1 to test floating point intervals. verify_runnable "both" @@ -68,4 +68,7 @@ if [[ $stat_count -ne 4 ]]; then log_fail "zpool iostat [pool_name] [interval] [count] failed" fi +# Test a floating point interval value +log_must zpool iostat -v 0.5 1 + log_pass "zpool iostat [pool_name ...] [interval] [count] passed" diff --git a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh index 0b4a87f66e..c42ddf000f 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh @@ -51,13 +51,15 @@ else fi set -A args "" "-?" "-f" "nonexistpool" "$TESTPOOL/$TESTFS" \ - "$testpool 1.23" "$testpool 0" "$testpool -1" "$testpool 1 0" \ - "$testpool 0 0" + "$testpool 0" "$testpool -1" "$testpool 1 0" \ + "$testpool 0 0" "$testpool -wl" "$testpool -wq" "$testpool -wr" \ + "$testpool -rq" "$testpool -lr" log_assert "Executing 'zpool iostat' with bad options fails" typeset -i i=1 while [[ $i -lt ${#args[*]} ]]; do + log_assert "doing $ZPOOL iostat ${args[i]}" log_mustnot zpool iostat ${args[i]} ((i = i + 1)) done diff --git a/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh new file mode 100755 index 0000000000..25d1c845b6 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh @@ -0,0 +1,76 @@ +#!/bin/ksh -p +# +# 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. +# + +# +# Copyright (c) 2013 by Delphix. All rights reserved. +# + +# Copyright (C) 2016 Lawrence Livermore National Security, LLC. + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Executing 'zpool iostat' command with various combinations of extended +# stats (-lqwr), parsable/script options (-pH), and misc lists of pools +# and vdevs. +# +# STRATEGY: +# 1. Create an array of mixed 'zpool iostat' options. +# 2. Execute each element of the array. +# 3. Verify an error code is returned. +# + +verify_runnable "both" + +typeset testpool +if is_global_zone ; then + testpool=$TESTPOOL +else + testpool=${TESTPOOL%%/*} +fi + +set -A args "" "-v" "-q" "-l" "-lq $TESTPOOL" "-ql ${DISKS[0]} ${DISKS[1]}" \ + "-w $TESTPOOL ${DISKS[0]} ${DISKS[1]}" \ + "-wp $TESTPOOL" \ + "-qlH $TESTPOOL ${DISKS[0]}" \ + "-vpH ${DISKS[0]}" \ + "-wpH ${DISKS[0]}" \ + "-r ${DISKS[0]}" \ + "-rpH ${DISKS[0]}" + +log_assert "Executing 'zpool iostat' with extended stat options succeeds" +log_note "testpool: $TESTPOOL, disks $DISKS" + +typeset -i i=1 +while [[ $i -lt ${#args[*]} ]]; do + log_note "doing $ZPOOL iostat ${args[i]}" + log_must zpool iostat ${args[i]} + ((i = i + 1)) +done + +log_pass "Executing 'zpool iostat' with extended stat options succeeds" diff --git a/usr/src/test/zfs-tests/tests/functional/devices/devices_common.kshlib b/usr/src/test/zfs-tests/tests/functional/devices/devices_common.kshlib index 24f7c7e018..a68e22038f 100644 --- a/usr/src/test/zfs-tests/tests/functional/devices/devices_common.kshlib +++ b/usr/src/test/zfs-tests/tests/functional/devices/devices_common.kshlib @@ -26,6 +26,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2020 Joyent, Inc. # . $STF_SUITE/tests/functional/devices/devices.cfg @@ -42,6 +43,10 @@ function create_dev_file typeset filetype=$1 typeset filename=$2 + # On illumos we need access to the root zpool to get the major/minor + # numbers here. + export __ZFS_POOL_EXCLUDE="" + case $filetype in b) devtype=$(df -n / | awk '{print $3}') diff --git a/usr/src/test/zfs-tests/tests/functional/fault/Makefile b/usr/src/test/zfs-tests/tests/functional/fault/Makefile new file mode 100644 index 0000000000..00d2de10a3 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/fault/Makefile @@ -0,0 +1,21 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/zfs-tests +TARGETDIR = $(ROOTOPTPKG)/tests/functional/fault + +include $(SRC)/test/zfs-tests/Makefile.com diff --git a/usr/src/test/zfs-tests/tests/functional/fault/cleanup.ksh b/usr/src/test/zfs-tests/tests/functional/fault/cleanup.ksh new file mode 100755 index 0000000000..45b94723a5 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/fault/cleanup.ksh @@ -0,0 +1,36 @@ +#!/bin/ksh -p +# +# 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) 2016, 2017 by Intel Corporation. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/fault/fault.cfg + +verify_runnable "global" + +cleanup_devices $DISKS + +zed_stop +zed_cleanup resilver_finish-start-scrub.sh + +log_pass diff --git a/usr/src/test/zfs-tests/tests/functional/fault/fault.cfg b/usr/src/test/zfs-tests/tests/functional/fault/fault.cfg new file mode 100644 index 0000000000..25601a71a3 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/fault/fault.cfg @@ -0,0 +1,57 @@ +# +# 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) 2016, 2017 by Intel Corporation. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "global" + +export DISK_ARRAY_NUM=$(echo ${DISKS} | nawk '{print NF}') +export DISKSARRAY=$DISKS +export FSIZE=10M +export MAXTIMEOUT=30 + +export SDSIZE=256 +export SDHOSTS=1 +export SDTGTS=1 +export SDLUNS=1 + +export DISK1=$(echo $DISKS | nawk '{print $1}') +export DISK2=$(echo $DISKS | nawk '{print $2}') +export DISK3=$(echo $DISKS | nawk '{print $3}') + +if is_linux; then + set_slice_prefix + set_device_dir + devs_id[0]=$(get_persistent_disk_name $DISK1) + devs_id[1]=$(get_persistent_disk_name $DISK2) + devs_id[2]=$(get_persistent_disk_name $DISK3) + export devs_id +else + DEV_DSKDIR="/dev" +fi + +export VDEV_FILES="$TEST_BASE_DIR/file-1 $TEST_BASE_DIR/file-2 \ + $TEST_BASE_DIR/file-3 $TEST_BASE_DIR/file-4" +export SPARE_FILE="$TEST_BASE_DIR/spare-1" +export FAULT_FILE="$TEST_BASE_DIR/file-1" diff --git a/usr/src/test/zfs-tests/tests/functional/fault/setup.ksh b/usr/src/test/zfs-tests/tests/functional/fault/setup.ksh new file mode 100755 index 0000000000..b78ee8ccdc --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/fault/setup.ksh @@ -0,0 +1,34 @@ +#!/bin/ksh -p +# +# 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) 2016, 2017 by Intel Corporation. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/fault/fault.cfg + +verify_runnable "global" + +zed_setup resilver_finish-start-scrub.sh +zed_start + +log_pass diff --git a/usr/src/test/zfs-tests/tests/functional/fault/zpool_status_-s.ksh b/usr/src/test/zfs-tests/tests/functional/fault/zpool_status_-s.ksh new file mode 100755 index 0000000000..b90db23c36 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/fault/zpool_status_-s.ksh @@ -0,0 +1,84 @@ +#!/bin/ksh -p +# +# 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) 2018 by Lawrence Livermore National Security, LLC. +# Copyright 2019 Joyent, Inc. +# + +# DESCRIPTION: +# Verify zpool status -s (slow IOs) works +# +# STRATEGY: +# 1. Create a file +# 2. Inject slow IOs into the pool +# 3. Verify we can see the slow IOs with "zpool status -s". +# 4. Verify we can see delay events. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/include/zpool_script.shlib + +# Zol/illumos Porting Note: The commands commented out below are due to the ZoL +# "event" support which has not yet been ported to illumos. + +DISK=${DISKS%% *} + +verify_runnable "both" + +log_must zpool create $TESTPOOL mirror ${DISKS} + +function cleanup +{ + log_must zinject -c all + log_must set_tunable32 zio_slow_io_ms $OLD_SLOW_IO +# log_must set_tunable64 zfs_slow_io_events_per_second $OLD_SLOW_IO_EVENTS + log_must destroy_pool $TESTPOOL +} + +log_onexit cleanup + +# log_must zpool events -c + +# Mark any IOs greater than 10ms as slow IOs +OLD_SLOW_IO=$(get_tunable zio_slow_io_ms) +# OLD_SLOW_IO_EVENTS=$(get_tunable zfs_slow_io_events_per_second) +log_must set_tunable32 zio_slow_io_ms 10 +# log_must set_tunable64 zfs_slow_io_events_per_second 1000 + +# Create 20ms IOs +log_must zinject -d $DISK -D20:100 $TESTPOOL +log_must mkfile 1048576 /$TESTPOOL/testfile +log_must zpool sync $TESTPOOL + +log_must zinject -c all +SLOW_IOS=$(zpool status -sp | grep "$DISK" | awk '{print $6}') +#DELAY_EVENTS=$(zpool events | grep delay | wc -l) + +# if [ $SLOW_IOS -gt 0 ] && [ $DELAY_EVENTS -gt 0 ] ; then +# log_pass "Correctly saw $SLOW_IOS slow IOs and $DELAY_EVENTS delay events" +if [ $SLOW_IOS -gt 0 ] ; then + log_pass "Correctly saw $SLOW_IOS slow IOs" +else +# log_fail "Only saw $SLOW_IOS slow IOs and $DELAY_EVENTS delay events" + log_fail "Only saw $SLOW_IOS slow IOs" +fi diff --git a/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh index 497529f94f..ccf4312e76 100644 --- a/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh @@ -26,6 +26,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2020 Joyent, Inc. # . $STF_SUITE/include/libtest.shlib @@ -201,8 +202,13 @@ function get_mntpt_val #dataset src index mnt_val=`get_prop mountpoint $dset` - mod_prop_val=${mnt_val##*/} - new_path="/"$mod_prop_val$new_path + if [[ $dset == $src ]]; then + new_path=$mnt_val$new_path + else + mod_prop_val=${mnt_val##*/} + new_path="/"$mod_prop_val$new_path + fi + dataset=$dset done diff --git a/usr/src/test/zfs-tests/tests/functional/trim/trim.kshlib b/usr/src/test/zfs-tests/tests/functional/trim/trim.kshlib index 77ee7fe0eb..92687c3eba 100644 --- a/usr/src/test/zfs-tests/tests/functional/trim/trim.kshlib +++ b/usr/src/test/zfs-tests/tests/functional/trim/trim.kshlib @@ -19,7 +19,7 @@ . $STF_SUITE/tests/functional/cli_root/zpool_trim/zpool_trim.kshlib # -# Get the actual on disk disk for the provided file. +# Get the actual size on disk for the provided file. # function get_size_mb { @@ -29,47 +29,6 @@ function get_size_mb } # -# Use mdb to get the approximate number of trim IOs issued for the pool. -# This really is just used to ensure that trim IO has occured and is a -# temporary solution until illumos supports zpool iostat histograms. -# -function get_illumos_trim_io -{ - typeset pool="${1-:$TESTPOOL}" - typeset spa - typeset vdevs - typeset total_trim - typeset v - typeset trimmed - typeset b - - # Get vdevs for the pool - spa=$(mdb -ke '::spa' | awk -v pool=$pool '{if ($3 == pool) print $1}') - vdevs=$(mdb -ke "$spa::spa -v" | awk '{ - if ($4 == "DESCRIPTION") {st=1; next} - if (st == 1) print $1 - }') - - # Get trim counts for each vdev - total_trim=0 - for v in $vdevs - do - b=$(mdb -ke "$v::print vdev_t vdev_trim_bytes_done" | \ - awk '{print $3}') - trimmed=$(mdb -e "$b=E") - trimmed=$((trimmed / 4096)) - total_trim=$((total_trim + trimmed)) - - b=$(mdb -ke "$v::print vdev_t vdev_autotrim_bytes_done" | \ - awk '{print $3}') - trimmed=$(mdb -e "$b=E") - trimmed=$((trimmed / 4096)) - total_trim=$((total_trim + trimmed)) - done - echo -n "$total_trim" -} - -# # Get the number of trim IOs issued for the pool (ind or agg). # function get_trim_io @@ -106,11 +65,7 @@ function verify_trim_io typeset min_trim_ios=${3:-100} typeset ios - if is_linux; then - ios=$(get_trim_io $pool $type) - else - ios=$(get_illumos_trim_io $pool $type) - fi + ios=$(get_trim_io $pool $type) if [[ $ios -ge $min_trim_ios ]]; then log_note "Issued $ios $type trim IOs for pool $pool" diff --git a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_common.shlib b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_common.shlib index 67b7c432cb..c857184751 100644 --- a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_common.shlib +++ b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_common.shlib @@ -26,6 +26,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2020 Joyent, Inc. # . $STF_SUITE/include/libtest.shlib @@ -133,6 +134,7 @@ function is_swap_inuse return 1 fi - swap -l | grep -w $device > /dev/null 2>&1 + swap -l | awk 'NR > 1 { print $1 }' | \ + grep "^$device\$" > /dev/null 2>&1 return $? } diff --git a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh index 683ad84ead..c7b7b4345e 100644 --- a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh @@ -28,6 +28,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. # Copyright 2016 Nexenta Systems, Inc. +# Copyright 2020 Joyent, Inc. # . $STF_SUITE/include/libtest.shlib @@ -54,7 +55,8 @@ function cleanup safe_dumpadm $savedumpdev fi - swap -l | grep -w $voldev > /dev/null 2>&1 + swap -l | awk 'NR > 1 { print $1 }' | \ + grep "^$voldev\$" > /dev/null 2>&1 if (( $? == 0 )); then log_must swap -d $voldev fi diff --git a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh index e6fb727d92..c84fbe5f92 100644 --- a/usr/src/test/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh @@ -27,6 +27,7 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright 2020 Joyent, Inc. # . $STF_SUITE/include/libtest.shlib @@ -54,8 +55,6 @@ function cleanup log_must mv $PREV_VFSTAB_FILE $VFSTAB_FILE [[ -f $PREV_VFSTAB_FILE ]] && rm -f $PREV_VFSTAB_FILE - log_must swapadd $VFSTAB_FILE - if is_swap_inuse $voldev ; then log_must swap -d $voldev fi diff --git a/usr/src/tools/env/illumos.sh b/usr/src/tools/env/illumos.sh index f8b2549def..cdf3a42bdd 100644 --- a/usr/src/tools/env/illumos.sh +++ b/usr/src/tools/env/illumos.sh @@ -118,6 +118,11 @@ export ENABLE_SMB_PRINTING= #export BUILDPY2='#' #export BUILDPY3='#' +# To disable building this workspace's tools in $SRC/tools with either Python2 +# or Python3 (but not both!), uncomment either of these lines: +#export BUILDPY2TOOLS='#' +#export BUILDPY3TOOLS='#' + # Set console color scheme either by build type: # #export RELEASE_CONSOLE_COLOR="-DDEFAULT_ANSI_FOREGROUND=ANSI_COLOR_BLACK \ diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 833adf5bc5..95c35a0f5f 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -1428,6 +1428,7 @@ spa_unload(spa_t *spa) ASSERT(MUTEX_HELD(&spa_namespace_lock)); ASSERT(spa_state(spa) != POOL_STATE_UNINITIALIZED); + spa_import_progress_remove(spa); spa_load_note(spa, "UNLOADING"); /* @@ -2389,6 +2390,7 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type) int error; spa->spa_load_state = state; + (void) spa_import_progress_set_state(spa, spa_load_state(spa)); gethrestime(&spa->spa_loaded_ts); error = spa_load_impl(spa, type, &ereport); @@ -2411,6 +2413,8 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type) spa->spa_load_state = error ? SPA_LOAD_ERROR : SPA_LOAD_NONE; spa->spa_ena = 0; + (void) spa_import_progress_set_state(spa, spa_load_state(spa)); + return (error); } @@ -2634,6 +2638,9 @@ spa_activity_check(spa_t *spa, uberblock_t *ub, nvlist_t *config) import_expire = gethrtime() + import_delay; while (gethrtime() < import_expire) { + (void) spa_import_progress_set_mmp_check(spa, + NSEC2SEC(import_expire - gethrtime())); + vdev_uberblock_load(rvd, ub, &mmp_label); if (txg != ub->ub_txg || timestamp != ub->ub_timestamp || @@ -3000,6 +3007,10 @@ spa_ld_select_uberblock(spa_t *spa, spa_import_type_t type) return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, ENXIO)); } + if (spa->spa_load_max_txg != UINT64_MAX) { + (void) spa_import_progress_set_max_txg(spa, + (u_longlong_t)spa->spa_load_max_txg); + } spa_load_note(spa, "using uberblock with txg=%llu", (u_longlong_t)ub->ub_txg); @@ -3935,6 +3946,8 @@ spa_ld_mos_init(spa_t *spa, spa_import_type_t type) if (error != 0) return (error); + spa_import_progress_add(spa); + /* * Now that we have the vdev tree, try to open each vdev. This involves * opening the underlying physical device, retrieving its geometry and @@ -4365,6 +4378,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, char **ereport) spa_config_exit(spa, SCL_CONFIG, FTAG); } + spa_import_progress_remove(spa); spa_load_note(spa, "LOADED"); return (0); @@ -4425,6 +4439,7 @@ spa_load_best(spa_t *spa, spa_load_state_t state, uint64_t max_request, * from previous txgs when spa_load fails. */ ASSERT(spa->spa_import_flags & ZFS_IMPORT_CHECKPOINT); + spa_import_progress_remove(spa); return (load_error); } @@ -4436,6 +4451,7 @@ spa_load_best(spa_t *spa, spa_load_state_t state, uint64_t max_request, if (rewind_flags & ZPOOL_NEVER_REWIND) { nvlist_free(config); + spa_import_progress_remove(spa); return (load_error); } @@ -4478,6 +4494,7 @@ spa_load_best(spa_t *spa, spa_load_state_t state, uint64_t max_request, if (state == SPA_LOAD_RECOVER) { ASSERT3P(loadinfo, ==, NULL); + spa_import_progress_remove(spa); return (rewind_error); } else { /* Store the rewind info as part of the initial load info */ @@ -4488,6 +4505,7 @@ spa_load_best(spa_t *spa, spa_load_state_t state, uint64_t max_request, fnvlist_free(spa->spa_load_info); spa->spa_load_info = loadinfo; + spa_import_progress_remove(spa); return (load_error); } } @@ -4757,6 +4775,8 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config) ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) == 0); vdev_get_stats(vd, vs); + vdev_config_generate_stats(vd, l2cache[i]); + } } } diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c index 45e1978803..9dac4e2ddc 100644 --- a/usr/src/uts/common/fs/zfs/spa_misc.c +++ b/usr/src/uts/common/fs/zfs/spa_misc.c @@ -28,6 +28,7 @@ * Copyright (c) 2017 Datto Inc. * Copyright 2019 Joyent, Inc. * Copyright (c) 2017, Intel Corporation. + * Copyright 2020 Joyent, Inc. */ #include <sys/zfs_context.h> @@ -635,6 +636,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot) mutex_init(&spa->spa_vdev_top_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_iokstat_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_flushed_ms_lock, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&spa->spa_imp_kstat_lock, NULL, MUTEX_DEFAULT, NULL); cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL); cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL); @@ -844,6 +846,7 @@ spa_remove(spa_t *spa) mutex_destroy(&spa->spa_suspend_lock); mutex_destroy(&spa->spa_vdev_top_lock); mutex_destroy(&spa->spa_iokstat_lock); + mutex_destroy(&spa->spa_imp_kstat_lock); kmem_free(spa, sizeof (spa_t)); } @@ -2046,6 +2049,140 @@ spa_dirty_data(spa_t *spa) /* * ========================================================================== + * SPA Import Progress Routines + * The illumos implementation of these are different from OpenZFS. OpenZFS + * uses the Linux /proc fs, whereas we use a kstat on the spa. + * ========================================================================== + */ + +typedef struct spa_import_progress { + kstat_named_t sip_load_state; + kstat_named_t sip_mmp_sec_remaining; /* MMP activity check */ + kstat_named_t sip_load_max_txg; /* rewind txg */ +} spa_import_progress_t; + +static void +spa_import_progress_init(void) +{ +} + +static void +spa_import_progress_destroy(void) +{ +} + +void spa_import_progress_add(spa_t *); + +int +spa_import_progress_set_state(spa_t *spa, spa_load_state_t load_state) +{ + if (spa->spa_imp_kstat == NULL) + spa_import_progress_add(spa); + + mutex_enter(&spa->spa_imp_kstat_lock); + if (spa->spa_imp_kstat != NULL) { + spa_import_progress_t *sip = spa->spa_imp_kstat->ks_data; + if (sip != NULL) + sip->sip_load_state.value.ui64 = (uint64_t)load_state; + } + mutex_exit(&spa->spa_imp_kstat_lock); + + return (0); +} + +int +spa_import_progress_set_max_txg(spa_t *spa, uint64_t load_max_txg) +{ + if (spa->spa_imp_kstat == NULL) + spa_import_progress_add(spa); + + mutex_enter(&spa->spa_imp_kstat_lock); + if (spa->spa_imp_kstat != NULL) { + spa_import_progress_t *sip = spa->spa_imp_kstat->ks_data; + if (sip != NULL) + sip->sip_load_max_txg.value.ui64 = load_max_txg; + } + mutex_exit(&spa->spa_imp_kstat_lock); + + return (0); +} + +int +spa_import_progress_set_mmp_check(spa_t *spa, uint64_t mmp_sec_remaining) +{ + if (spa->spa_imp_kstat == NULL) + spa_import_progress_add(spa); + + mutex_enter(&spa->spa_imp_kstat_lock); + if (spa->spa_imp_kstat != NULL) { + spa_import_progress_t *sip = spa->spa_imp_kstat->ks_data; + if (sip != NULL) + sip->sip_mmp_sec_remaining.value.ui64 = + mmp_sec_remaining; + } + mutex_exit(&spa->spa_imp_kstat_lock); + + return (0); +} + +/* + * A new import is in progress. Add an entry. + */ +void +spa_import_progress_add(spa_t *spa) +{ + char *poolname = NULL; + spa_import_progress_t *sip; + + mutex_enter(&spa->spa_imp_kstat_lock); + if (spa->spa_imp_kstat != NULL) { + sip = spa->spa_imp_kstat->ks_data; + sip->sip_load_state.value.ui64 = (uint64_t)spa_load_state(spa); + mutex_exit(&spa->spa_imp_kstat_lock); + return; + } + + (void) nvlist_lookup_string(spa->spa_config, ZPOOL_CONFIG_POOL_NAME, + &poolname); + if (poolname == NULL) + poolname = spa_name(spa); + + spa->spa_imp_kstat = kstat_create("zfs_import", 0, poolname, + "zfs_misc", KSTAT_TYPE_NAMED, + sizeof (spa_import_progress_t) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL); + if (spa->spa_imp_kstat != NULL) { + sip = kmem_alloc(sizeof (spa_import_progress_t), KM_SLEEP); + spa->spa_imp_kstat->ks_data = sip; + + sip->sip_load_state.value.ui64 = (uint64_t)spa_load_state(spa); + + kstat_named_init(&sip->sip_load_state, + "spa_load_state", KSTAT_DATA_UINT64); + kstat_named_init(&sip->sip_mmp_sec_remaining, + "mmp_sec_remaining", KSTAT_DATA_UINT64); + kstat_named_init(&sip->sip_load_max_txg, + "spa_load_max_txg", KSTAT_DATA_UINT64); + spa->spa_imp_kstat->ks_lock = &spa->spa_imp_kstat_lock; + kstat_install(spa->spa_imp_kstat); + } + mutex_exit(&spa->spa_imp_kstat_lock); +} + +void +spa_import_progress_remove(spa_t *spa) +{ + if (spa->spa_imp_kstat != NULL) { + void *data = spa->spa_imp_kstat->ks_data; + + kstat_delete(spa->spa_imp_kstat); + spa->spa_imp_kstat = NULL; + kmem_free(data, sizeof (spa_import_progress_t)); + } +} + +/* + * ========================================================================== * Initialization and Termination * ========================================================================== */ @@ -2122,6 +2259,7 @@ spa_init(int mode) spa_config_load(); l2arc_start(); scan_init(); + spa_import_progress_init(); } void @@ -2141,6 +2279,7 @@ spa_fini(void) unique_fini(); zfs_refcount_fini(); scan_fini(); + spa_import_progress_destroy(); avl_destroy(&spa_namespace_avl); avl_destroy(&spa_spare_avl); diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h index cb736db5dd..e017462613 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa.h +++ b/usr/src/uts/common/fs/zfs/sys/spa.h @@ -900,6 +900,12 @@ typedef struct spa_iostats { kstat_named_t autotrim_bytes_failed; } spa_iostats_t; +extern int spa_import_progress_set_state(spa_t *, spa_load_state_t); +extern int spa_import_progress_set_max_txg(spa_t *, uint64_t); +extern int spa_import_progress_set_mmp_check(spa_t *, uint64_t); +extern void spa_import_progress_add(spa_t *); +extern void spa_import_progress_remove(spa_t *); + /* Pool configuration locks */ extern int spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw); extern void spa_config_enter(spa_t *spa, int locks, void *tag, krw_t rw); @@ -1053,9 +1059,11 @@ extern void spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation, /* error handling */ struct zbookmark_phys; extern void spa_log_error(spa_t *spa, const struct zbookmark_phys *zb); -extern void zfs_ereport_post(const char *class, spa_t *spa, vdev_t *vd, +extern int zfs_ereport_post(const char *class, spa_t *spa, vdev_t *vd, const struct zbookmark_phys *zb, struct zio *zio, uint64_t stateoroffset, uint64_t length); +extern boolean_t zfs_ereport_is_valid(const char *class, spa_t *spa, vdev_t *vd, + zio_t *zio); extern void zfs_post_remove(spa_t *spa, vdev_t *vd); extern void zfs_post_state_change(spa_t *spa, vdev_t *vd); extern void zfs_post_autoreplace(spa_t *spa, vdev_t *vd); diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h index ad9a03e077..88a172eed5 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h @@ -400,6 +400,14 @@ struct spa { int spa_queued; } spa_queue_stats[ZIO_PRIORITY_NUM_QUEUEABLE]; + /* + * The following two members diverge from OpenZFS. Upstream import + * status is built around the Linux /proc fs. On illumos we use a kstat + * to track import status. spa_imp_kstat_lock protects spa_imp_kstat. + */ + kmutex_t spa_imp_kstat_lock; + struct kstat *spa_imp_kstat; /* kstat for import status */ + /* arc_memory_throttle() parameters during low memory condition */ uint64_t spa_lowmem_page_load; /* memory load during txg */ uint64_t spa_lowmem_last_txg; /* txg window start */ diff --git a/usr/src/uts/common/fs/zfs/sys/vdev.h b/usr/src/uts/common/fs/zfs/sys/vdev.h index 707e177fc3..a6de7e6f2c 100644 --- a/usr/src/uts/common/fs/zfs/sys/vdev.h +++ b/usr/src/uts/common/fs/zfs/sys/vdev.h @@ -99,6 +99,7 @@ extern void vdev_deadman(vdev_t *vd); extern void vdev_xlate(vdev_t *vd, const range_seg64_t *logical_rs, range_seg64_t *physical_rs); +extern void vdev_get_stats_ex(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx); extern void vdev_get_stats(vdev_t *vd, vdev_stat_t *vs); extern void vdev_clear_stats(vdev_t *vd); extern void vdev_stat_update(zio_t *zio, uint64_t psize); @@ -173,6 +174,7 @@ extern uint64_t vdev_label_offset(uint64_t psize, int l, uint64_t offset); extern int vdev_label_number(uint64_t psise, uint64_t offset); extern nvlist_t *vdev_label_read_config(vdev_t *vd, uint64_t txg); extern void vdev_uberblock_load(vdev_t *, struct uberblock *, nvlist_t **); +extern void vdev_config_generate_stats(vdev_t *vd, nvlist_t *nv); extern void vdev_label_write(zio_t *zio, vdev_t *vd, int l, abd_t *buf, uint64_t offset, uint64_t size, zio_done_func_t *done, void *private, int flags); diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h index fccd0a6784..774ed92db5 100644 --- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h @@ -230,6 +230,7 @@ struct vdev { vdev_t **vdev_child; /* array of children */ uint64_t vdev_children; /* number of children */ vdev_stat_t vdev_stat; /* virtual device statistics */ + vdev_stat_ex_t vdev_stat_ex; /* extended statistics */ boolean_t vdev_expanding; /* expand the vdev? */ boolean_t vdev_reopening; /* reopen in progress? */ boolean_t vdev_nonrot; /* true if solid state */ diff --git a/usr/src/uts/common/fs/zfs/sys/zio.h b/usr/src/uts/common/fs/zfs/sys/zio.h index 99805a339d..7592614d6d 100644 --- a/usr/src/uts/common/fs/zfs/sys/zio.h +++ b/usr/src/uts/common/fs/zfs/sys/zio.h @@ -472,6 +472,9 @@ struct zio { hrtime_t io_queued_timestamp; hrtime_t io_target_timestamp; hrtime_t io_dispatched; /* time I/O was dispatched to disk */ + hrtime_t io_delta; /* vdev queue service delta */ + hrtime_t io_delay; /* Device access time (disk or */ + /* file). */ avl_node_t io_queue_node; avl_node_t io_offset_node; avl_node_t io_alloc_node; @@ -657,7 +660,7 @@ extern void zfs_ereport_send_interim_checksum(zio_cksum_report_t *report); extern void zfs_ereport_free_checksum(zio_cksum_report_t *report); /* If we have the good data in hand, this function can be used */ -extern void zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, +extern int zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb, struct zio *zio, uint64_t offset, uint64_t length, const abd_t *good_data, const abd_t *bad_data, struct zio_bad_cksum *info); diff --git a/usr/src/uts/common/fs/zfs/sys/zio_priority.h b/usr/src/uts/common/fs/zfs/sys/zio_priority.h index 7d91a646d1..feb23fafd6 100644 --- a/usr/src/uts/common/fs/zfs/sys/zio_priority.h +++ b/usr/src/uts/common/fs/zfs/sys/zio_priority.h @@ -14,6 +14,7 @@ */ /* * Copyright (c) 2014, 2016 by Delphix. All rights reserved. + * Copyright 2020 Joyent, Inc. */ #ifndef _ZIO_PRIORITY_H #define _ZIO_PRIORITY_H @@ -22,6 +23,10 @@ extern "C" { #endif +/* + * NOTE: If ZIO_PRIORITY_NUM_QUEUEABLE changes, update ZIO_PRIORITY_N_QUEUEABLE + * in uts/common/sys/fs/zfs.h to match. + */ typedef enum zio_priority { ZIO_PRIORITY_SYNC_READ, ZIO_PRIORITY_SYNC_WRITE, /* ZIL */ @@ -32,7 +37,6 @@ typedef enum zio_priority { ZIO_PRIORITY_INITIALIZING, /* initializing I/O */ ZIO_PRIORITY_TRIM, /* trim I/O (discard) */ ZIO_PRIORITY_NUM_QUEUEABLE, - ZIO_PRIORITY_NOW /* non-queued i/os (e.g. free) */ } zio_priority_t; diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c index 52a7a62e4a..01e892f4c4 100644 --- a/usr/src/uts/common/fs/zfs/vdev.c +++ b/usr/src/uts/common/fs/zfs/vdev.c @@ -3505,6 +3505,7 @@ vdev_clear(spa_t *spa, vdev_t *vd) vd->vdev_stat.vs_read_errors = 0; vd->vdev_stat.vs_write_errors = 0; vd->vdev_stat.vs_checksum_errors = 0; + vd->vdev_stat.vs_slow_ios = 0; for (int c = 0; c < vd->vdev_children; c++) vdev_clear(spa, vd->vdev_child[c]); @@ -3628,6 +3629,51 @@ vdev_accessible(vdev_t *vd, zio_t *zio) return (B_TRUE); } +static void +vdev_get_child_stat(vdev_t *cvd, vdev_stat_t *vs, vdev_stat_t *cvs) +{ + for (int t = 0; t < VS_ZIO_TYPES; t++) { + vs->vs_ops[t] += cvs->vs_ops[t]; + vs->vs_bytes[t] += cvs->vs_bytes[t]; + } + + cvs->vs_scan_removing = cvd->vdev_removing; +} + +/* + * Get extended stats + */ +static void +vdev_get_child_stat_ex(vdev_t *cvd, vdev_stat_ex_t *vsx, vdev_stat_ex_t *cvsx) +{ + int t, b; + for (t = 0; t < ZIO_TYPES; t++) { + for (b = 0; b < ARRAY_SIZE(vsx->vsx_disk_histo[0]); b++) + vsx->vsx_disk_histo[t][b] += cvsx->vsx_disk_histo[t][b]; + + for (b = 0; b < ARRAY_SIZE(vsx->vsx_total_histo[0]); b++) { + vsx->vsx_total_histo[t][b] += + cvsx->vsx_total_histo[t][b]; + } + } + + for (t = 0; t < ZIO_PRIORITY_NUM_QUEUEABLE; t++) { + for (b = 0; b < ARRAY_SIZE(vsx->vsx_queue_histo[0]); b++) { + vsx->vsx_queue_histo[t][b] += + cvsx->vsx_queue_histo[t][b]; + } + vsx->vsx_active_queue[t] += cvsx->vsx_active_queue[t]; + vsx->vsx_pend_queue[t] += cvsx->vsx_pend_queue[t]; + + for (b = 0; b < ARRAY_SIZE(vsx->vsx_ind_histo[0]); b++) + vsx->vsx_ind_histo[t][b] += cvsx->vsx_ind_histo[t][b]; + + for (b = 0; b < ARRAY_SIZE(vsx->vsx_agg_histo[0]); b++) + vsx->vsx_agg_histo[t][b] += cvsx->vsx_agg_histo[t][b]; + } + +} + boolean_t vdev_is_spacemap_addressable(vdev_t *vd) { @@ -3652,81 +3698,121 @@ vdev_is_spacemap_addressable(vdev_t *vd) /* * Get statistics for the given vdev. */ -void -vdev_get_stats(vdev_t *vd, vdev_stat_t *vs) +static void +vdev_get_stats_ex_impl(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx) { - spa_t *spa = vd->vdev_spa; - vdev_t *rvd = spa->spa_root_vdev; - vdev_t *tvd = vd->vdev_top; + int t; + /* + * If we're getting stats on the root vdev, aggregate the I/O counts + * over all top-level vdevs (i.e. the direct children of the root). + */ + if (!vd->vdev_ops->vdev_op_leaf) { + if (vs) { + memset(vs->vs_ops, 0, sizeof (vs->vs_ops)); + memset(vs->vs_bytes, 0, sizeof (vs->vs_bytes)); + } + if (vsx) + memset(vsx, 0, sizeof (*vsx)); - ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0); + for (int c = 0; c < vd->vdev_children; c++) { + vdev_t *cvd = vd->vdev_child[c]; + vdev_stat_t *cvs = &cvd->vdev_stat; + vdev_stat_ex_t *cvsx = &cvd->vdev_stat_ex; - mutex_enter(&vd->vdev_stat_lock); - bcopy(&vd->vdev_stat, vs, sizeof (*vs)); - vs->vs_timestamp = gethrtime() - vs->vs_timestamp; - vs->vs_state = vd->vdev_state; - vs->vs_rsize = vdev_get_min_asize(vd); - if (vd->vdev_ops->vdev_op_leaf) { - vs->vs_rsize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; + vdev_get_stats_ex_impl(cvd, cvs, cvsx); + if (vs) + vdev_get_child_stat(cvd, vs, cvs); + if (vsx) + vdev_get_child_stat_ex(cvd, vsx, cvsx); + + } + } else { /* - * Report intializing progress. Since we don't have the - * initializing locks held, this is only an estimate (although a - * fairly accurate one). + * We're a leaf. Just copy our ZIO active queue stats in. The + * other leaf stats are updated in vdev_stat_update(). */ - vs->vs_initialize_bytes_done = vd->vdev_initialize_bytes_done; - vs->vs_initialize_bytes_est = vd->vdev_initialize_bytes_est; - vs->vs_initialize_state = vd->vdev_initialize_state; - vs->vs_initialize_action_time = vd->vdev_initialize_action_time; - } + if (!vsx) + return; - /* - * Report manual TRIM progress. Since we don't have - * the manual TRIM locks held, this is only an - * estimate (although fairly accurate one). - */ - vs->vs_trim_notsup = !vd->vdev_has_trim; - vs->vs_trim_bytes_done = vd->vdev_trim_bytes_done; - vs->vs_trim_bytes_est = vd->vdev_trim_bytes_est; - vs->vs_trim_state = vd->vdev_trim_state; - vs->vs_trim_action_time = vd->vdev_trim_action_time; + memcpy(vsx, &vd->vdev_stat_ex, sizeof (vd->vdev_stat_ex)); - /* - * Report expandable space on top-level, non-auxillary devices only. - * The expandable space is reported in terms of metaslab sized units - * since that determines how much space the pool can expand. - */ - if (vd->vdev_aux == NULL && tvd != NULL) { - vs->vs_esize = P2ALIGN(vd->vdev_max_asize - vd->vdev_asize - - spa->spa_bootsize, 1ULL << tvd->vdev_ms_shift); - } - if (vd->vdev_aux == NULL && vd == vd->vdev_top && - vdev_is_concrete(vd)) { - vs->vs_fragmentation = (vd->vdev_mg != NULL) ? - vd->vdev_mg->mg_fragmentation : 0; + for (t = 0; t < ARRAY_SIZE(vd->vdev_queue.vq_class); t++) { + vsx->vsx_active_queue[t] = + vd->vdev_queue.vq_class[t].vqc_active; + vsx->vsx_pend_queue[t] = avl_numnodes( + &vd->vdev_queue.vq_class[t].vqc_queued_tree); + } } - if (vd->vdev_ops->vdev_op_leaf) - vs->vs_resilver_deferred = vd->vdev_resilver_deferred; +} - /* - * If we're getting stats on the root vdev, aggregate the I/O counts - * over all top-level vdevs (i.e. the direct children of the root). - */ - if (vd == rvd) { - for (int c = 0; c < rvd->vdev_children; c++) { - vdev_t *cvd = rvd->vdev_child[c]; - vdev_stat_t *cvs = &cvd->vdev_stat; +void +vdev_get_stats_ex(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx) +{ + vdev_t *tvd = vd->vdev_top; + mutex_enter(&vd->vdev_stat_lock); + if (vs) { + bcopy(&vd->vdev_stat, vs, sizeof (*vs)); + vs->vs_timestamp = gethrtime() - vs->vs_timestamp; + vs->vs_state = vd->vdev_state; + vs->vs_rsize = vdev_get_min_asize(vd); + if (vd->vdev_ops->vdev_op_leaf) { + vs->vs_rsize += VDEV_LABEL_START_SIZE + + VDEV_LABEL_END_SIZE; + /* + * Report initializing progress. Since we don't + * have the initializing locks held, this is only + * an estimate (although a fairly accurate one). + */ + vs->vs_initialize_bytes_done = + vd->vdev_initialize_bytes_done; + vs->vs_initialize_bytes_est = + vd->vdev_initialize_bytes_est; + vs->vs_initialize_state = vd->vdev_initialize_state; + vs->vs_initialize_action_time = + vd->vdev_initialize_action_time; - for (int t = 0; t < VS_ZIO_TYPES; t++) { - vs->vs_ops[t] += cvs->vs_ops[t]; - vs->vs_bytes[t] += cvs->vs_bytes[t]; - } - cvs->vs_scan_removing = cvd->vdev_removing; + /* + * Report manual TRIM progress. Since we don't have + * the manual TRIM locks held, this is only an + * estimate (although fairly accurate one). + */ + vs->vs_trim_notsup = !vd->vdev_has_trim; + vs->vs_trim_bytes_done = vd->vdev_trim_bytes_done; + vs->vs_trim_bytes_est = vd->vdev_trim_bytes_est; + vs->vs_trim_state = vd->vdev_trim_state; + vs->vs_trim_action_time = vd->vdev_trim_action_time; + } + /* + * Report expandable space on top-level, non-auxiliary devices + * only. The expandable space is reported in terms of metaslab + * sized units since that determines how much space the pool + * can expand. + */ + if (vd->vdev_aux == NULL && tvd != NULL) { + vs->vs_esize = P2ALIGN( + vd->vdev_max_asize - vd->vdev_asize, + 1ULL << tvd->vdev_ms_shift); } + if (vd->vdev_aux == NULL && vd == vd->vdev_top && + vdev_is_concrete(vd)) { + vs->vs_fragmentation = (vd->vdev_mg != NULL) ? + vd->vdev_mg->mg_fragmentation : 0; + } + if (vd->vdev_ops->vdev_op_leaf) + vs->vs_resilver_deferred = vd->vdev_resilver_deferred; } + + vdev_get_stats_ex_impl(vd, vs, vsx); mutex_exit(&vd->vdev_stat_lock); } void +vdev_get_stats(vdev_t *vd, vdev_stat_t *vs) +{ + return (vdev_get_stats_ex(vd, vs, NULL)); +} + +void vdev_clear_stats(vdev_t *vd) { mutex_enter(&vd->vdev_stat_lock); @@ -3758,6 +3844,7 @@ vdev_stat_update(zio_t *zio, uint64_t psize) vdev_t *pvd; uint64_t txg = zio->io_txg; vdev_stat_t *vs = &vd->vdev_stat; + vdev_stat_ex_t *vsx = &vd->vdev_stat_ex; zio_type_t type = zio->io_type; int flags = zio->io_flags; @@ -3808,18 +3895,42 @@ vdev_stat_update(zio_t *zio, uint64_t psize) vs->vs_self_healed += psize; } - zio_type_t vs_type = type; - /* - * TRIM ops and bytes are reported to user space as - * ZIO_TYPE_IOCTL. This is done to preserve the - * vdev_stat_t structure layout for user space. + * The bytes/ops/histograms are recorded at the leaf level and + * aggregated into the higher level vdevs in vdev_get_stats(). */ - if (type == ZIO_TYPE_TRIM) - vs_type = ZIO_TYPE_IOCTL; + if (vd->vdev_ops->vdev_op_leaf && + (zio->io_priority < ZIO_PRIORITY_NUM_QUEUEABLE)) { + zio_type_t vs_type = type; + + /* + * TRIM ops and bytes are reported to user space as + * ZIO_TYPE_IOCTL. This is done to preserve the + * vdev_stat_t structure layout for user space. + */ + if (type == ZIO_TYPE_TRIM) + vs_type = ZIO_TYPE_IOCTL; + + vs->vs_ops[vs_type]++; + vs->vs_bytes[vs_type] += psize; + + if (flags & ZIO_FLAG_DELEGATED) { + vsx->vsx_agg_histo[zio->io_priority] + [RQ_HISTO(zio->io_size)]++; + } else { + vsx->vsx_ind_histo[zio->io_priority] + [RQ_HISTO(zio->io_size)]++; + } - vs->vs_ops[vs_type]++; - vs->vs_bytes[vs_type] += psize; + if (zio->io_delta && zio->io_delay) { + vsx->vsx_queue_histo[zio->io_priority] + [L_HISTO(zio->io_delta - zio->io_delay)]++; + vsx->vsx_disk_histo[type] + [L_HISTO(zio->io_delay)]++; + vsx->vsx_total_histo[type] + [L_HISTO(zio->io_delta)]++; + } + } mutex_exit(&vd->vdev_stat_lock); return; diff --git a/usr/src/uts/common/fs/zfs/vdev_label.c b/usr/src/uts/common/fs/zfs/vdev_label.c index bb377f08ce..6235b06f17 100644 --- a/usr/src/uts/common/fs/zfs/vdev_label.c +++ b/usr/src/uts/common/fs/zfs/vdev_label.c @@ -23,7 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. * Copyright (c) 2017, Intel Corporation. - * Copyright 2019 Joyent, Inc. + * Copyright 2020 Joyent, Inc. */ /* @@ -211,6 +211,169 @@ vdev_label_write(zio_t *zio, vdev_t *vd, int l, abd_t *buf, uint64_t offset, ZIO_PRIORITY_SYNC_WRITE, flags, B_TRUE)); } +/* + * Generate the nvlist representing this vdev's stats + */ +void +vdev_config_generate_stats(vdev_t *vd, nvlist_t *nv) +{ + nvlist_t *nvx; + vdev_stat_t *vs; + vdev_stat_ex_t *vsx; + + vs = kmem_alloc(sizeof (*vs), KM_SLEEP); + vsx = kmem_alloc(sizeof (*vsx), KM_SLEEP); + + vdev_get_stats_ex(vd, vs, vsx); + fnvlist_add_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, + (uint64_t *)vs, sizeof (*vs) / sizeof (uint64_t)); + + /* + * Add extended stats into a special extended stats nvlist. This keeps + * all the extended stats nicely grouped together. The extended stats + * nvlist is then added to the main nvlist. + */ + nvx = fnvlist_alloc(); + + /* ZIOs in flight to disk */ + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_SYNC_READ]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_SYNC_WRITE]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_ASYNC_READ]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_ASYNC_WRITE]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_SCRUB]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE, + vsx->vsx_active_queue[ZIO_PRIORITY_TRIM]); + + /* ZIOs pending */ + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_SYNC_READ]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_SYNC_WRITE]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_ASYNC_READ]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_ASYNC_WRITE]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_SCRUB]); + + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE, + vsx->vsx_pend_queue[ZIO_PRIORITY_TRIM]); + + /* Histograms */ + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + vsx->vsx_total_histo[ZIO_TYPE_READ], + ARRAY_SIZE(vsx->vsx_total_histo[ZIO_TYPE_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + vsx->vsx_total_histo[ZIO_TYPE_WRITE], + ARRAY_SIZE(vsx->vsx_total_histo[ZIO_TYPE_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + vsx->vsx_disk_histo[ZIO_TYPE_READ], + ARRAY_SIZE(vsx->vsx_disk_histo[ZIO_TYPE_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + vsx->vsx_disk_histo[ZIO_TYPE_WRITE], + ARRAY_SIZE(vsx->vsx_disk_histo[ZIO_TYPE_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_READ], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_WRITE], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_READ], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_WRITE], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_SCRUB], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SCRUB])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO, + vsx->vsx_queue_histo[ZIO_PRIORITY_TRIM], + ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_TRIM])); + + /* Request sizes */ + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_READ], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_WRITE], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_READ], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_WRITE], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_SCRUB], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SCRUB])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO, + vsx->vsx_ind_histo[ZIO_PRIORITY_TRIM], + ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_TRIM])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_READ], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_WRITE], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_READ], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_READ])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_WRITE], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_WRITE])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB])); + + fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO, + vsx->vsx_agg_histo[ZIO_PRIORITY_TRIM], + ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_TRIM])); + + /* IO delays */ + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SLOW_IOS, vs->vs_slow_ios); + + /* Add extended stats nvlist to main nvlist */ + fnvlist_add_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, nvx); + + nvlist_free(nvx); + kmem_free(vs, sizeof (*vs)); + kmem_free(vsx, sizeof (*vsx)); +} + static void root_vdev_actions_getprogress(vdev_t *vd, nvlist_t *nvl) { @@ -386,11 +549,7 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats, } if (getstats) { - vdev_stat_t vs; - - vdev_get_stats(vd, &vs); - fnvlist_add_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, - (uint64_t *)&vs, sizeof (vs) / sizeof (uint64_t)); + vdev_config_generate_stats(vd, nv); root_vdev_actions_getprogress(vd, nv); diff --git a/usr/src/uts/common/fs/zfs/vdev_queue.c b/usr/src/uts/common/fs/zfs/vdev_queue.c index f430ab79c2..b40126cac0 100644 --- a/usr/src/uts/common/fs/zfs/vdev_queue.c +++ b/usr/src/uts/common/fs/zfs/vdev_queue.c @@ -839,6 +839,7 @@ vdev_queue_io_done(zio_t *zio) vdev_queue_pending_remove(vq, zio); + zio->io_delta = gethrtime() - zio->io_timestamp; vq->vq_io_complete_ts = gethrtime(); while ((nio = vdev_queue_io_to_issue(vq)) != NULL) { diff --git a/usr/src/uts/common/fs/zfs/zfs_fm.c b/usr/src/uts/common/fs/zfs/zfs_fm.c index 87846292b1..dd854c12e1 100644 --- a/usr/src/uts/common/fs/zfs/zfs_fm.c +++ b/usr/src/uts/common/fs/zfs/zfs_fm.c @@ -102,7 +102,11 @@ * ereport with information about the differences. */ #ifdef _KERNEL -static void + +/* + * Return B_TRUE if the event actually posted, B_FALSE if not. + */ +static boolean_t zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out, const char *subclass, spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb, zio_t *zio, uint64_t stateoroffset, uint64_t size) @@ -112,88 +116,15 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out, uint64_t ena; char class[64]; - /* - * If we are doing a spa_tryimport() or in recovery mode, - * ignore errors. - */ - if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT || - spa_load_state(spa) == SPA_LOAD_RECOVER) - return; - - /* - * If we are in the middle of opening a pool, and the previous attempt - * failed, don't bother logging any new ereports - we're just going to - * get the same diagnosis anyway. - */ - if (spa_load_state(spa) != SPA_LOAD_NONE && - spa->spa_last_open_failed) - return; - - if (zio != NULL) { - /* - * If this is not a read or write zio, ignore the error. This - * can occur if the DKIOCFLUSHWRITECACHE ioctl fails. - */ - if (zio->io_type != ZIO_TYPE_READ && - zio->io_type != ZIO_TYPE_WRITE) - return; - - /* - * Ignore any errors from speculative I/Os, as failure is an - * expected result. - */ - if (zio->io_flags & ZIO_FLAG_SPECULATIVE) - return; - - /* - * If this I/O is not a retry I/O, don't post an ereport. - * Otherwise, we risk making bad diagnoses based on B_FAILFAST - * I/Os. - */ - if (zio->io_error == EIO && - !(zio->io_flags & ZIO_FLAG_IO_RETRY)) - return; - - if (vd != NULL) { - /* - * If the vdev has already been marked as failing due - * to a failed probe, then ignore any subsequent I/O - * errors, as the DE will automatically fault the vdev - * on the first such failure. This also catches cases - * where vdev_remove_wanted is set and the device has - * not yet been asynchronously placed into the REMOVED - * state. - */ - if (zio->io_vd == vd && !vdev_accessible(vd, zio)) - return; - - /* - * Ignore checksum errors for reads from DTL regions of - * leaf vdevs. - */ - if (zio->io_type == ZIO_TYPE_READ && - zio->io_error == ECKSUM && - vd->vdev_ops->vdev_op_leaf && - vdev_dtl_contains(vd, DTL_MISSING, zio->io_txg, 1)) - return; - } - } - - /* - * For probe failure, we want to avoid posting ereports if we've - * already removed the device in the meantime. - */ - if (vd != NULL && - strcmp(subclass, FM_EREPORT_ZFS_PROBE_FAILURE) == 0 && - (vd->vdev_remove_wanted || vd->vdev_state == VDEV_STATE_REMOVED)) - return; + if (!zfs_ereport_is_valid(subclass, spa, vd, zio)) + return (B_FALSE); if ((ereport = fm_nvlist_create(NULL)) == NULL) - return; + return (B_FALSE); if ((detector = fm_nvlist_create(NULL)) == NULL) { fm_nvlist_destroy(ereport, FM_NVA_FREE); - return; + return (B_FALSE); } /* @@ -336,7 +267,7 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out, /* * Payload for I/Os with corresponding logical information. */ - if (zb != NULL && (zio == NULL || zio->io_logical != NULL)) + if (zb != NULL && (zio == NULL || zio->io_logical != NULL)) { fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_OBJSET, DATA_TYPE_UINT64, zb->zb_objset, @@ -346,11 +277,13 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out, DATA_TYPE_INT64, zb->zb_level, FM_EREPORT_PAYLOAD_ZFS_ZIO_BLKID, DATA_TYPE_UINT64, zb->zb_blkid, NULL); + } mutex_exit(&spa->spa_errlist_lock); *ereport_out = ereport; *detector_out = detector; + return (B_TRUE); } /* if it's <= 128 bytes, save the corruption directly */ @@ -674,26 +607,110 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info, } #endif -void +/* + * Make sure our event is still valid for the given zio/vdev/pool. For example, + * we don't want to keep logging events for a faulted or missing vdev. + */ +boolean_t +zfs_ereport_is_valid(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio) +{ +#ifdef _KERNEL + /* + * If we are doing a spa_tryimport() or in recovery mode, + * ignore errors. + */ + if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT || + spa_load_state(spa) == SPA_LOAD_RECOVER) + return (B_FALSE); + + /* + * If we are in the middle of opening a pool, and the previous attempt + * failed, don't bother logging any new ereports - we're just going to + * get the same diagnosis anyway. + */ + if (spa_load_state(spa) != SPA_LOAD_NONE && + spa->spa_last_open_failed) + return (B_FALSE); + + if (zio != NULL) { + /* + * If this is not a read or write zio, ignore the error. This + * can occur if the DKIOCFLUSHWRITECACHE ioctl fails. + */ + if (zio->io_type != ZIO_TYPE_READ && + zio->io_type != ZIO_TYPE_WRITE) + return (B_FALSE); + + if (vd != NULL) { + /* + * If the vdev has already been marked as failing due + * to a failed probe, then ignore any subsequent I/O + * errors, as the DE will automatically fault the vdev + * on the first such failure. This also catches cases + * where vdev_remove_wanted is set and the device has + * not yet been asynchronously placed into the REMOVED + * state. + */ + if (zio->io_vd == vd && !vdev_accessible(vd, zio)) + return (B_FALSE); + + /* + * Ignore checksum errors for reads from DTL regions of + * leaf vdevs. + */ + if (zio->io_type == ZIO_TYPE_READ && + zio->io_error == ECKSUM && + vd->vdev_ops->vdev_op_leaf && + vdev_dtl_contains(vd, DTL_MISSING, zio->io_txg, 1)) + return (B_FALSE); + } + } + + /* + * For probe failure, we want to avoid posting ereports if we've + * already removed the device in the meantime. + */ + if (vd != NULL && + strcmp(subclass, FM_EREPORT_ZFS_PROBE_FAILURE) == 0 && + (vd->vdev_remove_wanted || vd->vdev_state == VDEV_STATE_REMOVED)) + return (B_FALSE); + + /* Ignore bogus delay events (like from ioctls or unqueued IOs) */ + if ((strcmp(subclass, FM_EREPORT_ZFS_DELAY) == 0) && + (zio != NULL) && (!zio->io_timestamp)) { + return (B_FALSE); + } +#endif + return (B_TRUE); +} + +/* + * Return 0 if event was posted, EINVAL if there was a problem posting it or + * EBUSY if the event was rate limited. + */ +int zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, const struct zbookmark_phys *zb, zio_t *zio, uint64_t stateoroffset, uint64_t size) { + int rc = 0; #ifdef _KERNEL nvlist_t *ereport = NULL; nvlist_t *detector = NULL; - zfs_ereport_start(&ereport, &detector, subclass, spa, vd, - zb, zio, stateoroffset, size); + if (!zfs_ereport_start(&ereport, &detector, subclass, spa, vd, + zb, zio, stateoroffset, size)) + return (SET_ERROR(EINVAL)); /* couldn't post event */ if (ereport == NULL) - return; + return (SET_ERROR(EINVAL)); fm_ereport_post(ereport, EVCH_SLEEP); fm_nvlist_destroy(ereport, FM_NVA_FREE); fm_nvlist_destroy(detector, FM_NVA_FREE); #endif + return (rc); } void @@ -786,21 +803,21 @@ zfs_ereport_send_interim_checksum(zio_cksum_report_t *report) #endif } -void +int zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb, struct zio *zio, uint64_t offset, uint64_t length, const abd_t *good_data, const abd_t *bad_data, zio_bad_cksum_t *zbc) { + int rc = 0; #ifdef _KERNEL nvlist_t *ereport = NULL; nvlist_t *detector = NULL; zfs_ecksum_info_t *info; - zfs_ereport_start(&ereport, &detector, FM_EREPORT_ZFS_CHECKSUM, - spa, vd, zb, zio, offset, length); - - if (ereport == NULL) - return; + if (!zfs_ereport_start(&ereport, &detector, FM_EREPORT_ZFS_CHECKSUM, + spa, vd, zb, zio, offset, length) || (ereport == NULL)) { + return (SET_ERROR(EINVAL)); + } info = annotate_ecksum(ereport, zbc, good_data, bad_data, length, B_FALSE); @@ -814,6 +831,7 @@ zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd, const zbookmark_phys_t *zb, if (info != NULL) kmem_free(info, sizeof (*info)); #endif + return (rc); } static void diff --git a/usr/src/uts/common/fs/zfs/zio.c b/usr/src/uts/common/fs/zfs/zio.c index a932ccb544..b02363e7eb 100644 --- a/usr/src/uts/common/fs/zfs/zio.c +++ b/usr/src/uts/common/fs/zfs/zio.c @@ -45,6 +45,7 @@ #include <sys/blkptr.h> #include <sys/zfeature.h> #include <sys/zfs_zone.h> +#include <sys/time.h> #include <sys/dsl_scan.h> #include <sys/metaslab_impl.h> #include <sys/abd.h> @@ -80,6 +81,9 @@ extern vmem_t *zio_alloc_arena; #define ZIO_PIPELINE_CONTINUE 0x100 #define ZIO_PIPELINE_STOP 0x101 +/* Mark IOs as "slow" if they take longer than 30 seconds */ +int zio_slow_io_ms = (30 * MILLISEC); + #define BP_SPANB(indblkshift, level) \ (((uint64_t)1) << ((level) * ((indblkshift) - SPA_BLKPTRSHIFT))) #define COMPARE_META_LEVEL 0x80000000ul @@ -3394,6 +3398,8 @@ zio_vdev_io_start(zio_t *zio) uint64_t align; spa_t *spa = zio->io_spa; + zio->io_delay = 0; + ASSERT(zio->io_error == 0); ASSERT(zio->io_child_error[ZIO_CHILD_VDEV] == 0); @@ -3511,6 +3517,7 @@ zio_vdev_io_start(zio_t *zio) zio_interrupt(zio); return (ZIO_PIPELINE_STOP); } + zio->io_delay = gethrtime(); } vd->vdev_ops->vdev_op_io_start(zio); @@ -3531,6 +3538,9 @@ zio_vdev_io_done(zio_t *zio) ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE || zio->io_type == ZIO_TYPE_TRIM); + if (zio->io_delay) + zio->io_delay = gethrtime() - zio->io_delay; + if (vd != NULL && vd->vdev_ops->vdev_op_leaf) { vdev_queue_io_done(zio); @@ -4234,6 +4244,29 @@ zio_done(zio_t *zio) vdev_stat_update(zio, psize); + if (zio->io_delay >= MSEC2NSEC(zio_slow_io_ms)) { + if (zio->io_vd != NULL && !vdev_is_dead(zio->io_vd)) { + /* + * We want to only increment our slow IO counters if + * the IO is valid (i.e. not if the drive is removed). + * + * zfs_ereport_post() will also do these checks, but + * it can also have other failures, so we need to + * increment the slow_io counters independent of it. + */ + if (zfs_ereport_is_valid(FM_EREPORT_ZFS_DELAY, + zio->io_spa, zio->io_vd, zio)) { + mutex_enter(&zio->io_vd->vdev_stat_lock); + zio->io_vd->vdev_stat.vs_slow_ios++; + mutex_exit(&zio->io_vd->vdev_stat_lock); + + zfs_ereport_post(FM_EREPORT_ZFS_DELAY, + zio->io_spa, zio->io_vd, &zio->io_bookmark, + zio, 0, 0); + } + } + } + if (zio->io_error) { /* * If this I/O is attached to a particular vdev, diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h index ce09473f95..450b05b64c 100644 --- a/usr/src/uts/common/nfs/nfs4.h +++ b/usr/src/uts/common/nfs/nfs4.h @@ -40,7 +40,6 @@ #ifdef _KERNEL #include <nfs/nfs4_kprot.h> -#include <nfs/nfs4_drc.h> #include <sys/nvpair.h> #else #include <rpcsvc/nfs4_prot.h> @@ -807,7 +806,7 @@ typedef struct nfs4_srv { */ rfs4_dss_path_t *dss_pathlist; /* Duplicate request cache */ - rfs4_drc_t *nfs4_drc; + struct rfs4_drc *nfs4_drc; /* nfsv4 server start time */ time_t rfs4_start_time; /* Used to serialize lookups of clientids */ diff --git a/usr/src/uts/common/sys/fm/fs/zfs.h b/usr/src/uts/common/sys/fm/fs/zfs.h index c3eb950326..8e56f244cd 100644 --- a/usr/src/uts/common/sys/fm/fs/zfs.h +++ b/usr/src/uts/common/sys/fm/fs/zfs.h @@ -36,6 +36,7 @@ extern "C" { #define FM_EREPORT_ZFS_AUTHENTICATION "authentication" #define FM_EREPORT_ZFS_IO "io" #define FM_EREPORT_ZFS_DATA "data" +#define FM_EREPORT_ZFS_DELAY "delay" #define FM_EREPORT_ZFS_POOL "zpool" #define FM_EREPORT_ZFS_DEVICE_UNKNOWN "vdev.unknown" #define FM_EREPORT_ZFS_DEVICE_OPEN_FAILED "vdev.open_failed" @@ -61,6 +62,7 @@ extern "C" { #define FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU "vdev_fru" #define FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE "vdev_state" #define FM_EREPORT_PAYLOAD_ZFS_VDEV_ASHIFT "vdev_ashift" +#define FM_EREPORT_PAYLOAD_ZFS_VDEV_DELAYS "vdev_delays" #define FM_EREPORT_PAYLOAD_ZFS_PARENT_GUID "parent_guid" #define FM_EREPORT_PAYLOAD_ZFS_PARENT_TYPE "parent_type" #define FM_EREPORT_PAYLOAD_ZFS_PARENT_PATH "parent_path" diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h index 1bc421e33b..93a2b5887a 100644 --- a/usr/src/uts/common/sys/fs/zfs.h +++ b/usr/src/uts/common/sys/fs/zfs.h @@ -24,7 +24,7 @@ * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Integros [integros.com] - * Copyright 2017 Joyent, Inc. + * Copyright 2020 Joyent, Inc. * Copyright (c) 2017 Datto Inc. * Copyright (c) 2017, Intel Corporation. */ @@ -35,6 +35,15 @@ #define _SYS_FS_ZFS_H #include <sys/time.h> +/* + * In OpenZFS we include sys/zio_priority.h to get the enum value of + * ZIO_PRIORITY_NUM_QUEUEABLE, which is used for the various array sizes in + * the structure definitions below. However, in illumos zio_priority.h is not + * readily available to the userland code where we have a very large number of + * files including sys/zfs.h. Thus, we define ZIO_PRIORITY_N_QUEUEABLE here and + * this should be kept in sync if ZIO_PRIORITY_NUM_QUEUEABLE changes. + */ +#define ZIO_PRIORITY_N_QUEUEABLE 8 #ifdef __cplusplus extern "C" { @@ -601,6 +610,55 @@ typedef struct zpool_load_policy { #define ZPOOL_CONFIG_CHECKPOINT_STATS "checkpoint_stats" /* not on disk */ #define ZPOOL_CONFIG_VDEV_STATS "vdev_stats" /* not stored on disk */ #define ZPOOL_CONFIG_INDIRECT_SIZE "indirect_size" /* not stored on disk */ + +/* container nvlist of extended stats */ +#define ZPOOL_CONFIG_VDEV_STATS_EX "vdev_stats_ex" + +/* Active queue read/write stats */ +#define ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE "vdev_sync_r_active_queue" +#define ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE "vdev_sync_w_active_queue" +#define ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE "vdev_async_r_active_queue" +#define ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE "vdev_async_w_active_queue" +#define ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE "vdev_async_scrub_active_queue" +#define ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE "vdev_async_trim_active_queue" + +/* Queue sizes */ +#define ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE "vdev_sync_r_pend_queue" +#define ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE "vdev_sync_w_pend_queue" +#define ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE "vdev_async_r_pend_queue" +#define ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE "vdev_async_w_pend_queue" +#define ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE "vdev_async_scrub_pend_queue" +#define ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE "vdev_async_trim_pend_queue" + +/* Latency read/write histogram stats */ +#define ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO "vdev_tot_r_lat_histo" +#define ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO "vdev_tot_w_lat_histo" +#define ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO "vdev_disk_r_lat_histo" +#define ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO "vdev_disk_w_lat_histo" +#define ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO "vdev_sync_r_lat_histo" +#define ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO "vdev_sync_w_lat_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO "vdev_async_r_lat_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO "vdev_async_w_lat_histo" +#define ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO "vdev_scrub_histo" +#define ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO "vdev_trim_histo" + +/* Request size histograms */ +#define ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO "vdev_sync_ind_r_histo" +#define ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO "vdev_sync_ind_w_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO "vdev_async_ind_r_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO "vdev_async_ind_w_histo" +#define ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO "vdev_ind_scrub_histo" +#define ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO "vdev_ind_trim_histo" +#define ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO "vdev_sync_agg_r_histo" +#define ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO "vdev_sync_agg_w_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO "vdev_async_agg_r_histo" +#define ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO "vdev_async_agg_w_histo" +#define ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO "vdev_agg_scrub_histo" +#define ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO "vdev_agg_trim_histo" + +/* Number of slow IOs */ +#define ZPOOL_CONFIG_VDEV_SLOW_IOS "vdev_slow_ios" + #define ZPOOL_CONFIG_WHOLE_DISK "whole_disk" #define ZPOOL_CONFIG_ERRCOUNT "error_count" #define ZPOOL_CONFIG_NOT_PRESENT "not_present" @@ -1001,6 +1059,7 @@ typedef struct vdev_stat { uint64_t vs_initialize_action_time; /* time_t */ uint64_t vs_checkpoint_space; /* checkpoint-consumed space */ uint64_t vs_resilver_deferred; /* resilver deferred */ + uint64_t vs_slow_ios; /* slow IOs */ uint64_t vs_trim_errors; /* trimming errors */ uint64_t vs_trim_notsup; /* supported by device */ uint64_t vs_trim_bytes_done; /* bytes trimmed */ @@ -1010,6 +1069,58 @@ typedef struct vdev_stat { } vdev_stat_t; /* + * Extended stats + * + * These are stats which aren't included in the original iostat output. For + * convenience, they are grouped together in vdev_stat_ex, although each stat + * is individually exported as a nvlist. + */ +typedef struct vdev_stat_ex { + /* Number of ZIOs issued to disk and waiting to finish */ + uint64_t vsx_active_queue[ZIO_PRIORITY_N_QUEUEABLE]; + + /* Number of ZIOs pending to be issued to disk */ + uint64_t vsx_pend_queue[ZIO_PRIORITY_N_QUEUEABLE]; + + /* + * Below are the histograms for various latencies. Buckets are in + * units of nanoseconds. + */ + + /* + * 2^37 nanoseconds = 134s. Timeouts will probably start kicking in + * before this. + */ +#define VDEV_L_HISTO_BUCKETS 37 /* Latency histo buckets */ +#define VDEV_RQ_HISTO_BUCKETS 25 /* Request size histo buckets */ + + /* Amount of time in ZIO queue (ns) */ + uint64_t vsx_queue_histo[ZIO_PRIORITY_N_QUEUEABLE] + [VDEV_L_HISTO_BUCKETS]; + + /* Total ZIO latency (ns). Includes queuing and disk access time */ + uint64_t vsx_total_histo[ZIO_TYPES][VDEV_L_HISTO_BUCKETS]; + + /* Amount of time to read/write the disk (ns) */ + uint64_t vsx_disk_histo[ZIO_TYPES][VDEV_L_HISTO_BUCKETS]; + + /* "lookup the bucket for a value" macro */ +#define HISTO(val, buckets) (val != 0 ? MIN(highbit64(val) - 1, \ + buckets - 1) : 0) +#define L_HISTO(a) HISTO(a, VDEV_L_HISTO_BUCKETS) +#define RQ_HISTO(a) HISTO(a, VDEV_RQ_HISTO_BUCKETS) + + /* Physical IO histogram */ + uint64_t vsx_ind_histo[ZIO_PRIORITY_N_QUEUEABLE] + [VDEV_RQ_HISTO_BUCKETS]; + + /* Delegated (aggregated) physical IO histogram */ + uint64_t vsx_agg_histo[ZIO_PRIORITY_N_QUEUEABLE] + [VDEV_RQ_HISTO_BUCKETS]; + +} vdev_stat_ex_t; + +/* * DDT statistics. Note: all fields should be 64-bit because this * is passed between kernel and userland as an nvlist uint64 array. */ |