Print this page
NEX-6088 ZFS scrub/resilver take excessively long due to issuing lots of random IO
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5284 need to document and update default for import -t option
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
NEX-5795 Rename 'wrc' as 'wbc' in the source and in the tech docs
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5745 WBC: Sometimes disabled instance never finish migration
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-5750 Time values for aggregated NFS server kstats should be normalized
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-5562 Trim timestamps incorrectly shown in UTC instead of local time
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-5064 On-demand trim should store operation start and stop time (lint fix)
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-5064 On-demand trim should store operation start and stop time
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5163 backport illumos 6027 EOL zulu (XVR-4000)
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
6027 EOL zulu (XVR-4000)
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Peter Tribble <peter.tribble@gmail.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@omniti.com>
NEX-5162 backport illumos 6507 i386 makecontext(3c) needs to 16-byte align the stack
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
6507 i386 makecontext(3c) needs to 16-byte align the stack
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
NEX-5207 attempt to activate spare cores fmd
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-4934 Add capability to remove special vdev
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-4776 zpool(1M) coredumps on status when trimming a pool with log devices
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
6328 Fix cstyle errors in zfs codebase (fix studio)
6328 Fix cstyle errors in zfs codebase
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Jorgen Lundman <lundman@lundman.net>
Approved by: Robert Mustacchi <rm@joyent.com>
6047 SPARC boot should support feature@embedded_data
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
Approved by: Dan McDonald <danmcd@omniti.com>
5959 clean up per-dataset feature count code
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
5669 altroot not set in zpool create when specified with -o
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>
5767 fix several problems with zfs test suite
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Approved by: Gordon Ross <gwr@nexenta.com>
NEX-4476 WRC: Allow to use write back cache per tree of datasets
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
NEX-4336 zpool vdev-get with an unsuported prop name core dumps
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3984 On-demand TRIM
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Conflicts:
        usr/src/common/zfs/zpool_prop.c
        usr/src/uts/common/sys/fs/zfs.h
NEX-3558 KRRP Integration
NEX-3165 need some dedup improvements
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
OS-195 itadm needs an easily parsable output mode
OS-207 SUP-817 causes lint warnings in zpool_main.c
Reviewed by: Alek Pinchuk <alek.pinchuk@nexena.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Albert Lee <albert.lee@nexenta.com>
OS-199 keep your tree clean (lint zpool_main.c)
SUP-817 Removed references to special device from man and help
Revert "SUP-817 Removed references to special device"
This reverts commit f8970e28f0d8bd6b69711722f341e3e1d0e1babf.
SUP-817 Removed references to special device
OS-132 zpool(1m) in scripting mode returns wrong exit code if no pools available
OS-103 handle CoS descriptor persistent references across vdev operations
OS-102 add man page info and tests for vdev/CoS properties and ZFS meta features
SUP-647 Long failover times dominated by zpool import times trigger client-side errors
Fix up some merges where we wanted the upstream version.
Make special vdev subtree topology the same as regular vdev subtree to simplify testcase setup
Fixup merge issues
Issue #26: partial scrub
Added partial scrub options:
-M for MOS only scrub
-m for metadata scrub
Issue #9: Support for persistent CoS/vdev attributes with feature flags
          Support for feature flags for special tier
          Contributors: Daniil Lunev, Boris Protopopov
Fixup merge results
re 13748 added zpool export -c option
zpool export -c command exports specified pool while keeping its latest
configuration in the cache file for subsequent zpool import -c.
re #13594 rb4488 Lint complaints fix
re #10054 #13409 rb4387 added parallel unmount for zpool export
re #8279 rb3915 need a mechanism to notify NMS about ZFS config changes (fix lint -courtesy of Yuri Pankov)
re #12584 rb4049 zfsxx latest code merge (fix lint - courtesy of Yuri Pankov)
re #12585 rb4049 ZFS++ work port - refactoring to improve separation of open/closed code, bug fixes, performance improvements - open code
re #8279 rb3915 need a mechanism to notify NMS about ZFS config changes (Opened code)
re #8346 rb2639 KT disk failures
ZFS plus work: special vdevs, cos, cos/vdev properties (fix lint)
Bug 11205: add missing libzfs_closed_stubs.c to fix opensource-only build.
ZFS plus work: special vdevs, cos, cos/vdev properties
re #6853 rb1787 remove references to sun.com

*** 19,30 **** * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright (c) 2011, 2018 by Delphix. All rights reserved. * Copyright (c) 2012 by Frederik Wessels. All rights reserved. * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. * Copyright 2016 Nexenta Systems, Inc. * Copyright (c) 2017 Datto Inc. */ --- 19,31 ---- * CDDL HEADER END */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright (c) 2012 by Frederik Wessels. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. * Copyright 2016 Nexenta Systems, Inc. * Copyright (c) 2017 Datto Inc. */
*** 56,65 **** --- 57,70 ---- #include "zfs_comutil.h" #include "zfeature_common.h" #include "statcommon.h" + #ifndef MAX + #define MAX(x, y) ((x) > (y) ? (x) : (y)) + #endif /* MAX */ + static int zpool_do_create(int, char **); static int zpool_do_destroy(int, char **); static int zpool_do_add(int, char **); static int zpool_do_remove(int, char **);
*** 80,89 **** --- 85,95 ---- static int zpool_do_detach(int, char **); static int zpool_do_replace(int, char **); static int zpool_do_split(int, char **); static int zpool_do_scrub(int, char **); + static int zpool_do_trim(int, char **); static int zpool_do_import(int, char **); static int zpool_do_export(int, char **); static int zpool_do_upgrade(int, char **);
*** 91,100 **** --- 97,117 ---- static int zpool_do_history(int, char **); static int zpool_do_get(int, char **); static int zpool_do_set(int, char **); + static int zpool_do_vdev_get(int, char **); + static int zpool_do_vdev_set(int, char **); + + static int zpool_do_cos_alloc(int, char **); + static int zpool_do_cos_free(int, char **); + static int zpool_do_cos_list(int, char **); + static int zpool_do_cos_get(int, char **); + static int zpool_do_cos_set(int, char **); + + static boolean_t nexenta_meta_enable(); + /* * These libumem hooks provide a reasonable set of defaults for the allocator's * debugging facilities. */
*** 128,144 **** HELP_OFFLINE, HELP_ONLINE, HELP_REPLACE, HELP_REMOVE, HELP_SCRUB, HELP_STATUS, HELP_UPGRADE, HELP_GET, HELP_SET, HELP_SPLIT, HELP_REGUID, ! HELP_REOPEN } zpool_help_t; typedef struct zpool_command { const char *name; --- 145,169 ---- HELP_OFFLINE, HELP_ONLINE, HELP_REPLACE, HELP_REMOVE, HELP_SCRUB, + HELP_TRIM, HELP_STATUS, HELP_UPGRADE, HELP_GET, HELP_SET, HELP_SPLIT, HELP_REGUID, ! HELP_REOPEN, ! HELP_VDEV_GET, ! HELP_VDEV_SET, ! HELP_COS_ALLOC, ! HELP_COS_FREE, ! HELP_COS_LIST, ! HELP_COS_GET, ! HELP_COS_SET } zpool_help_t; typedef struct zpool_command { const char *name;
*** 178,195 **** --- 203,229 ---- { "replace", zpool_do_replace, HELP_REPLACE }, { "split", zpool_do_split, HELP_SPLIT }, { NULL }, { "scrub", zpool_do_scrub, HELP_SCRUB }, { NULL }, + { "trim", zpool_do_trim, HELP_TRIM }, + { NULL }, { "import", zpool_do_import, HELP_IMPORT }, { "export", zpool_do_export, HELP_EXPORT }, { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, { "reguid", zpool_do_reguid, HELP_REGUID }, { NULL }, { "history", zpool_do_history, HELP_HISTORY }, { "get", zpool_do_get, HELP_GET }, { "set", zpool_do_set, HELP_SET }, + { "vdev-get", zpool_do_vdev_get, HELP_VDEV_GET }, + { "vdev-set", zpool_do_vdev_set, HELP_VDEV_SET }, + { "cos-alloc", zpool_do_cos_alloc, HELP_COS_ALLOC }, + { "cos-free", zpool_do_cos_free, HELP_COS_FREE }, + { "cos-list", zpool_do_cos_list, HELP_COS_LIST }, + { "cos-get", zpool_do_cos_get, HELP_COS_GET }, + { "cos-set", zpool_do_cos_set, HELP_COS_SET } }; #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) static zpool_command_t *current_command;
*** 220,234 **** case HELP_EXPORT: return (gettext("\texport [-f] <pool> ...\n")); case HELP_HISTORY: return (gettext("\thistory [-il] [<pool>] ...\n")); case HELP_IMPORT: ! return (gettext("\timport [-d dir] [-D]\n" "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" "\timport [-o mntopts] [-o property=value] ... \n" "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " ! "[-R root] [-F [-n]] -a\n" "\timport [-o mntopts] [-o property=value] ... \n" "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " "[-R root] [-F [-n]]\n" "\t <pool | id> [newpool]\n")); case HELP_IOSTAT: --- 254,268 ---- case HELP_EXPORT: return (gettext("\texport [-f] <pool> ...\n")); case HELP_HISTORY: return (gettext("\thistory [-il] [<pool>] ...\n")); case HELP_IMPORT: ! return (gettext("\timport [-d dir] [-D] [-t num]\n" "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" "\timport [-o mntopts] [-o property=value] ... \n" "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " ! "[-R root] [-F [-n]] [-t num] -a\n" "\timport [-o mntopts] [-o property=value] ... \n" "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " "[-R root] [-F [-n]]\n" "\t <pool | id> [newpool]\n")); case HELP_IOSTAT:
*** 245,259 **** return (gettext("\tonline <pool> <device> ...\n")); case HELP_REPLACE: return (gettext("\treplace [-f] <pool> <device> " "[new-device]\n")); case HELP_REMOVE: ! return (gettext("\tremove [-nps] <pool> <device> ...\n")); case HELP_REOPEN: return (gettext("\treopen <pool>\n")); case HELP_SCRUB: ! return (gettext("\tscrub [-s | -p] <pool> ...\n")); case HELP_STATUS: return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " "[count]]\n")); case HELP_UPGRADE: return (gettext("\tupgrade\n" --- 279,295 ---- return (gettext("\tonline <pool> <device> ...\n")); case HELP_REPLACE: return (gettext("\treplace [-f] <pool> <device> " "[new-device]\n")); case HELP_REMOVE: ! return (gettext("\tremove <pool> <device> ...\n")); case HELP_REOPEN: return (gettext("\treopen <pool>\n")); case HELP_SCRUB: ! return (gettext("\tscrub [-m|-M|-p|-s] <pool> ...\n")); ! case HELP_TRIM: ! return (gettext("\ttrim [-s|-r <rate>] <pool> ...\n")); case HELP_STATUS: return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " "[count]]\n")); case HELP_UPGRADE: return (gettext("\tupgrade\n"
*** 268,284 **** return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" "\t [-o property=value] <pool> <newpool> " "[<device> ...]\n")); case HELP_REGUID: return (gettext("\treguid <pool>\n")); } abort(); /* NOTREACHED */ } - /* * Callback routine that will print out a pool property value. */ static int print_prop_cb(int prop, void *cb) --- 304,351 ---- return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" "\t [-o property=value] <pool> <newpool> " "[<device> ...]\n")); case HELP_REGUID: return (gettext("\treguid <pool>\n")); + case HELP_VDEV_GET: + return (gettext("\tvdev-get <property | all> <pool> " + "<vdev name | GUID>\n")); + case HELP_VDEV_SET: + return (gettext("\tvdev-set <property=value> <pool> " + "<vdev name | GUID>\n")); + case HELP_COS_ALLOC: + return (gettext("\tcos-alloc <pool> <cos name | GUID>\n")); + case HELP_COS_FREE: + return (gettext("\tcos-free [-f] <pool> <cos name | GUID>\n")); + case HELP_COS_LIST: + return (gettext("\tcos-list <pool>\n")); + case HELP_COS_GET: + return (gettext("\tcos-get <property | all> <pool>" + "<cos name | GUID>\n")); + case HELP_COS_SET: + return (gettext("\tcos-set <property=value> <pool>" + "<cos name | GUID>\n")); } abort(); /* NOTREACHED */ } + /* + * Check if additional ZFS meta features are enabled. + */ + static boolean_t + nexenta_meta_enable() + { + if (getenv("nexenta_meta_enable") == NULL) { + (void) fprintf(stderr, gettext("feature not enabled\n")); + (void) fprintf(stderr, + gettext("set nexenta_meta_enable to access\n")); + return (B_FALSE); + } + return (B_TRUE); + } /* * Callback routine that will print out a pool property value. */ static int print_prop_cb(int prop, void *cb)
*** 409,419 **** */ static int add_prop_list(const char *propname, char *propval, nvlist_t **props, boolean_t poolprop) { ! zpool_prop_t prop = ZPOOL_PROP_INVAL; zfs_prop_t fprop; nvlist_t *proplist; const char *normnm; char *strval; --- 476,486 ---- */ static int add_prop_list(const char *propname, char *propval, nvlist_t **props, boolean_t poolprop) { ! zpool_prop_t prop = ZPROP_INVAL; zfs_prop_t fprop; nvlist_t *proplist; const char *normnm; char *strval;
*** 427,437 **** proplist = *props; if (poolprop) { const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); ! if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL && !zpool_prop_feature(propname)) { (void) fprintf(stderr, gettext("property '%s' is " "not a valid pool property\n"), propname); return (2); } --- 494,504 ---- proplist = *props; if (poolprop) { const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); ! if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && !zpool_prop_feature(propname)) { (void) fprintf(stderr, gettext("property '%s' is " "not a valid pool property\n"), propname); return (2); }
*** 438,448 **** /* * feature@ properties and version should not be specified * at the same time. */ ! if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) && nvlist_exists(proplist, vname)) || (prop == ZPOOL_PROP_VERSION && prop_list_contains_feature(proplist))) { (void) fprintf(stderr, gettext("'feature@' and " "'version' properties cannot be specified " --- 505,515 ---- /* * feature@ properties and version should not be specified * at the same time. */ ! if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && nvlist_exists(proplist, vname)) || (prop == ZPOOL_PROP_VERSION && prop_list_contains_feature(proplist))) { (void) fprintf(stderr, gettext("'feature@' and " "'version' properties cannot be specified "
*** 478,487 **** --- 545,620 ---- return (0); } /* + * Add a property pair (name, string-value) into a vdev property nvlist. + */ + static int + add_vdev_prop_list(const char *propname, char *propval, nvlist_t **props) + { + vdev_prop_t prop = ZPROP_INVAL; + nvlist_t *proplist; + const char *normnm; + + if (*props == NULL && nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, + gettext("internal error: out of memory\n")); + return (1); + } + + proplist = *props; + if ((prop = vdev_name_to_prop(propname)) == ZPROP_INVAL) { + (void) fprintf(stderr, gettext("property '%s' is " + "not a valid vdev property\n"), propname); + return (2); + } + normnm = vdev_prop_to_name(prop); + + if (nvlist_add_string(proplist, normnm, propval) != 0) { + (void) fprintf(stderr, gettext("internal " + "error: out of memory\n")); + return (1); + } + + return (0); + } + + /* + * Add a property pair (name, string-value) into a cos property nvlist. + */ + static int + add_cos_prop_list(const char *propname, char *propval, nvlist_t **props) + { + cos_prop_t prop = ZPROP_INVAL; + nvlist_t *proplist; + const char *normnm; + + if (*props == NULL && nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, + gettext("internal error: out of memory\n")); + return (1); + } + + proplist = *props; + if ((prop = cos_name_to_prop(propname)) == ZPROP_INVAL) { + (void) fprintf(stderr, gettext("property '%s' is " + "not a valid cos property\n"), propname); + return (2); + } + normnm = cos_prop_to_name(prop); + + if (nvlist_add_string(proplist, normnm, propval) != 0) { + (void) fprintf(stderr, gettext("internal " + "error: out of memory\n")); + return (1); + } + + return (0); + } + + /* * zpool add [-fn] <pool> <vdev> ... * * -f Force addition of devices, even if they appear in use * -n Do not add the devices, but display the resulting layout if * they were to be added.
*** 595,694 **** } /* * zpool remove <pool> <vdev> ... * ! * Removes the given vdev from the pool. */ int zpool_do_remove(int argc, char **argv) { char *poolname; int i, ret = 0; zpool_handle_t *zhp; - boolean_t stop = B_FALSE; - boolean_t noop = B_FALSE; - boolean_t parsable = B_FALSE; - char c; ! /* check options */ ! while ((c = getopt(argc, argv, "nps")) != -1) { ! switch (c) { ! case 'n': ! noop = B_TRUE; ! break; ! case 'p': ! parsable = B_TRUE; ! break; ! case 's': ! stop = B_TRUE; ! break; ! case '?': ! (void) fprintf(stderr, gettext("invalid option '%c'\n"), ! optopt); ! usage(B_FALSE); ! } ! } - argc -= optind; - argv += optind; - /* get pool name and check number of arguments */ if (argc < 1) { (void) fprintf(stderr, gettext("missing pool name argument\n")); usage(B_FALSE); } poolname = argv[0]; if ((zhp = zpool_open(g_zfs, poolname)) == NULL) return (1); - if (stop && noop) { - (void) fprintf(stderr, gettext("stop request ignored\n")); - return (0); - } - - if (stop) { - if (argc > 1) { - (void) fprintf(stderr, gettext("too many arguments\n")); - usage(B_FALSE); - } - if (zpool_vdev_remove_cancel(zhp) != 0) - ret = 1; - } else { - if (argc < 2) { - (void) fprintf(stderr, gettext("missing device\n")); - usage(B_FALSE); - } - for (i = 1; i < argc; i++) { - if (noop) { - uint64_t size; - - if (zpool_vdev_indirect_size(zhp, argv[i], - &size) != 0) { - ret = 1; - break; - } - if (parsable) { - (void) printf("%s %llu\n", - argv[i], size); - } else { - char valstr[32]; - zfs_nicenum(size, valstr, - sizeof (valstr)); - (void) printf("Memory that will be " - "used after removing %s: %s\n", - argv[i], valstr); - } - } else { if (zpool_vdev_remove(zhp, argv[i]) != 0) ret = 1; } - } - } return (ret); } /* --- 728,769 ---- } /* * zpool remove <pool> <vdev> ... * ! * Removes the given vdev from the pool. Currently, this supports removing ! * spares, cache, and log devices from the pool. */ int zpool_do_remove(int argc, char **argv) { char *poolname; int i, ret = 0; zpool_handle_t *zhp; ! argc--; ! argv++; /* get pool name and check number of arguments */ if (argc < 1) { (void) fprintf(stderr, gettext("missing pool name argument\n")); usage(B_FALSE); } + if (argc < 2) { + (void) fprintf(stderr, gettext("missing device\n")); + usage(B_FALSE); + } poolname = argv[0]; if ((zhp = zpool_open(g_zfs, poolname)) == NULL) return (1); for (i = 1; i < argc; i++) { if (zpool_vdev_remove(zhp, argv[i]) != 0) ret = 1; } return (ret); } /*
*** 1262,1271 **** --- 1337,1366 ---- (void) fprintf(stderr, gettext("use 'zfs destroy' to " "destroy a dataset\n")); return (1); } + ret = zfs_check_krrp(g_zfs, argv[0]); + /* + * ENOTSUP means that autosnaper doesn't handle this pool. + */ + if (ret != ENOTSUP) { + if (ret == ECHILD || ret == EBUSY || ret == EUSERS) + ret = EBUSY; + + if (ret) { + (void) zpool_standard_error(g_zfs, + ret, gettext("cannnot destroy pool because " + "of krrp")); + zpool_close(zhp); + ret = 1; + return (ret); + } + } else { + ret = 0; + } + if (zpool_disable_datasets(zhp, force) != 0) { (void) fprintf(stderr, gettext("could not destroy '%s': " "could not unmount datasets\n"), zpool_get_name(zhp)); return (1); }
*** 1292,1319 **** int zpool_do_export(int argc, char **argv) { boolean_t force = B_FALSE; boolean_t hardforce = B_FALSE; int c; zpool_handle_t *zhp; int ret; int i; /* check options */ ! while ((c = getopt(argc, argv, "fF")) != -1) { switch (c) { case 'f': force = B_TRUE; break; case 'F': hardforce = B_TRUE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); usage(B_FALSE); } } argc -= optind; argv += optind; --- 1387,1428 ---- int zpool_do_export(int argc, char **argv) { boolean_t force = B_FALSE; boolean_t hardforce = B_FALSE; + boolean_t saveconfig = B_FALSE; int c; + int n_threads = sysconf(_SC_NPROCESSORS_ONLN) * 2; zpool_handle_t *zhp; int ret; int i; /* check options */ ! while ((c = getopt(argc, argv, ":fFct:")) != -1) { switch (c) { case 'f': force = B_TRUE; break; case 'F': hardforce = B_TRUE; break; + case 'c': + saveconfig = B_TRUE; + break; + case 't': + n_threads = atoi(optarg); + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); usage(B_FALSE); + break; + case ':': + (void) fprintf(stderr, gettext("missing argument " + "for option '%c'\n"), optopt); + usage(B_FALSE); + break; } } argc -= optind; argv += optind;
*** 1329,1351 **** if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { ret = 1; continue; } ! if (zpool_disable_datasets(zhp, force) != 0) { ret = 1; zpool_close(zhp); continue; } /* The history must be logged as part of the export */ log_history = B_FALSE; if (hardforce) { ! if (zpool_export_force(zhp, history_str) != 0) ret = 1; ! } else if (zpool_export(zhp, force, history_str) != 0) { ret = 1; } zpool_close(zhp); } --- 1438,1482 ---- if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { ret = 1; continue; } ! ret = zfs_check_krrp(g_zfs, argv[0]); ! /* ! * ENOTSUP means that autosnaper doesn't handle this pool. ! */ ! if (ret != ENOTSUP) { ! if (ret == ECHILD || ret == EBUSY || ret == EUSERS) ! ret = EBUSY; ! ! if (ret) { ! (void) zpool_standard_error(g_zfs, ! ret, gettext("cannnot export pool because " ! "of krrp")); ! zpool_close(zhp); ret = 1; + continue; + } + } else { + ret = 0; + } + + if (zpool_disable_datasets_ex(zhp, force, n_threads) != 0) { + ret = 1; zpool_close(zhp); continue; } /* The history must be logged as part of the export */ log_history = B_FALSE; if (hardforce) { ! if (zpool_export_force(zhp, saveconfig, history_str) ! != 0) ret = 1; ! } else if (zpool_export(zhp, force, saveconfig, history_str) ! != 0) { ret = 1; } zpool_close(zhp); }
*** 1457,1480 **** char rbuf[6], wbuf[6], cbuf[6]; char *vname; uint64_t notpresent; spare_cbdata_t cb; const char *state; - char *type; if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) children = 0; verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c) == 0); - verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); - - if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) - return; - state = zpool_state_to_name(vs->vs_state, vs->vs_aux); if (isspare) { /* * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for * online drives. --- 1588,1605 ----
*** 1560,1600 **** case VDEV_AUX_SPLIT_POOL: (void) printf(gettext("split into new pool")); break; - case VDEV_AUX_CHILDREN_OFFLINE: - (void) printf(gettext("all children offline")); - break; - default: (void) printf(gettext("corrupted data")); break; } } (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); ! if (ps && ps->pss_state == DSS_SCANNING && ! vs->vs_scan_processed != 0 && children == 0) { (void) printf(gettext(" (%s)"), (ps->pss_func == POOL_SCAN_RESILVER) ? "resilvering" : "repairing"); } (void) printf("\n"); for (c = 0; c < children; c++) { ! uint64_t islog = B_FALSE, ishole = B_FALSE; /* Don't print logs or holes here */ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, &islog); (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, &ishole); ! if (islog || ishole) continue; vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); print_status_config(zhp, vname, child[c], namewidth, depth + 2, isspare); free(vname); --- 1685,1724 ---- case VDEV_AUX_SPLIT_POOL: (void) printf(gettext("split into new pool")); break; default: (void) printf(gettext("corrupted data")); break; } } (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); ! if (ps != NULL && (ps->pss_state == DSS_SCANNING || ! ps->pss_state == DSS_FINISHING) && vs->vs_scan_processed != 0 && ! children == 0) { (void) printf(gettext(" (%s)"), (ps->pss_func == POOL_SCAN_RESILVER) ? "resilvering" : "repairing"); } (void) printf("\n"); for (c = 0; c < children; c++) { ! uint64_t islog = B_FALSE, ishole = B_FALSE, isspecial = B_FALSE; /* Don't print logs or holes here */ (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, &islog); (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, &ishole); ! (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL, ! &isspecial); ! if (islog || ishole || isspecial) continue; vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); print_status_config(zhp, vname, child[c], namewidth, depth + 2, isspare); free(vname);
*** 1651,1664 **** case VDEV_AUX_ERR_EXCEEDED: (void) printf(gettext("too many errors")); break; - case VDEV_AUX_CHILDREN_OFFLINE: - (void) printf(gettext("all children offline")); - break; - default: (void) printf(gettext("corrupted data")); break; } } --- 1775,1784 ----
*** 1667,1681 **** if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) return; for (c = 0; c < children; c++) { ! uint64_t is_log = B_FALSE; (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, &is_log); ! if (is_log) continue; vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); print_import_config(vname, child[c], namewidth, depth + 2); free(vname); --- 1787,1803 ---- if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) return; for (c = 0; c < children; c++) { ! uint64_t is_log = B_FALSE, is_special = B_FALSE; (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, &is_log); ! (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL, ! &is_special); ! if (is_log || is_special) continue; vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); print_import_config(vname, child[c], namewidth, depth + 2); free(vname);
*** 1739,1748 **** --- 1861,1909 ---- free(name); } } /* + * Print special vdevs. + * Special vdevs are recorded as top level vdevs in the main pool child array + * but with "is_special" set to 1. We use either print_status_config() or + * print_import_config() to print the top level logs then any log + * children (eg mirrored slogs) are printed recursively - which + * works because only the top level vdev is marked "is_special" + */ + static void + print_special(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, + boolean_t verbose) + { + uint_t c, children; + nvlist_t **child; + + if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, + &children) != 0) + return; + + (void) printf(gettext("\tspecial\n")); + + for (c = 0; c < children; c++) { + uint64_t is_special = B_FALSE; + char *name; + + (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL, + &is_special); + if (!is_special) + continue; + name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); + if (verbose) + print_status_config(zhp, name, child[c], namewidth, + 2, B_FALSE); + else + print_import_config(name, child[c], namewidth, 2); + free(name); + } + } + + /* * Display the status for the given pool. */ static void show_import(nvlist_t *config) {
*** 1953,1962 **** --- 2114,2126 ---- namewidth = max_width(NULL, nvroot, 0, 0); if (namewidth < 10) namewidth = 10; print_import_config(name, nvroot, namewidth, 0); + if (num_special(nvroot) > 0) + print_special(NULL, nvroot, namewidth, B_FALSE); + if (num_logs(nvroot) > 0) print_logs(NULL, nvroot, namewidth, B_FALSE); if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { (void) printf(gettext("\n\tAdditional devices are known to "
*** 1970,1980 **** * lifting off to zpool_import_props(), and then mounts the datasets contained * within the pool. */ static int do_import(nvlist_t *config, const char *newname, const char *mntopts, ! nvlist_t *props, int flags) { zpool_handle_t *zhp; char *name; uint64_t state; uint64_t version; --- 2134,2144 ---- * lifting off to zpool_import_props(), and then mounts the datasets contained * within the pool. */ static int do_import(nvlist_t *config, const char *newname, const char *mntopts, ! nvlist_t *props, int flags, int n_threads) { zpool_handle_t *zhp; char *name; uint64_t state; uint64_t version;
*** 2034,2044 **** if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) return (1); if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && !(flags & ZFS_IMPORT_ONLY) && ! zpool_enable_datasets(zhp, mntopts, 0) != 0) { zpool_close(zhp); return (1); } zpool_close(zhp); --- 2198,2208 ---- if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) return (1); if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && !(flags & ZFS_IMPORT_ONLY) && ! zpool_enable_datasets_ex(zhp, mntopts, 0, n_threads) != 0) { zpool_close(zhp); return (1); } zpool_close(zhp);
*** 2045,2057 **** return (0); } /* * zpool import [-d dir] [-D] ! * import [-o mntopts] [-o prop=value] ... [-R root] [-D] * [-d dir | -c cachefile] [-f] -a ! * import [-o mntopts] [-o prop=value] ... [-R root] [-D] * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] * * -c Read pool information from a cachefile instead of searching * devices. * --- 2209,2221 ---- return (0); } /* * zpool import [-d dir] [-D] ! * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-t num] * [-d dir | -c cachefile] [-f] -a ! * import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-t num] * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] * * -c Read pool information from a cachefile instead of searching * devices. *
*** 2077,2086 **** --- 2241,2252 ---- * * -n See if rewind would work, but don't actually rewind. * * -N Import the pool but don't mount datasets. * + * -t Use up to num threads to mount datasets in parallel. + * * -T Specify a starting txg to use for import. This option is * intentionally undocumented option for testing purposes. * * -a Import all pools found. *
*** 2115,2128 **** boolean_t do_rewind = B_FALSE; boolean_t xtreme_rewind = B_FALSE; uint64_t pool_state, txg = -1ULL; char *cachefile = NULL; importargs_t idata = { 0 }; char *endptr; /* check options */ ! while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) { switch (c) { case 'a': do_all = B_TRUE; break; case 'c': --- 2281,2295 ---- boolean_t do_rewind = B_FALSE; boolean_t xtreme_rewind = B_FALSE; uint64_t pool_state, txg = -1ULL; char *cachefile = NULL; importargs_t idata = { 0 }; + unsigned long n_threads = sysconf(_SC_NPROCESSORS_ONLN) * 2; char *endptr; /* check options */ ! while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:t:T:VX")) != -1) { switch (c) { case 'a': do_all = B_TRUE; break; case 'c':
*** 2180,2189 **** --- 2347,2365 ---- break; if (add_prop_list(zpool_prop_to_name( ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) goto error; break; + case 't': + errno = 0; + n_threads = strtol(optarg, &endptr, 10); + if (errno != 0 || *endptr != '\0') { + (void) fprintf(stderr, + gettext("invalid num value\n")); + usage(B_FALSE); + } + break; case 'T': errno = 0; txg = strtoull(optarg, &endptr, 0); if (errno != 0 || *endptr != '\0') { (void) fprintf(stderr,
*** 2302,2312 **** idata.path = searchdirs; idata.paths = nsearch; idata.poolname = searchname; idata.guid = searchguid; idata.cachefile = cachefile; - idata.policy = policy; pools = zpool_search_import(g_zfs, &idata); if (pools != NULL && idata.exists && (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { --- 2478,2487 ----
*** 2367,2377 **** else if (!do_all) (void) printf("\n"); if (do_all) { err |= do_import(config, NULL, mntopts, ! props, flags); } else { show_import(config); } } else if (searchname != NULL) { char *name; --- 2542,2552 ---- else if (!do_all) (void) printf("\n"); if (do_all) { err |= do_import(config, NULL, mntopts, ! props, flags, n_threads); } else { show_import(config); } } else if (searchname != NULL) { char *name;
*** 2416,2426 **** (void) fprintf(stderr, gettext("cannot import '%s': " "no such pool available\n"), argv[0]); err = B_TRUE; } else { err |= do_import(found_config, argc == 1 ? NULL : ! argv[1], mntopts, props, flags); } } /* * If we were just looking for pools, report an error if none were --- 2591,2601 ---- (void) fprintf(stderr, gettext("cannot import '%s': " "no such pool available\n"), argv[0]); err = B_TRUE; } else { err |= do_import(found_config, argc == 1 ? NULL : ! argv[1], mntopts, props, flags, n_threads); } } /* * If we were just looking for pools, report an error if none were
*** 2451,2470 **** { int i = 0; for (i = 0; i < cb->cb_namewidth; i++) (void) printf("-"); ! (void) 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); } /* * Display a single statistic. --- 2626,2646 ---- { int i = 0; for (i = 0; i < cb->cb_namewidth; i++) (void) printf("-"); ! (void) printf(" ----- ----- ----- ----- ----- ----- ----- " ! "-----\n"); } static void print_iostat_header(iostat_cbdata_t *cb) { ! (void) printf("%*s capacity operations bandwidth " ! "latency\n", cb->cb_namewidth, ""); ! (void) printf("%-*s alloc free read write read write read " ! "write\n", cb->cb_namewidth, "pool"); print_iostat_separator(cb); } /* * Display a single statistic.
*** 2477,2486 **** --- 2653,2681 ---- zfs_nicenum(value, buf, sizeof (buf)); (void) printf(" %5s", buf); } /* + * Display latency statistic (extra care needed) + */ + static void + print_one_latency_stat(uint64_t iotime, uint64_t ops) + { + char buf[64]; + double value = 0.0; /* latency in milliseconds */ + + if (ops != 0) { + value = (double)iotime; + value /= (double)ops; + value /= (double)(MICROSEC / MILLISEC); + } + + (void) sprintf(buf, "%.2f", value); + (void) printf(" %5s", buf); + } + + /* * 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. */ void
*** 2493,2505 **** vdev_stat_t zerovs = { 0 }; uint64_t tdelta; double scale; char *vname; - if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) - return; - if (oldnv != NULL) { verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); } else { oldvs = &zerovs; --- 2688,2697 ----
*** 2539,2548 **** --- 2731,2753 ---- oldvs->vs_bytes[ZIO_TYPE_READ]))); print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - oldvs->vs_bytes[ZIO_TYPE_WRITE]))); + /* + * No scale needed here since we are dividing in + * print_one_latency_stat() + */ + + print_one_latency_stat( + newvs->vs_iotime[ZIO_TYPE_READ] - oldvs->vs_iotime[ZIO_TYPE_READ], + newvs->vs_ops[ZIO_TYPE_READ] - oldvs->vs_ops[ZIO_TYPE_READ]); + + print_one_latency_stat( + newvs->vs_iotime[ZIO_TYPE_WRITE] - oldvs->vs_iotime[ZIO_TYPE_WRITE], + newvs->vs_ops[ZIO_TYPE_WRITE] - oldvs->vs_ops[ZIO_TYPE_WRITE]); + (void) printf("\n"); if (!cb->cb_verbose) return;
*** 2553,2571 **** if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, &oldchild, &c) != 0) return; for (c = 0; c < children; c++) { ! uint64_t ishole = B_FALSE, islog = B_FALSE; (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, &ishole); (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, &islog); ! if (ishole || islog) continue; vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2); --- 2758,2779 ---- if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, &oldchild, &c) != 0) return; for (c = 0; c < children; c++) { ! uint64_t ishole = B_FALSE, islog = B_FALSE, isspec = B_FALSE; (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, &ishole); (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, &islog); ! (void) nvlist_lookup_uint64(newchild[c], ! ZPOOL_CONFIG_IS_SPECIAL, &isspec); ! ! if (ishole || islog || isspec) continue; vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2);
*** 2592,2603 **** --- 2800,2834 ---- oldchild[c] : NULL, newchild[c], cb, depth + 2); free(vname); } } + } + /* + * Special device section + */ + + if (num_special(newnv) > 0) { + (void) printf("%-*s - - - - - " + "-\n", cb->cb_namewidth, "special"); + + for (c = 0; c < children; c++) { + uint64_t isspec = B_FALSE; + (void) nvlist_lookup_uint64(newchild[c], + ZPOOL_CONFIG_IS_SPECIAL, &isspec); + + if (isspec) { + vname = zpool_vdev_name(g_zfs, zhp, newchild[c], + B_FALSE); + print_vdev_stats(zhp, vname, oldnv ? + oldchild[c] : NULL, newchild[c], + cb, depth + 2); + free(vname); } + } + } /* * Include level 2 ARC devices in iostat output */ if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
*** 3102,3114 **** if (name != NULL) { boolean_t toplevel = (vs->vs_space != 0); uint64_t cap; - if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) - return; - if (scripted) (void) printf("\t%s", name); else if (strlen(name) + depth > cb->cb_namewidth) (void) printf("%*s%s", depth, "", name); else --- 3333,3342 ----
*** 3236,3246 **** */ int zpool_do_list(int argc, char **argv) { int c; ! int ret; list_cbdata_t cb = { 0 }; static char default_props[] = "name,size,allocated,free,expandsize,fragmentation,capacity," "dedupratio,health,altroot"; char *props = default_props; --- 3464,3474 ---- */ int zpool_do_list(int argc, char **argv) { int c; ! int ret = 0; list_cbdata_t cb = { 0 }; static char default_props[] = "name,size,allocated,free,expandsize,fragmentation,capacity," "dedupratio,health,altroot"; char *props = default_props;
*** 3980,3989 **** --- 4208,4242 ---- err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); return (err != 0); } + typedef struct trim_cbdata { + boolean_t cb_start; + uint64_t cb_rate; + } trim_cbdata_t; + + int + trim_callback(zpool_handle_t *zhp, void *data) + { + trim_cbdata_t *cb = data; + int err; + + /* + * Ignore faulted pools. + */ + if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { + (void) fprintf(stderr, gettext("cannot trim '%s': pool is " + "currently unavailable\n"), zpool_get_name(zhp)); + return (1); + } + + err = zpool_trim(zhp, cb->cb_start, cb->cb_rate); + + return (err != 0); + } + /* * zpool scrub [-s | -p] <pool> ... * * -s Stop. Stops any in-progress scrub. * -p Pause. Pause in-progress scrub.
*** 3996,4010 **** cb.cb_type = POOL_SCAN_SCRUB; cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; /* check options */ ! while ((c = getopt(argc, argv, "sp")) != -1) { switch (c) { case 's': cb.cb_type = POOL_SCAN_NONE; break; case 'p': cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), --- 4249,4284 ---- cb.cb_type = POOL_SCAN_SCRUB; cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; /* check options */ ! while ((c = getopt(argc, argv, "mMps")) != -1) { switch (c) { case 's': + if (cb.cb_type != POOL_SCAN_SCRUB) { + (void) fprintf(stderr, + gettext("incompatible options\n")); + usage(B_FALSE); + } else cb.cb_type = POOL_SCAN_NONE; break; + case 'M': + if (cb.cb_type != POOL_SCAN_SCRUB) { + (void) fprintf(stderr, + gettext("incompatible options\n")); + usage(B_FALSE); + } else + cb.cb_type = POOL_SCAN_MOS; + break; + case 'm': + if (cb.cb_type != POOL_SCAN_SCRUB) { + (void) fprintf(stderr, + gettext("incompatible options\n")); + usage(B_FALSE); + } else + cb.cb_type = POOL_SCAN_META; + break; case 'p': cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"),
*** 4031,4040 **** --- 4305,4360 ---- } return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); } + /* + * zpool trim [-s|-r <rate>] <pool> ... + * + * -s Stop. Stops any in-progress trim. + * -r <rate> Sets the TRIM rate. + */ + int + zpool_do_trim(int argc, char **argv) + { + int c; + trim_cbdata_t cb; + + cb.cb_start = B_TRUE; + cb.cb_rate = 0; + + /* check options */ + while ((c = getopt(argc, argv, "sr:")) != -1) { + switch (c) { + case 's': + cb.cb_start = B_FALSE; + break; + case 'r': + if (zfs_nicestrtonum(NULL, optarg, &cb.cb_rate) == -1) { + (void) fprintf(stderr, + gettext("invalid value for rate\n")); + usage(B_FALSE); + } + break; + case '?': + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + optopt); + usage(B_FALSE); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + (void) fprintf(stderr, gettext("missing pool name argument\n")); + usage(B_FALSE); + } + + return (for_each_pool(argc, argv, B_TRUE, NULL, trim_callback, &cb)); + } + typedef struct status_cbdata { int cb_count; boolean_t cb_allpools; boolean_t cb_verbose; boolean_t cb_explain;
*** 4043,4061 **** } status_cbdata_t; /* * Print out detailed scrub status. */ ! static void print_scan_status(pool_scan_stat_t *ps) { time_t start, end, pause; uint64_t elapsed, mins_left, hours_left; ! uint64_t pass_exam, examined, total; ! uint_t rate; double fraction_done; ! char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; (void) printf(gettext(" scan: ")); /* If there's never been a scan, there's not much to say. */ if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || --- 4363,4382 ---- } status_cbdata_t; /* * Print out detailed scrub status. */ ! void print_scan_status(pool_scan_stat_t *ps) { time_t start, end, pause; uint64_t elapsed, mins_left, hours_left; ! uint64_t examined, total; ! uint64_t rate, proc_rate; double fraction_done; ! char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7], ! issued_buf[7]; (void) printf(gettext(" scan: ")); /* If there's never been a scan, there's not much to say. */ if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
*** 4068,4078 **** end = ps->pss_end_time; pause = ps->pss_pass_scrub_pause; zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); assert(ps->pss_func == POOL_SCAN_SCRUB || ! ps->pss_func == POOL_SCAN_RESILVER); /* * Scan is finished or canceled. */ if (ps->pss_state == DSS_FINISHED) { uint64_t minutes_taken = (end - start) / 60; --- 4389,4401 ---- end = ps->pss_end_time; pause = ps->pss_pass_scrub_pause; zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); assert(ps->pss_func == POOL_SCAN_SCRUB || ! ps->pss_func == POOL_SCAN_RESILVER || ! ps->pss_func == POOL_SCAN_MOS || ! ps->pss_func == POOL_SCAN_META); /* * Scan is finished or canceled. */ if (ps->pss_state == DSS_FINISHED) { uint64_t minutes_taken = (end - start) / 60;
*** 4079,4088 **** --- 4402,4417 ---- char *fmt = NULL; if (ps->pss_func == POOL_SCAN_SCRUB) { fmt = gettext("scrub repaired %s in %lluh%um with " "%llu errors on %s"); + } else if (ps->pss_func == POOL_SCAN_MOS) { + fmt = gettext("MOS scrub repaired %s in %lluh%um with " + "%llu errors on %s"); + } else if (ps->pss_func == POOL_SCAN_META) { + fmt = gettext("meta scrub repaired %s in %lluh%um with " + "%llu errors on %s"); } else if (ps->pss_func == POOL_SCAN_RESILVER) { fmt = gettext("resilvered %s in %lluh%um with " "%llu errors on %s"); } /* LINTED */
*** 4094,4111 **** return; } else if (ps->pss_state == DSS_CANCELED) { if (ps->pss_func == POOL_SCAN_SCRUB) { (void) printf(gettext("scrub canceled on %s"), ctime(&end)); } else if (ps->pss_func == POOL_SCAN_RESILVER) { (void) printf(gettext("resilver canceled on %s"), ctime(&end)); } return; } ! assert(ps->pss_state == DSS_SCANNING); /* * Scan is in progress. */ if (ps->pss_func == POOL_SCAN_SCRUB) { --- 4423,4446 ---- return; } else if (ps->pss_state == DSS_CANCELED) { if (ps->pss_func == POOL_SCAN_SCRUB) { (void) printf(gettext("scrub canceled on %s"), ctime(&end)); + } else if (ps->pss_func == POOL_SCAN_MOS) { + (void) printf(gettext("MOS scrub canceled on %s"), + ctime(&end)); + } else if (ps->pss_func == POOL_SCAN_META) { + (void) printf(gettext("meta scrub canceled on %s"), + ctime(&end)); } else if (ps->pss_func == POOL_SCAN_RESILVER) { (void) printf(gettext("resilver canceled on %s"), ctime(&end)); } return; } ! assert(ps->pss_state == DSS_SCANNING || ps->pss_state == DSS_FINISHING); /* * Scan is in progress. */ if (ps->pss_func == POOL_SCAN_SCRUB) {
*** 4118,4280 **** (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); (void) printf(gettext("scrub paused since %s\n"), buf); (void) printf(gettext("\tscrub started on %s"), ctime(&start)); } } else if (ps->pss_func == POOL_SCAN_RESILVER) { (void) printf(gettext("resilver in progress since %s"), ctime(&start)); } ! examined = ps->pss_examined ? ps->pss_examined : 1; total = ps->pss_to_examine; ! fraction_done = (double)examined / total; /* elapsed time for this pass */ ! elapsed = time(NULL) - ps->pss_pass_start; ! elapsed -= ps->pss_pass_scrub_spent_paused; ! elapsed = elapsed ? elapsed : 1; ! pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; ! rate = pass_exam / elapsed; ! rate = rate ? rate : 1; ! mins_left = ((total - examined) / rate) / 60; hours_left = mins_left / 60; zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); zfs_nicenum(total, total_buf, sizeof (total_buf)); /* * do not print estimated time if hours_left is more than 30 days * or we have a paused scrub */ if (pause == 0) { - zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); - (void) printf(gettext("\t%s scanned out of %s at %s/s"), - examined_buf, total_buf, rate_buf); if (hours_left < (30 * 24)) { (void) printf(gettext(", %lluh%um to go\n"), (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); } else { (void) printf(gettext( ", (scan is slow, no estimated time)\n")); } } else { ! (void) printf(gettext("\t%s scanned out of %s\n"), ! examined_buf, total_buf); } - - if (ps->pss_func == POOL_SCAN_RESILVER) { - (void) printf(gettext(" %s resilvered, %.2f%% done\n"), - processed_buf, 100 * fraction_done); - } else if (ps->pss_func == POOL_SCAN_SCRUB) { - (void) printf(gettext(" %s repaired, %.2f%% done\n"), - processed_buf, 100 * fraction_done); - } } - /* - * Print out detailed removal status. - */ static void ! print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs) { ! char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; ! time_t start, end; ! nvlist_t *config, *nvroot; ! nvlist_t **child; ! uint_t children; ! char *vdev_name; ! if (prs == NULL || prs->prs_state == DSS_NONE) ! return; ! ! /* ! * Determine name of vdev. ! */ ! config = zpool_get_config(zhp, NULL); ! nvroot = fnvlist_lookup_nvlist(config, ! ZPOOL_CONFIG_VDEV_TREE); ! verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, ! &child, &children) == 0); ! assert(prs->prs_removing_vdev < children); ! vdev_name = zpool_vdev_name(g_zfs, zhp, ! child[prs->prs_removing_vdev], B_TRUE); ! ! (void) printf(gettext("remove: ")); ! ! start = prs->prs_start_time; ! end = prs->prs_end_time; ! zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf)); ! ! /* ! * Removal is finished or canceled. ! */ ! if (prs->prs_state == DSS_FINISHED) { ! uint64_t minutes_taken = (end - start) / 60; ! ! (void) printf(gettext("Removal of vdev %llu copied %s " ! "in %lluh%um, completed on %s"), ! (longlong_t)prs->prs_removing_vdev, ! copied_buf, ! (u_longlong_t)(minutes_taken / 60), ! (uint_t)(minutes_taken % 60), ! ctime((time_t *)&end)); ! } else if (prs->prs_state == DSS_CANCELED) { ! (void) printf(gettext("Removal of %s canceled on %s"), ! vdev_name, ctime(&end)); } else { ! uint64_t copied, total, elapsed, mins_left, hours_left; ! double fraction_done; ! uint_t rate; ! ! assert(prs->prs_state == DSS_SCANNING); ! /* ! * Removal is in progress. */ ! (void) printf(gettext( ! "Evacuation of %s in progress since %s"), ! vdev_name, ctime(&start)); ! copied = prs->prs_copied > 0 ? prs->prs_copied : 1; ! total = prs->prs_to_copy; ! fraction_done = (double)copied / total; ! ! /* elapsed time for this pass */ ! elapsed = time(NULL) - prs->prs_start_time; ! elapsed = elapsed > 0 ? elapsed : 1; ! rate = copied / elapsed; ! rate = rate > 0 ? rate : 1; ! mins_left = ((total - copied) / rate) / 60; ! hours_left = mins_left / 60; ! ! zfs_nicenum(copied, examined_buf, sizeof (examined_buf)); ! zfs_nicenum(total, total_buf, sizeof (total_buf)); ! zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); ! ! /* ! * do not print estimated time if hours_left is more than ! * 30 days ! */ ! (void) printf(gettext(" %s copied out of %s at %s/s, " ! "%.2f%% done"), ! examined_buf, total_buf, rate_buf, 100 * fraction_done); ! if (hours_left < (30 * 24)) { ! (void) printf(gettext(", %lluh%um to go\n"), ! (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); } else { ! (void) printf(gettext( ! ", (copy is slow, no estimated time)\n")); } } - - if (prs->prs_mapping_memory > 0) { - char mem_buf[7]; - zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf)); - (void) printf(gettext(" %s memory used for " - "removed device mappings\n"), - mem_buf); } } static void print_error_log(zpool_handle_t *zhp) --- 4453,4585 ---- (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); (void) printf(gettext("scrub paused since %s\n"), buf); (void) printf(gettext("\tscrub started on %s"), ctime(&start)); } + } else if (ps->pss_func == POOL_SCAN_MOS) { + (void) printf(gettext("MOS scrub in progress since %s"), + ctime(&start)); + } else if (ps->pss_func == POOL_SCAN_META) { + (void) printf(gettext("meta scrub in progress since %s"), + ctime(&start)); } else if (ps->pss_func == POOL_SCAN_RESILVER) { (void) printf(gettext("resilver in progress since %s"), ctime(&start)); } ! examined = ps->pss_examined; total = ps->pss_to_examine; ! fraction_done = (double)ps->pss_issued / total; /* elapsed time for this pass */ ! elapsed = MAX(time(NULL) - ps->pss_start_time - ! ps->pss_pass_scrub_spent_paused, 1); ! if (ps->pss_func == POOL_SCAN_RESILVER) { ! rate = MAX(((ps->pss_issued + ps->pss_processed) / 2) / ! elapsed, 1); ! } else { ! rate = MAX(ps->pss_issued / elapsed, 1); ! } ! proc_rate = MAX(ps->pss_processed / elapsed, 1); ! if (ps->pss_func == POOL_SCAN_RESILVER) ! mins_left = ((total - ps->pss_issued) / proc_rate) / 60; ! else ! mins_left = ((total - ps->pss_issued) / rate) / 60; hours_left = mins_left / 60; zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); + zfs_nicenum(ps->pss_issued, issued_buf, sizeof (issued_buf)); zfs_nicenum(total, total_buf, sizeof (total_buf)); + zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); + if (pause == 0) { + (void) printf(gettext(" %s scanned, %s verified " + "out of %s at %s/s, %.2f%% done\n"), examined_buf, + issued_buf, total_buf, rate_buf, 100 * fraction_done); + } + + if (ps->pss_func == POOL_SCAN_RESILVER) { + char proc_rate_buf[7]; + zfs_nicenum(proc_rate, proc_rate_buf, + sizeof (proc_rate_buf)); + (void) printf(gettext(" %s resilvered at %s/s"), + processed_buf, proc_rate_buf); + } else if (ps->pss_func == POOL_SCAN_SCRUB || + ps->pss_func == POOL_SCAN_MOS || + ps->pss_func == POOL_SCAN_META) { + (void) printf(gettext(" %s repaired"), + processed_buf); + } + /* * do not print estimated time if hours_left is more than 30 days * or we have a paused scrub */ if (pause == 0) { if (hours_left < (30 * 24)) { (void) printf(gettext(", %lluh%um to go\n"), (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); } else { (void) printf(gettext( ", (scan is slow, no estimated time)\n")); } } else { ! (void) printf(gettext("\t%s scanned, %s verified out of %s\n"), ! examined_buf, issued_buf, total_buf); } } static void ! print_trim_status(uint64_t trim_prog, uint64_t total_size, uint64_t rate, ! uint64_t start_time_u64, uint64_t end_time_u64) { ! time_t start_time = start_time_u64, end_time = end_time_u64; ! char *buf; ! assert(trim_prog <= total_size); ! if (trim_prog != 0 && trim_prog != total_size) { ! buf = ctime(&start_time); ! buf[strlen(buf) - 1] = '\0'; /* strip trailing newline */ ! if (rate != 0) { ! char rate_str[32]; ! zfs_nicenum(rate, rate_str, sizeof (rate_str)); ! (void) printf(" trim: %.02f%%\tstarted: %s\t" ! "(rate: %s/s)\n", (((double)trim_prog) / ! total_size) * 100, buf, rate_str); } else { ! (void) printf(" trim: %.02f%%\tstarted: %s\t" ! "(rate: max)\n", (((double)trim_prog) / ! total_size) * 100, buf); ! } ! } else { ! if (start_time != 0) { /* ! * Non-zero start time means we were run at some point ! * in the past. */ ! if (end_time != 0) { ! /* Non-zero end time means we completed */ ! time_t diff = end_time - start_time; ! int hrs, mins; ! buf = ctime(&end_time); ! buf[strlen(buf) - 1] = '\0'; ! hrs = diff / 3600; ! mins = (diff % 3600) / 60; ! (void) printf(gettext(" trim: completed on %s " ! "(after %dh%dm)\n"), buf, hrs, mins); } else { ! buf = ctime(&start_time); ! buf[strlen(buf) - 1] = '\0'; ! /* Zero end time means we were interrupted */ ! (void) printf(gettext(" trim: interrupted\t" ! "(started %s)\n"), buf); } + } else { + /* trim was never run */ + (void) printf(gettext(" trim: none requested\n")); } } } static void print_error_log(zpool_handle_t *zhp)
*** 4386,4395 **** --- 4691,4737 ---- (uint64_t **)&ddh, &c) == 0); zpool_dump_ddt(dds, ddh); } /* + * Calculates the total space available on log devices on the pool. + * For whatever reason, this is not counted in the root vdev's space stats. + */ + static uint64_t + zpool_slog_space(nvlist_t *nvroot) + { + nvlist_t **newchild; + uint_t c, children; + uint64_t space = 0; + + verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, + &newchild, &children) == 0); + + for (c = 0; c < children; c++) { + uint64_t islog = B_FALSE; + vdev_stat_t *vs; + uint_t n; + uint_t n_subchildren = 1; + nvlist_t **subchild; + + (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, + &islog); + if (!islog) + continue; + verify(nvlist_lookup_uint64_array(newchild[c], + ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &n) == 0); + + /* vdev can be non-leaf, so multiply by number of children */ + (void) nvlist_lookup_nvlist_array(newchild[c], + ZPOOL_CONFIG_CHILDREN, &subchild, &n_subchildren); + space += n_subchildren * vs->vs_space; + } + + return (space); + } + + /* * Display a summary of pool status. Displays a summary such as: * * pool: tank * status: DEGRADED * reason: One or more devices ...
*** 4438,4448 **** if (cbp->cb_first) cbp->cb_first = B_FALSE; else (void) printf("\n"); ! nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c) == 0); health = zpool_state_to_name(vs->vs_state, vs->vs_aux); (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); --- 4780,4791 ---- if (cbp->cb_first) cbp->cb_first = B_FALSE; else (void) printf("\n"); ! verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, ! &nvroot) == 0); verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c) == 0); health = zpool_state_to_name(vs->vs_state, vs->vs_aux); (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
*** 4646,4664 **** int namewidth; uint64_t nerr; nvlist_t **spares, **l2cache; uint_t nspares, nl2cache; pool_scan_stat_t *ps = NULL; ! pool_removal_stat_t *prs = NULL; (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); print_scan_status(ps); ! (void) nvlist_lookup_uint64_array(nvroot, ! ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c); ! print_removal_status(zhp, prs); namewidth = max_width(zhp, nvroot, 0, 0); if (namewidth < 10) namewidth = 10; --- 4989,5021 ---- int namewidth; uint64_t nerr; nvlist_t **spares, **l2cache; uint_t nspares, nl2cache; pool_scan_stat_t *ps = NULL; ! uint64_t trim_prog, trim_rate, trim_start_time, trim_stop_time; (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); print_scan_status(ps); ! /* Grab trim stats if the pool supports it */ ! if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_PROG, ! &trim_prog) == 0 && ! nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_RATE, ! &trim_rate) == 0 && ! nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_START_TIME, ! &trim_start_time) == 0 && ! nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_STOP_TIME, ! &trim_stop_time) == 0) { ! /* ! * For whatever reason, root vdev_stats_t don't ! * include log devices. ! */ ! print_trim_status(trim_prog, vs->vs_space + ! zpool_slog_space(nvroot), trim_rate, ! trim_start_time, trim_stop_time); ! } namewidth = max_width(zhp, nvroot, 0, 0); if (namewidth < 10) namewidth = 10;
*** 4666,4675 **** --- 5023,5034 ---- (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, "NAME", "STATE", "READ", "WRITE", "CKSUM"); print_status_config(zhp, zpool_get_name(zhp), nvroot, namewidth, 0, B_FALSE); + if (num_special(nvroot) > 0) + print_special(zhp, nvroot, namewidth, B_TRUE); if (num_logs(nvroot) > 0) print_logs(zhp, nvroot, namewidth, B_TRUE); if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0) print_l2cache(zhp, l2cache, nl2cache, namewidth);
*** 4845,4858 **** boolean_t firstff = B_TRUE; nvlist_t *enabled = zpool_get_features(zhp); count = 0; for (i = 0; i < SPA_FEATURES; i++) { ! const char *fname = spa_feature_table[i].fi_uname; ! const char *fguid = spa_feature_table[i].fi_guid; if (!nvlist_exists(enabled, fguid)) { char *propname; verify(-1 != asprintf(&propname, "feature@%s", fname)); ret = zpool_set_prop(zhp, propname, ZFS_FEATURE_ENABLED); if (ret != 0) { free(propname); --- 5204,5226 ---- boolean_t firstff = B_TRUE; nvlist_t *enabled = zpool_get_features(zhp); count = 0; for (i = 0; i < SPA_FEATURES; i++) { ! zfeature_info_t *finfo = &spa_feature_table[i]; ! const char *fname = finfo->fi_uname; ! const char *fguid = finfo->fi_guid; if (!nvlist_exists(enabled, fguid)) { char *propname; + + /* + * SPA_FEATURE_WBC can be enabled only + * if 'special' vdev available + */ + if (finfo->fi_feature == SPA_FEATURE_WBC) + continue; + verify(-1 != asprintf(&propname, "feature@%s", fname)); ret = zpool_set_prop(zhp, propname, ZFS_FEATURE_ENABLED); if (ret != 0) { free(propname);
*** 5606,5634 **** return (ret); } typedef struct set_cbdata { ! char *cb_propname; ! char *cb_value; boolean_t cb_any_successful; } set_cbdata_t; int set_callback(zpool_handle_t *zhp, void *data) { int error; set_cbdata_t *cb = (set_cbdata_t *)data; ! error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); ! if (!error) cb->cb_any_successful = B_TRUE; return (error); } int zpool_do_set(int argc, char **argv) { set_cbdata_t cb = { 0 }; int error; --- 5974,6042 ---- return (ret); } typedef struct set_cbdata { ! nvlist_t *cb_nvl; boolean_t cb_any_successful; } set_cbdata_t; int set_callback(zpool_handle_t *zhp, void *data) { int error; set_cbdata_t *cb = (set_cbdata_t *)data; ! error = zpool_set_proplist(zhp, cb->cb_nvl); if (!error) cb->cb_any_successful = B_TRUE; return (error); } + static void + parse_props(char *propname, nvlist_t **nvl, zfs_type_t prop_type) + { + char *propval; + char *delim; + int err; + + do { + delim = strchr(propname, ','); + if (delim != NULL) + *delim++ = '\0'; + + propval = strchr(propname, '='); + if (propval == NULL) { + (void) fprintf(stderr, gettext("missing value " + "in property=value argument\n")); + if (*nvl != NULL) + nvlist_free(*nvl); + usage(B_FALSE); + } + *propval++ = '\0'; + switch (prop_type) { + case ZFS_TYPE_VDEV: + err = add_vdev_prop_list(propname, propval, nvl); + break; + case ZFS_TYPE_COS: + err = add_cos_prop_list(propname, propval, nvl); + break; + default: + err = add_prop_list(propname, propval, nvl, B_TRUE); + } + + if (err) { + if (*nvl != NULL) + nvlist_free(*nvl); + usage(B_FALSE); + } + + propname = delim; + } while (delim != NULL); + } + int zpool_do_set(int argc, char **argv) { set_cbdata_t cb = { 0 }; int error;
*** 5653,5680 **** if (argc > 3) { (void) fprintf(stderr, gettext("too many pool names\n")); usage(B_FALSE); } ! cb.cb_propname = argv[1]; ! cb.cb_value = strchr(cb.cb_propname, '='); ! if (cb.cb_value == NULL) { ! (void) fprintf(stderr, gettext("missing value in " ! "property=value argument\n")); usage(B_FALSE); } ! *(cb.cb_value) = '\0'; ! cb.cb_value++; ! error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, ! set_callback, &cb); return (error); } static int find_command_idx(char *command, int *idx) { int i; for (i = 0; i < NCOMMAND; i++) { --- 6061,6530 ---- if (argc > 3) { (void) fprintf(stderr, gettext("too many pool names\n")); usage(B_FALSE); } ! parse_props(argv[1], &cb.cb_nvl, ZFS_TYPE_POOL); ! ! error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, ! set_callback, &cb); ! ! return (error); ! } ! ! typedef struct vdev_cbdata { ! char *vcb_vdev; ! nvlist_t *vcb_nvl; /* values */ ! boolean_t vcb_any_successful; ! } vdev_cbdata_t; ! ! typedef struct vdev_get_cbdata { ! zprop_get_cbdata_t vcb_zprop_get_cbdata; ! char *vcb_vdev; ! nvlist_t *vcb_nvl; /* values */ ! boolean_t vcb_any_successful; ! } vdev_get_cbdata_t; ! ! static int ! vdev_get_callback(zpool_handle_t *zhp, void *data) ! { ! int err; ! boolean_t l2cache, avail_space; ! vdev_get_cbdata_t *vcb = (vdev_get_cbdata_t *)data; ! zprop_get_cbdata_t *cb = &vcb->vcb_zprop_get_cbdata; ! char value[MAXNAMELEN]; ! zprop_list_t *pl; ! ! (void) zpool_find_vdev(zhp, vcb->vcb_vdev, &avail_space, ! &l2cache, NULL, NULL); ! for (pl = cb->cb_proplist; pl != NULL; pl = pl->pl_next) { ! if ((err = vdev_get_prop(zhp, vcb->vcb_vdev, ! pl->pl_prop, value, sizeof (value))) != 0) ! return (err); ! ! /* don't show L2ARC prop for non L2ARC dev, can't set anyway */ ! if (!l2cache && pl->pl_prop == VDEV_PROP_L2ADDDT) ! continue; ! vdev_print_one_property(zpool_get_name(zhp), vcb->vcb_vdev, cb, ! vdev_prop_to_name(pl->pl_prop), value); ! } ! ! return (0); ! } ! ! ! int ! zpool_do_vdev_get(int argc, char **argv) ! { ! vdev_get_cbdata_t vcb = { 0 }; ! zprop_get_cbdata_t *cb = &vcb.vcb_zprop_get_cbdata; ! int error; ! ! if (argc > 1 && argv[1][0] == '-') { ! (void) fprintf(stderr, gettext("invalid option '%c'\n"), ! argv[1][1]); usage(B_FALSE); } ! if (argc < 2) { ! (void) fprintf(stderr, gettext("missing property name\n")); ! usage(B_FALSE); ! } ! if (argc < 3) { ! (void) fprintf(stderr, gettext("missing pool name\n")); ! usage(B_FALSE); ! } + if (argc < 4) { + (void) fprintf(stderr, + gettext("at least one vdev name or guid is required\n")); + usage(B_FALSE); + } + + cb->cb_first = B_TRUE; + cb->cb_sources = ZPROP_SRC_ALL; + cb->cb_columns[0] = GET_COL_NAME; + cb->cb_columns[1] = GET_COL_SOURCE; + cb->cb_columns[2] = GET_COL_PROPERTY; + cb->cb_columns[3] = GET_COL_VALUE; + cb->cb_type = ZFS_TYPE_VDEV; + + if (vdev_get_proplist(g_zfs, argv[1], &cb->cb_proplist) != 0) + usage(B_FALSE); + + vcb.vcb_vdev = argv[3]; + error = for_each_pool(1, argv + 2, B_TRUE, NULL, + vdev_get_callback, &vcb); + + zprop_free_list(cb->cb_proplist); + return (error); } + int + vdev_set_callback(zpool_handle_t *zhp, void *data) + { + int error; + vdev_cbdata_t *cb = (vdev_cbdata_t *)data; + + error = vdev_set_proplist(zhp, cb->vcb_vdev, cb->vcb_nvl); + if (!error) + cb->vcb_any_successful = B_TRUE; + + return (error); + } + + int + zpool_do_vdev_set(int argc, char **argv) + { + vdev_cbdata_t cb = { 0 }; + int error; + + if (argc > 1 && argv[1][0] == '-') { + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + argv[1][1]); + usage(B_FALSE); + } + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing property=value " + "argument\n")); + usage(B_FALSE); + } + + if (argc < 3) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + if (argc < 4) { + (void) fprintf(stderr, + gettext("at least one vdev name or guid is required\n")); + usage(B_FALSE); + } + + parse_props(argv[1], &cb.vcb_nvl, ZFS_TYPE_VDEV); + + cb.vcb_vdev = argv[3]; + error = for_each_pool(1, argv + 2, B_TRUE, NULL, + vdev_set_callback, &cb); + + return (error); + } + + typedef struct cos_af_cbdata { + char *cb_cos; + uint64_t cb_guid; + boolean_t cb_alloc; + boolean_t cb_any_successful; + boolean_t cb_force; + nvlist_t *cb_nvl; + } cos_af_cbdata_t; + + int + cos_alloc_callback(zpool_handle_t *zhp, void *data) + { + int error; + cos_af_cbdata_t *cb = (cos_af_cbdata_t *)data; + + if (cb->cb_alloc) + error = cos_alloc(zhp, cb->cb_cos, cb->cb_nvl); + else + error = cos_free(zhp, cb->cb_cos, cb->cb_guid, cb->cb_force); + if (!error) + cb->cb_any_successful = B_TRUE; + + if (error == ENOTSUP) { + (void) fprintf(stderr, gettext("operation failed: " + "CoS feature is disabled.\n")); + } + + return (error); + } + + int + zpool_do_cos_alloc(int argc, char **argv) + { + nvlist_t *nvl; + cos_af_cbdata_t cb = { 0 }; + int error; + + if (!nexenta_meta_enable()) + return (-1); + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + if (argc < 3) { + (void) fprintf(stderr, + gettext("at least one cos name or id is required\n")); + usage(B_FALSE); + } + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, + gettext("internal error: out of memory\n")); + return (1); + } + + cb.cb_cos = argv[2]; + cb.cb_alloc = B_TRUE; + cb.cb_nvl = nvl; + error = for_each_pool(1, argv + 1, B_TRUE, NULL, + cos_alloc_callback, &cb); + + nvlist_free(nvl); + + return (error); + } + + int + zpool_do_cos_free(int argc, char **argv) + { + cos_af_cbdata_t cb = { 0 }; + char *endp; + int error; + + if (!nexenta_meta_enable()) + return (-1); + + if (argc > 1 && strncmp(argv[1], "-f", sizeof ("-f")) == 0) { + /* -f - force option */ + cb.cb_force = B_TRUE; + argc--; + argv++; + } + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + if (argc < 3) { + (void) fprintf(stderr, + gettext("at least one cos name or id is required\n")); + usage(B_FALSE); + } + + cb.cb_guid = strtoll(argv[2], &endp, 10); + if (endp < argv[2] + strlen(argv[2])) { + cb.cb_guid = 0; + } + + if (cb.cb_guid == 0) + cb.cb_cos = argv[2]; + else + cb.cb_cos = ""; + + error = for_each_pool(1, argv + 1, B_TRUE, NULL, + cos_alloc_callback, &cb); + + return (error); + } + + static int + cos_list_callback(zpool_handle_t *zhp, void *data) + { + int err, i; + nvlist_t *nvl = (nvlist_t *)data; + nvpair_t *nvp; + + if ((err = cos_list(zhp, &nvl)) == 0) { + (void) printf("%-*s %s\n", MAXCOSNAMELEN, gettext("COSNAME"), + gettext("COSID")); + for (i = 0, nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; + nvp = nvlist_next_nvpair(nvl, nvp), i++) { + uint64_t cosid; + char *cosname = nvpair_name(nvp); + if (nvpair_value_uint64(nvp, &cosid) == 0) + (void) printf("%-*s %llu\n", MAXCOSNAMELEN, + cosname, cosid); + } + + if (!i) + (void) printf("%s\n", gettext("<no classes found>")); + } + return (err); + } + + int + zpool_do_cos_list(int argc, char **argv) + { + nvlist_t *nvl; + int error; + + if (!nexenta_meta_enable()) + return (-1); + + if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, + gettext("internal error: out of memory\n")); + return (1); + } + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + error = for_each_pool(1, argv+1, B_TRUE, NULL, + cos_list_callback, nvl); + + nvlist_free(nvl); + + return (error); + + } + + typedef struct cos_cbdata { + char *vcb_cos; + nvlist_t *vcb_nvl; /* values */ + boolean_t vcb_any_successful; + } cos_cbdata_t; + + typedef struct cos_get_cbdata { + zprop_get_cbdata_t vcb_zprop_get_cbdata; + char *vcb_cos; + nvlist_t *vcb_nvl; /* values */ + boolean_t vcb_any_successful; + } cos_get_cbdata_t; + + static int + cos_get_callback(zpool_handle_t *zhp, void *data) + { + int err; + cos_get_cbdata_t *vcb = (cos_get_cbdata_t *)data; + zprop_get_cbdata_t *cb = &vcb->vcb_zprop_get_cbdata; + char value[MAXNAMELEN]; + zprop_list_t *pl; + nvlist_t *nvl = NULL; + + for (pl = cb->cb_proplist; pl != NULL; pl = pl->pl_next) { + if ((err = cos_get_prop(zhp, vcb->vcb_cos, + pl->pl_prop, value, sizeof (value), &nvl)) != 0) + return (err); + + cos_print_one_property(zpool_get_name(zhp), vcb->vcb_cos, cb, + cos_prop_to_name(pl->pl_prop), value); + } + + return (0); + } + + + int + zpool_do_cos_get(int argc, char **argv) + { + cos_get_cbdata_t vcb = { 0 }; + zprop_get_cbdata_t *cb = &vcb.vcb_zprop_get_cbdata; + int error; + + if (!nexenta_meta_enable()) + return (-1); + + if (argc > 1 && argv[1][0] == '-') { + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + argv[1][1]); + usage(B_FALSE); + } + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing property name\n")); + usage(B_FALSE); + } + + if (argc < 3) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + if (argc < 4) { + (void) fprintf(stderr, + gettext("at least one cos name or guid is required\n")); + usage(B_FALSE); + } + + cb->cb_first = B_TRUE; + cb->cb_sources = ZPROP_SRC_ALL; + cb->cb_columns[0] = GET_COL_NAME; + cb->cb_columns[1] = GET_COL_SOURCE; + cb->cb_columns[2] = GET_COL_PROPERTY; + cb->cb_columns[3] = GET_COL_VALUE; + cb->cb_type = ZFS_TYPE_COS; + + if (cos_get_proplist(g_zfs, argv[1], &cb->cb_proplist) != 0) + usage(B_FALSE); + + vcb.vcb_cos = argv[3]; + error = for_each_pool(1, argv + 2, B_TRUE, NULL, + cos_get_callback, &vcb); + + zprop_free_list(cb->cb_proplist); + + return (error); + + } + + int + cos_set_callback(zpool_handle_t *zhp, void *data) + { + int error; + cos_cbdata_t *cb = (cos_cbdata_t *)data; + + error = cos_set_proplist(zhp, cb->vcb_cos, cb->vcb_nvl); + if (!error) + cb->vcb_any_successful = B_TRUE; + + return (error); + } + + int + zpool_do_cos_set(int argc, char **argv) + { + cos_cbdata_t cb = { 0 }; + int error; + + if (!nexenta_meta_enable()) + return (-1); + + if (argc > 1 && argv[1][0] == '-') { + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + argv[1][1]); + usage(B_FALSE); + } + + if (argc < 2) { + (void) fprintf(stderr, gettext("missing property=value " + "argument\n")); + usage(B_FALSE); + } + + if (argc < 3) { + (void) fprintf(stderr, gettext("missing pool name\n")); + usage(B_FALSE); + } + + if (argc < 4) { + (void) fprintf(stderr, + gettext("at least one cos name or id is required\n")); + usage(B_FALSE); + } + + parse_props(argv[1], &cb.vcb_nvl, ZFS_TYPE_COS); + + cb.vcb_cos = argv[3]; + error = for_each_pool(1, argv + 2, B_TRUE, NULL, + cos_set_callback, &cb); + + return (error); + } + + static int find_command_idx(char *command, int *idx) { int i; for (i = 0; i < NCOMMAND; i++) {
*** 5724,5733 **** --- 6574,6584 ---- */ if (strcmp(cmdname, "-?") == 0) usage(B_TRUE); zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); + verify(zpool_stage_history(g_zfs, history_str) == 0); /* * Run the appropriate command. */ if (find_command_idx(cmdname, &i) == 0) {