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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zpool/zpool_main.c
          +++ new/usr/src/cmd/zpool/zpool_main.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
       24 + * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
       26 + * Copyright (c) 2013 by Delphix. All rights reserved.
  26   27   * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
  27   28   * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  28   29   * Copyright 2016 Nexenta Systems, Inc.
  29   30   * Copyright (c) 2017 Datto Inc.
  30   31   */
  31   32  
  32   33  #include <assert.h>
  33   34  #include <ctype.h>
  34   35  #include <dirent.h>
  35   36  #include <errno.h>
↓ open down ↓ 15 lines elided ↑ open up ↑
  51   52  #include <sys/stat.h>
  52   53  
  53   54  #include <libzfs.h>
  54   55  
  55   56  #include "zpool_util.h"
  56   57  #include "zfs_comutil.h"
  57   58  #include "zfeature_common.h"
  58   59  
  59   60  #include "statcommon.h"
  60   61  
       62 +#ifndef MAX
       63 +#define MAX(x, y)       ((x) > (y) ? (x) : (y))
       64 +#endif  /* MAX */
       65 +
  61   66  static int zpool_do_create(int, char **);
  62   67  static int zpool_do_destroy(int, char **);
  63   68  
  64   69  static int zpool_do_add(int, char **);
  65   70  static int zpool_do_remove(int, char **);
  66   71  static int zpool_do_labelclear(int, char **);
  67   72  
  68   73  static int zpool_do_list(int, char **);
  69   74  static int zpool_do_iostat(int, char **);
  70   75  static int zpool_do_status(int, char **);
↓ open down ↓ 4 lines elided ↑ open up ↑
  75   80  static int zpool_do_reopen(int, char **);
  76   81  
  77   82  static int zpool_do_reguid(int, char **);
  78   83  
  79   84  static int zpool_do_attach(int, char **);
  80   85  static int zpool_do_detach(int, char **);
  81   86  static int zpool_do_replace(int, char **);
  82   87  static int zpool_do_split(int, char **);
  83   88  
  84   89  static int zpool_do_scrub(int, char **);
       90 +static int zpool_do_trim(int, char **);
  85   91  
  86   92  static int zpool_do_import(int, char **);
  87   93  static int zpool_do_export(int, char **);
  88   94  
  89   95  static int zpool_do_upgrade(int, char **);
  90   96  
  91   97  static int zpool_do_history(int, char **);
  92   98  
  93   99  static int zpool_do_get(int, char **);
  94  100  static int zpool_do_set(int, char **);
  95  101  
      102 +static int zpool_do_vdev_get(int, char **);
      103 +static int zpool_do_vdev_set(int, char **);
      104 +
      105 +static int zpool_do_cos_alloc(int, char **);
      106 +static int zpool_do_cos_free(int, char **);
      107 +static int zpool_do_cos_list(int, char **);
      108 +static int zpool_do_cos_get(int, char **);
      109 +static int zpool_do_cos_set(int, char **);
      110 +
      111 +static boolean_t nexenta_meta_enable();
      112 +
  96  113  /*
  97  114   * These libumem hooks provide a reasonable set of defaults for the allocator's
  98  115   * debugging facilities.
  99  116   */
 100  117  
 101  118  #ifdef DEBUG
 102  119  const char *
 103  120  _umem_debug_init(void)
 104  121  {
 105  122          return ("default,verbose"); /* $UMEM_DEBUG setting */
↓ open down ↓ 17 lines elided ↑ open up ↑
 123  140          HELP_HISTORY,
 124  141          HELP_IMPORT,
 125  142          HELP_IOSTAT,
 126  143          HELP_LABELCLEAR,
 127  144          HELP_LIST,
 128  145          HELP_OFFLINE,
 129  146          HELP_ONLINE,
 130  147          HELP_REPLACE,
 131  148          HELP_REMOVE,
 132  149          HELP_SCRUB,
      150 +        HELP_TRIM,
 133  151          HELP_STATUS,
 134  152          HELP_UPGRADE,
 135  153          HELP_GET,
 136  154          HELP_SET,
 137  155          HELP_SPLIT,
 138  156          HELP_REGUID,
 139      -        HELP_REOPEN
      157 +        HELP_REOPEN,
      158 +        HELP_VDEV_GET,
      159 +        HELP_VDEV_SET,
      160 +        HELP_COS_ALLOC,
      161 +        HELP_COS_FREE,
      162 +        HELP_COS_LIST,
      163 +        HELP_COS_GET,
      164 +        HELP_COS_SET
 140  165  } zpool_help_t;
 141  166  
 142  167  
 143  168  typedef struct zpool_command {
 144  169          const char      *name;
 145  170          int             (*func)(int, char **);
 146  171          zpool_help_t    usage;
 147  172  } zpool_command_t;
 148  173  
 149  174  /*
↓ open down ↓ 23 lines elided ↑ open up ↑
 173  198          { "clear",      zpool_do_clear,         HELP_CLEAR              },
 174  199          { "reopen",     zpool_do_reopen,        HELP_REOPEN             },
 175  200          { NULL },
 176  201          { "attach",     zpool_do_attach,        HELP_ATTACH             },
 177  202          { "detach",     zpool_do_detach,        HELP_DETACH             },
 178  203          { "replace",    zpool_do_replace,       HELP_REPLACE            },
 179  204          { "split",      zpool_do_split,         HELP_SPLIT              },
 180  205          { NULL },
 181  206          { "scrub",      zpool_do_scrub,         HELP_SCRUB              },
 182  207          { NULL },
      208 +        { "trim",       zpool_do_trim,          HELP_TRIM               },
      209 +        { NULL },
 183  210          { "import",     zpool_do_import,        HELP_IMPORT             },
 184  211          { "export",     zpool_do_export,        HELP_EXPORT             },
 185  212          { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
 186  213          { "reguid",     zpool_do_reguid,        HELP_REGUID             },
 187  214          { NULL },
 188  215          { "history",    zpool_do_history,       HELP_HISTORY            },
 189  216          { "get",        zpool_do_get,           HELP_GET                },
 190  217          { "set",        zpool_do_set,           HELP_SET                },
      218 +        { "vdev-get",   zpool_do_vdev_get,      HELP_VDEV_GET           },
      219 +        { "vdev-set",   zpool_do_vdev_set,      HELP_VDEV_SET           },
      220 +        { "cos-alloc",  zpool_do_cos_alloc,     HELP_COS_ALLOC          },
      221 +        { "cos-free",   zpool_do_cos_free,      HELP_COS_FREE           },
      222 +        { "cos-list",   zpool_do_cos_list,      HELP_COS_LIST           },
      223 +        { "cos-get",    zpool_do_cos_get,       HELP_COS_GET            },
      224 +        { "cos-set",    zpool_do_cos_set,       HELP_COS_SET            }
 191  225  };
 192  226  
 193  227  #define NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
 194  228  
 195  229  static zpool_command_t *current_command;
 196  230  static char history_str[HIS_MAX_RECORD_LEN];
 197  231  static boolean_t log_history = B_TRUE;
 198  232  static uint_t timestamp_fmt = NODATE;
 199  233  
 200  234  static const char *
↓ open down ↓ 14 lines elided ↑ open up ↑
 215  249                      "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
 216  250          case HELP_DESTROY:
 217  251                  return (gettext("\tdestroy [-f] <pool>\n"));
 218  252          case HELP_DETACH:
 219  253                  return (gettext("\tdetach <pool> <device>\n"));
 220  254          case HELP_EXPORT:
 221  255                  return (gettext("\texport [-f] <pool> ...\n"));
 222  256          case HELP_HISTORY:
 223  257                  return (gettext("\thistory [-il] [<pool>] ...\n"));
 224  258          case HELP_IMPORT:
 225      -                return (gettext("\timport [-d dir] [-D]\n"
      259 +                return (gettext("\timport [-d dir] [-D] [-t num]\n"
 226  260                      "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
 227  261                      "\timport [-o mntopts] [-o property=value] ... \n"
 228  262                      "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
 229      -                    "[-R root] [-F [-n]] -a\n"
      263 +                    "[-R root] [-F [-n]] [-t num] -a\n"
 230  264                      "\timport [-o mntopts] [-o property=value] ... \n"
 231  265                      "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
 232  266                      "[-R root] [-F [-n]]\n"
 233  267                      "\t    <pool | id> [newpool]\n"));
 234  268          case HELP_IOSTAT:
 235  269                  return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
 236  270                      "[count]]\n"));
 237  271          case HELP_LABELCLEAR:
 238  272                  return (gettext("\tlabelclear [-f] <vdev>\n"));
 239  273          case HELP_LIST:
 240  274                  return (gettext("\tlist [-Hp] [-o property[,...]] "
 241  275                      "[-T d|u] [pool] ... [interval [count]]\n"));
 242  276          case HELP_OFFLINE:
 243  277                  return (gettext("\toffline [-t] <pool> <device> ...\n"));
 244  278          case HELP_ONLINE:
 245  279                  return (gettext("\tonline <pool> <device> ...\n"));
 246  280          case HELP_REPLACE:
 247  281                  return (gettext("\treplace [-f] <pool> <device> "
 248  282                      "[new-device]\n"));
 249  283          case HELP_REMOVE:
 250      -                return (gettext("\tremove [-nps] <pool> <device> ...\n"));
      284 +                return (gettext("\tremove <pool> <device> ...\n"));
 251  285          case HELP_REOPEN:
 252  286                  return (gettext("\treopen <pool>\n"));
 253  287          case HELP_SCRUB:
 254      -                return (gettext("\tscrub [-s | -p] <pool> ...\n"));
      288 +                return (gettext("\tscrub [-m|-M|-p|-s] <pool> ...\n"));
      289 +        case HELP_TRIM:
      290 +                return (gettext("\ttrim [-s|-r <rate>] <pool> ...\n"));
 255  291          case HELP_STATUS:
 256  292                  return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
 257  293                      "[count]]\n"));
 258  294          case HELP_UPGRADE:
 259  295                  return (gettext("\tupgrade\n"
 260  296                      "\tupgrade -v\n"
 261  297                      "\tupgrade [-V version] <-a | pool ...>\n"));
 262  298          case HELP_GET:
 263  299                  return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
 264  300                      "<\"all\" | property[,...]> <pool> ...\n"));
 265  301          case HELP_SET:
 266  302                  return (gettext("\tset <property=value> <pool> \n"));
 267  303          case HELP_SPLIT:
 268  304                  return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
 269  305                      "\t    [-o property=value] <pool> <newpool> "
 270  306                      "[<device> ...]\n"));
 271  307          case HELP_REGUID:
 272  308                  return (gettext("\treguid <pool>\n"));
      309 +        case HELP_VDEV_GET:
      310 +                return (gettext("\tvdev-get <property | all> <pool> "
      311 +                    "<vdev name | GUID>\n"));
      312 +        case HELP_VDEV_SET:
      313 +                return (gettext("\tvdev-set <property=value> <pool> "
      314 +                    "<vdev name | GUID>\n"));
      315 +        case HELP_COS_ALLOC:
      316 +                return (gettext("\tcos-alloc <pool> <cos name | GUID>\n"));
      317 +        case HELP_COS_FREE:
      318 +                return (gettext("\tcos-free [-f] <pool> <cos name | GUID>\n"));
      319 +        case HELP_COS_LIST:
      320 +                return (gettext("\tcos-list <pool>\n"));
      321 +        case HELP_COS_GET:
      322 +                return (gettext("\tcos-get <property | all> <pool>"
      323 +                    "<cos name | GUID>\n"));
      324 +        case HELP_COS_SET:
      325 +                return (gettext("\tcos-set <property=value> <pool>"
      326 +                    "<cos name | GUID>\n"));
 273  327          }
 274  328  
 275  329          abort();
 276  330          /* NOTREACHED */
 277  331  }
      332 +/*
      333 + * Check if additional ZFS meta features are enabled.
      334 + */
      335 +static boolean_t
      336 +nexenta_meta_enable()
      337 +{
      338 +        if (getenv("nexenta_meta_enable") == NULL) {
      339 +                (void) fprintf(stderr, gettext("feature not enabled\n"));
      340 +                (void) fprintf(stderr,
      341 +                    gettext("set nexenta_meta_enable to access\n"));
      342 +                return (B_FALSE);
      343 +        }
      344 +        return (B_TRUE);
      345 +}
 278  346  
 279      -
 280  347  /*
 281  348   * Callback routine that will print out a pool property value.
 282  349   */
 283  350  static int
 284  351  print_prop_cb(int prop, void *cb)
 285  352  {
 286  353          FILE *fp = cb;
 287  354  
 288  355          (void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
 289  356  
↓ open down ↓ 114 lines elided ↑ open up ↑
 404  471          return (B_FALSE);
 405  472  }
 406  473  
 407  474  /*
 408  475   * Add a property pair (name, string-value) into a property nvlist.
 409  476   */
 410  477  static int
 411  478  add_prop_list(const char *propname, char *propval, nvlist_t **props,
 412  479      boolean_t poolprop)
 413  480  {
 414      -        zpool_prop_t prop = ZPOOL_PROP_INVAL;
      481 +        zpool_prop_t prop = ZPROP_INVAL;
 415  482          zfs_prop_t fprop;
 416  483          nvlist_t *proplist;
 417  484          const char *normnm;
 418  485          char *strval;
 419  486  
 420  487          if (*props == NULL &&
 421  488              nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
 422  489                  (void) fprintf(stderr,
 423  490                      gettext("internal error: out of memory\n"));
 424  491                  return (1);
 425  492          }
 426  493  
 427  494          proplist = *props;
 428  495  
 429  496          if (poolprop) {
 430  497                  const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
 431  498  
 432      -                if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL &&
      499 +                if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
 433  500                      !zpool_prop_feature(propname)) {
 434  501                          (void) fprintf(stderr, gettext("property '%s' is "
 435  502                              "not a valid pool property\n"), propname);
 436  503                          return (2);
 437  504                  }
 438  505  
 439  506                  /*
 440  507                   * feature@ properties and version should not be specified
 441  508                   * at the same time.
 442  509                   */
 443      -                if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
      510 +                if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
 444  511                      nvlist_exists(proplist, vname)) ||
 445  512                      (prop == ZPOOL_PROP_VERSION &&
 446  513                      prop_list_contains_feature(proplist))) {
 447  514                          (void) fprintf(stderr, gettext("'feature@' and "
 448  515                              "'version' properties cannot be specified "
 449  516                              "together\n"));
 450  517                          return (2);
 451  518                  }
 452  519  
 453  520  
↓ open down ↓ 19 lines elided ↑ open up ↑
 473  540          if (nvlist_add_string(proplist, normnm, propval) != 0) {
 474  541                  (void) fprintf(stderr, gettext("internal "
 475  542                      "error: out of memory\n"));
 476  543                  return (1);
 477  544          }
 478  545  
 479  546          return (0);
 480  547  }
 481  548  
 482  549  /*
      550 + * Add a property pair (name, string-value) into a vdev property nvlist.
      551 + */
      552 +static int
      553 +add_vdev_prop_list(const char *propname, char *propval, nvlist_t **props)
      554 +{
      555 +        vdev_prop_t prop = ZPROP_INVAL;
      556 +        nvlist_t *proplist;
      557 +        const char *normnm;
      558 +
      559 +        if (*props == NULL && nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
      560 +                (void) fprintf(stderr,
      561 +                    gettext("internal error: out of memory\n"));
      562 +                return (1);
      563 +        }
      564 +
      565 +        proplist = *props;
      566 +        if ((prop = vdev_name_to_prop(propname)) == ZPROP_INVAL) {
      567 +                (void) fprintf(stderr, gettext("property '%s' is "
      568 +                    "not a valid vdev property\n"), propname);
      569 +                return (2);
      570 +        }
      571 +        normnm = vdev_prop_to_name(prop);
      572 +
      573 +        if (nvlist_add_string(proplist, normnm, propval) != 0) {
      574 +                (void) fprintf(stderr, gettext("internal "
      575 +                    "error: out of memory\n"));
      576 +                return (1);
      577 +        }
      578 +
      579 +        return (0);
      580 +}
      581 +
      582 +/*
      583 + * Add a property pair (name, string-value) into a cos property nvlist.
      584 + */
      585 +static int
      586 +add_cos_prop_list(const char *propname, char *propval, nvlist_t **props)
      587 +{
      588 +        cos_prop_t prop = ZPROP_INVAL;
      589 +        nvlist_t *proplist;
      590 +        const char *normnm;
      591 +
      592 +        if (*props == NULL && nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
      593 +                (void) fprintf(stderr,
      594 +                    gettext("internal error: out of memory\n"));
      595 +                return (1);
      596 +        }
      597 +
      598 +        proplist = *props;
      599 +        if ((prop = cos_name_to_prop(propname)) == ZPROP_INVAL) {
      600 +                (void) fprintf(stderr, gettext("property '%s' is "
      601 +                    "not a valid cos property\n"), propname);
      602 +                return (2);
      603 +        }
      604 +        normnm = cos_prop_to_name(prop);
      605 +
      606 +        if (nvlist_add_string(proplist, normnm, propval) != 0) {
      607 +                (void) fprintf(stderr, gettext("internal "
      608 +                    "error: out of memory\n"));
      609 +                return (1);
      610 +        }
      611 +
      612 +        return (0);
      613 +}
      614 +
      615 +/*
 483  616   * zpool add [-fn] <pool> <vdev> ...
 484  617   *
 485  618   *      -f      Force addition of devices, even if they appear in use
 486  619   *      -n      Do not add the devices, but display the resulting layout if
 487  620   *              they were to be added.
 488  621   *
 489  622   * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
 490  623   * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
 491  624   * libzfs.
 492  625   */
↓ open down ↓ 97 lines elided ↑ open up ↑
 590  723  
 591  724          nvlist_free(nvroot);
 592  725          zpool_close(zhp);
 593  726  
 594  727          return (ret);
 595  728  }
 596  729  
 597  730  /*
 598  731   * zpool remove  <pool> <vdev> ...
 599  732   *
 600      - * Removes the given vdev from the pool.
      733 + * Removes the given vdev from the pool.  Currently, this supports removing
      734 + * spares, cache, and log devices from the pool.
 601  735   */
 602  736  int
 603  737  zpool_do_remove(int argc, char **argv)
 604  738  {
 605  739          char *poolname;
 606  740          int i, ret = 0;
 607  741          zpool_handle_t *zhp;
 608      -        boolean_t stop = B_FALSE;
 609      -        boolean_t noop = B_FALSE;
 610      -        boolean_t parsable = B_FALSE;
 611      -        char c;
 612  742  
 613      -        /* check options */
 614      -        while ((c = getopt(argc, argv, "nps")) != -1) {
 615      -                switch (c) {
 616      -                case 'n':
 617      -                        noop = B_TRUE;
 618      -                        break;
 619      -                case 'p':
 620      -                        parsable = B_TRUE;
 621      -                        break;
 622      -                case 's':
 623      -                        stop = B_TRUE;
 624      -                        break;
 625      -                case '?':
 626      -                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
 627      -                            optopt);
 628      -                        usage(B_FALSE);
 629      -                }
 630      -        }
      743 +        argc--;
      744 +        argv++;
 631  745  
 632      -        argc -= optind;
 633      -        argv += optind;
 634      -
 635  746          /* get pool name and check number of arguments */
 636  747          if (argc < 1) {
 637  748                  (void) fprintf(stderr, gettext("missing pool name argument\n"));
 638  749                  usage(B_FALSE);
 639  750          }
      751 +        if (argc < 2) {
      752 +                (void) fprintf(stderr, gettext("missing device\n"));
      753 +                usage(B_FALSE);
      754 +        }
 640  755  
 641  756          poolname = argv[0];
 642  757  
 643  758          if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
 644  759                  return (1);
 645  760  
 646      -        if (stop && noop) {
 647      -                (void) fprintf(stderr, gettext("stop request ignored\n"));
 648      -                return (0);
 649      -        }
 650      -
 651      -        if (stop) {
 652      -                if (argc > 1) {
 653      -                        (void) fprintf(stderr, gettext("too many arguments\n"));
 654      -                        usage(B_FALSE);
 655      -                }
 656      -                if (zpool_vdev_remove_cancel(zhp) != 0)
      761 +        for (i = 1; i < argc; i++) {
      762 +                if (zpool_vdev_remove(zhp, argv[i]) != 0)
 657  763                          ret = 1;
 658      -        } else {
 659      -                if (argc < 2) {
 660      -                        (void) fprintf(stderr, gettext("missing device\n"));
 661      -                        usage(B_FALSE);
 662      -                }
 663      -
 664      -                for (i = 1; i < argc; i++) {
 665      -                        if (noop) {
 666      -                                uint64_t size;
 667      -
 668      -                                if (zpool_vdev_indirect_size(zhp, argv[i],
 669      -                                    &size) != 0) {
 670      -                                        ret = 1;
 671      -                                        break;
 672      -                                }
 673      -                                if (parsable) {
 674      -                                        (void) printf("%s %llu\n",
 675      -                                            argv[i], size);
 676      -                                } else {
 677      -                                        char valstr[32];
 678      -                                        zfs_nicenum(size, valstr,
 679      -                                            sizeof (valstr));
 680      -                                        (void) printf("Memory that will be "
 681      -                                            "used after removing %s: %s\n",
 682      -                                            argv[i], valstr);
 683      -                                }
 684      -                        } else {
 685      -                                if (zpool_vdev_remove(zhp, argv[i]) != 0)
 686      -                                        ret = 1;
 687      -                        }
 688      -                }
 689  764          }
 690  765  
 691  766          return (ret);
 692  767  }
 693  768  
 694  769  /*
 695  770   * zpool labelclear [-f] <vdev>
 696  771   *
 697  772   *      -f      Force clearing the label for the vdevs which are members of
 698  773   *              the exported or foreign pools.
↓ open down ↓ 558 lines elided ↑ open up ↑
1257 1332                  /*
1258 1333                   * As a special case, check for use of '/' in the name, and
1259 1334                   * direct the user to use 'zfs destroy' instead.
1260 1335                   */
1261 1336                  if (strchr(pool, '/') != NULL)
1262 1337                          (void) fprintf(stderr, gettext("use 'zfs destroy' to "
1263 1338                              "destroy a dataset\n"));
1264 1339                  return (1);
1265 1340          }
1266 1341  
     1342 +        ret = zfs_check_krrp(g_zfs, argv[0]);
     1343 +        /*
     1344 +         * ENOTSUP means that autosnaper doesn't handle this pool.
     1345 +         */
     1346 +        if (ret != ENOTSUP) {
     1347 +                if (ret == ECHILD || ret == EBUSY || ret == EUSERS)
     1348 +                        ret = EBUSY;
     1349 +
     1350 +                if (ret) {
     1351 +                        (void) zpool_standard_error(g_zfs,
     1352 +                            ret, gettext("cannnot destroy pool because "
     1353 +                            "of krrp"));
     1354 +                        zpool_close(zhp);
     1355 +                        ret = 1;
     1356 +                        return (ret);
     1357 +                }
     1358 +        } else {
     1359 +                ret = 0;
     1360 +        }
     1361 +
1267 1362          if (zpool_disable_datasets(zhp, force) != 0) {
1268 1363                  (void) fprintf(stderr, gettext("could not destroy '%s': "
1269 1364                      "could not unmount datasets\n"), zpool_get_name(zhp));
1270 1365                  return (1);
1271 1366          }
1272 1367  
1273 1368          /* The history must be logged as part of the export */
1274 1369          log_history = B_FALSE;
1275 1370  
1276 1371          ret = (zpool_destroy(zhp, history_str) != 0);
↓ open down ↓ 10 lines elided ↑ open up ↑
1287 1382   *
1288 1383   * Export the given pools.  By default, the command will attempt to cleanly
1289 1384   * unmount any active datasets within the pool.  If the '-f' flag is specified,
1290 1385   * then the datasets will be forcefully unmounted.
1291 1386   */
1292 1387  int
1293 1388  zpool_do_export(int argc, char **argv)
1294 1389  {
1295 1390          boolean_t force = B_FALSE;
1296 1391          boolean_t hardforce = B_FALSE;
     1392 +        boolean_t saveconfig = B_FALSE;
1297 1393          int c;
     1394 +        int n_threads = sysconf(_SC_NPROCESSORS_ONLN) * 2;
1298 1395          zpool_handle_t *zhp;
1299 1396          int ret;
1300 1397          int i;
1301 1398  
1302 1399          /* check options */
1303      -        while ((c = getopt(argc, argv, "fF")) != -1) {
     1400 +        while ((c = getopt(argc, argv, ":fFct:")) != -1) {
1304 1401                  switch (c) {
1305 1402                  case 'f':
1306 1403                          force = B_TRUE;
1307 1404                          break;
1308 1405                  case 'F':
1309 1406                          hardforce = B_TRUE;
1310 1407                          break;
     1408 +                case 'c':
     1409 +                        saveconfig = B_TRUE;
     1410 +                        break;
     1411 +                case 't':
     1412 +                        n_threads = atoi(optarg);
     1413 +                        break;
1311 1414                  case '?':
1312 1415                          (void) fprintf(stderr, gettext("invalid option '%c'\n"),
1313 1416                              optopt);
1314 1417                          usage(B_FALSE);
     1418 +                        break;
     1419 +                case ':':
     1420 +                        (void) fprintf(stderr, gettext("missing argument "
     1421 +                            "for option '%c'\n"), optopt);
     1422 +                        usage(B_FALSE);
     1423 +                        break;
1315 1424                  }
1316 1425          }
1317 1426  
1318 1427          argc -= optind;
1319 1428          argv += optind;
1320 1429  
1321 1430          /* check arguments */
1322 1431          if (argc < 1) {
1323 1432                  (void) fprintf(stderr, gettext("missing pool argument\n"));
1324 1433                  usage(B_FALSE);
1325 1434          }
1326 1435  
1327 1436          ret = 0;
1328 1437          for (i = 0; i < argc; i++) {
1329 1438                  if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1330 1439                          ret = 1;
1331 1440                          continue;
1332 1441                  }
1333 1442  
1334      -                if (zpool_disable_datasets(zhp, force) != 0) {
     1443 +                ret = zfs_check_krrp(g_zfs, argv[0]);
     1444 +                /*
     1445 +                 * ENOTSUP means that autosnaper doesn't handle this pool.
     1446 +                 */
     1447 +                if (ret != ENOTSUP) {
     1448 +                        if (ret == ECHILD || ret == EBUSY || ret == EUSERS)
     1449 +                                ret = EBUSY;
     1450 +
     1451 +                        if (ret) {
     1452 +                                (void) zpool_standard_error(g_zfs,
     1453 +                                    ret, gettext("cannnot export pool because "
     1454 +                                    "of krrp"));
     1455 +                                zpool_close(zhp);
     1456 +                                ret = 1;
     1457 +                                continue;
     1458 +                        }
     1459 +                } else {
     1460 +                        ret = 0;
     1461 +                }
     1462 +
     1463 +                if (zpool_disable_datasets_ex(zhp, force, n_threads) != 0) {
1335 1464                          ret = 1;
1336 1465                          zpool_close(zhp);
1337 1466                          continue;
1338 1467                  }
1339 1468  
1340 1469                  /* The history must be logged as part of the export */
1341 1470                  log_history = B_FALSE;
1342 1471  
1343 1472                  if (hardforce) {
1344      -                        if (zpool_export_force(zhp, history_str) != 0)
     1473 +                        if (zpool_export_force(zhp, saveconfig, history_str)
     1474 +                            != 0)
1345 1475                                  ret = 1;
1346      -                } else if (zpool_export(zhp, force, history_str) != 0) {
     1476 +                } else if (zpool_export(zhp, force, saveconfig, history_str)
     1477 +                    != 0) {
1347 1478                          ret = 1;
1348 1479                  }
1349 1480  
1350 1481                  zpool_close(zhp);
1351 1482          }
1352 1483  
1353 1484          return (ret);
1354 1485  }
1355 1486  
1356 1487  /*
↓ open down ↓ 95 lines elided ↑ open up ↑
1452 1583  {
1453 1584          nvlist_t **child;
1454 1585          uint_t c, children;
1455 1586          pool_scan_stat_t *ps = NULL;
1456 1587          vdev_stat_t *vs;
1457 1588          char rbuf[6], wbuf[6], cbuf[6];
1458 1589          char *vname;
1459 1590          uint64_t notpresent;
1460 1591          spare_cbdata_t cb;
1461 1592          const char *state;
1462      -        char *type;
1463 1593  
1464 1594          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1465 1595              &child, &children) != 0)
1466 1596                  children = 0;
1467 1597  
1468 1598          verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1469 1599              (uint64_t **)&vs, &c) == 0);
1470 1600  
1471      -        verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1472      -
1473      -        if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
1474      -                return;
1475      -
1476 1601          state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1477 1602          if (isspare) {
1478 1603                  /*
1479 1604                   * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1480 1605                   * online drives.
1481 1606                   */
1482 1607                  if (vs->vs_aux == VDEV_AUX_SPARED)
1483 1608                          state = "INUSE";
1484 1609                  else if (vs->vs_state == VDEV_STATE_HEALTHY)
1485 1610                          state = "AVAIL";
↓ open down ↓ 69 lines elided ↑ open up ↑
1555 1680                          break;
1556 1681  
1557 1682                  case VDEV_AUX_EXTERNAL:
1558 1683                          (void) printf(gettext("external device fault"));
1559 1684                          break;
1560 1685  
1561 1686                  case VDEV_AUX_SPLIT_POOL:
1562 1687                          (void) printf(gettext("split into new pool"));
1563 1688                          break;
1564 1689  
1565      -                case VDEV_AUX_CHILDREN_OFFLINE:
1566      -                        (void) printf(gettext("all children offline"));
1567      -                        break;
1568      -
1569 1690                  default:
1570 1691                          (void) printf(gettext("corrupted data"));
1571 1692                          break;
1572 1693                  }
1573 1694          }
1574 1695  
1575 1696          (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1576 1697              (uint64_t **)&ps, &c);
1577 1698  
1578      -        if (ps && ps->pss_state == DSS_SCANNING &&
1579      -            vs->vs_scan_processed != 0 && children == 0) {
     1699 +        if (ps != NULL && (ps->pss_state == DSS_SCANNING ||
     1700 +            ps->pss_state == DSS_FINISHING) && vs->vs_scan_processed != 0 &&
     1701 +            children == 0) {
1580 1702                  (void) printf(gettext("  (%s)"),
1581 1703                      (ps->pss_func == POOL_SCAN_RESILVER) ?
1582 1704                      "resilvering" : "repairing");
1583 1705          }
1584 1706  
1585 1707          (void) printf("\n");
1586 1708  
1587 1709          for (c = 0; c < children; c++) {
1588      -                uint64_t islog = B_FALSE, ishole = B_FALSE;
     1710 +                uint64_t islog = B_FALSE, ishole = B_FALSE, isspecial = B_FALSE;
1589 1711  
1590 1712                  /* Don't print logs or holes here */
1591 1713                  (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1592 1714                      &islog);
1593 1715                  (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1594 1716                      &ishole);
1595      -                if (islog || ishole)
     1717 +                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL,
     1718 +                    &isspecial);
     1719 +                if (islog || ishole || isspecial)
1596 1720                          continue;
1597 1721                  vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1598 1722                  print_status_config(zhp, vname, child[c],
1599 1723                      namewidth, depth + 2, isspare);
1600 1724                  free(vname);
1601 1725          }
1602 1726  }
1603 1727  
1604 1728  
1605 1729  /*
↓ open down ↓ 40 lines elided ↑ open up ↑
1646 1770                          break;
1647 1771  
1648 1772                  case VDEV_AUX_UNSUP_FEAT:
1649 1773                          (void) printf(gettext("unsupported feature(s)"));
1650 1774                          break;
1651 1775  
1652 1776                  case VDEV_AUX_ERR_EXCEEDED:
1653 1777                          (void) printf(gettext("too many errors"));
1654 1778                          break;
1655 1779  
1656      -                case VDEV_AUX_CHILDREN_OFFLINE:
1657      -                        (void) printf(gettext("all children offline"));
1658      -                        break;
1659      -
1660 1780                  default:
1661 1781                          (void) printf(gettext("corrupted data"));
1662 1782                          break;
1663 1783                  }
1664 1784          }
1665 1785          (void) printf("\n");
1666 1786  
1667 1787          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1668 1788              &child, &children) != 0)
1669 1789                  return;
1670 1790  
1671 1791          for (c = 0; c < children; c++) {
1672      -                uint64_t is_log = B_FALSE;
     1792 +                uint64_t is_log = B_FALSE, is_special = B_FALSE;
1673 1793  
1674 1794                  (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1675 1795                      &is_log);
1676      -                if (is_log)
     1796 +                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL,
     1797 +                    &is_special);
     1798 +                if (is_log || is_special)
1677 1799                          continue;
1678 1800  
1679 1801                  vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1680 1802                  print_import_config(vname, child[c], namewidth, depth + 2);
1681 1803                  free(vname);
1682 1804          }
1683 1805  
1684 1806          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1685 1807              &child, &children) == 0) {
1686 1808                  (void) printf(gettext("\tcache\n"));
↓ open down ↓ 47 lines elided ↑ open up ↑
1734 1856                  if (verbose)
1735 1857                          print_status_config(zhp, name, child[c], namewidth,
1736 1858                              2, B_FALSE);
1737 1859                  else
1738 1860                          print_import_config(name, child[c], namewidth, 2);
1739 1861                  free(name);
1740 1862          }
1741 1863  }
1742 1864  
1743 1865  /*
     1866 + * Print special vdevs.
     1867 + * Special vdevs are recorded as top level vdevs in the main pool child array
     1868 + * but with "is_special" set to 1. We use either print_status_config() or
     1869 + * print_import_config() to print the top level logs then any log
     1870 + * children (eg mirrored slogs) are printed recursively - which
     1871 + * works because only the top level vdev is marked "is_special"
     1872 + */
     1873 +static void
     1874 +print_special(zpool_handle_t *zhp, nvlist_t *nv, int namewidth,
     1875 +    boolean_t verbose)
     1876 +{
     1877 +        uint_t c, children;
     1878 +        nvlist_t **child;
     1879 +
     1880 +        if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
     1881 +            &children) != 0)
     1882 +                return;
     1883 +
     1884 +        (void) printf(gettext("\tspecial\n"));
     1885 +
     1886 +        for (c = 0; c < children; c++) {
     1887 +                uint64_t is_special = B_FALSE;
     1888 +                char *name;
     1889 +
     1890 +                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_SPECIAL,
     1891 +                    &is_special);
     1892 +                if (!is_special)
     1893 +                        continue;
     1894 +                name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
     1895 +                if (verbose)
     1896 +                        print_status_config(zhp, name, child[c], namewidth,
     1897 +                            2, B_FALSE);
     1898 +                else
     1899 +                        print_import_config(name, child[c], namewidth, 2);
     1900 +                free(name);
     1901 +        }
     1902 +}
     1903 +
     1904 +/*
1744 1905   * Display the status for the given pool.
1745 1906   */
1746 1907  static void
1747 1908  show_import(nvlist_t *config)
1748 1909  {
1749 1910          uint64_t pool_state;
1750 1911          vdev_stat_t *vs;
1751 1912          char *name;
1752 1913          uint64_t guid;
1753 1914          char *msgid;
↓ open down ↓ 194 lines elided ↑ open up ↑
1948 2109                  (void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1949 2110                      msgid);
1950 2111  
1951 2112          (void) printf(gettext(" config:\n\n"));
1952 2113  
1953 2114          namewidth = max_width(NULL, nvroot, 0, 0);
1954 2115          if (namewidth < 10)
1955 2116                  namewidth = 10;
1956 2117  
1957 2118          print_import_config(name, nvroot, namewidth, 0);
     2119 +        if (num_special(nvroot) > 0)
     2120 +                print_special(NULL, nvroot, namewidth, B_FALSE);
     2121 +
1958 2122          if (num_logs(nvroot) > 0)
1959 2123                  print_logs(NULL, nvroot, namewidth, B_FALSE);
1960 2124  
1961 2125          if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1962 2126                  (void) printf(gettext("\n\tAdditional devices are known to "
1963 2127                      "be part of this pool, though their\n\texact "
1964 2128                      "configuration cannot be determined.\n"));
1965 2129          }
1966 2130  }
1967 2131  
1968 2132  /*
1969 2133   * Perform the import for the given configuration.  This passes the heavy
1970 2134   * lifting off to zpool_import_props(), and then mounts the datasets contained
1971 2135   * within the pool.
1972 2136   */
1973 2137  static int
1974 2138  do_import(nvlist_t *config, const char *newname, const char *mntopts,
1975      -    nvlist_t *props, int flags)
     2139 +    nvlist_t *props, int flags, int n_threads)
1976 2140  {
1977 2141          zpool_handle_t *zhp;
1978 2142          char *name;
1979 2143          uint64_t state;
1980 2144          uint64_t version;
1981 2145  
1982 2146          verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1983 2147              &name) == 0);
1984 2148  
1985 2149          verify(nvlist_lookup_uint64(config,
↓ open down ↓ 43 lines elided ↑ open up ↑
2029 2193                  return (1);
2030 2194  
2031 2195          if (newname != NULL)
2032 2196                  name = (char *)newname;
2033 2197  
2034 2198          if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
2035 2199                  return (1);
2036 2200  
2037 2201          if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
2038 2202              !(flags & ZFS_IMPORT_ONLY) &&
2039      -            zpool_enable_datasets(zhp, mntopts, 0) != 0) {
     2203 +            zpool_enable_datasets_ex(zhp, mntopts, 0, n_threads) != 0) {
2040 2204                  zpool_close(zhp);
2041 2205                  return (1);
2042 2206          }
2043 2207  
2044 2208          zpool_close(zhp);
2045 2209          return (0);
2046 2210  }
2047 2211  
2048 2212  /*
2049 2213   * zpool import [-d dir] [-D]
2050      - *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
     2214 + *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-t num]
2051 2215   *              [-d dir | -c cachefile] [-f] -a
2052      - *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
     2216 + *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-t num]
2053 2217   *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
2054 2218   *
2055 2219   *       -c     Read pool information from a cachefile instead of searching
2056 2220   *              devices.
2057 2221   *
2058 2222   *       -d     Scan in a specific directory, other than /dev/dsk.  More than
2059 2223   *              one directory can be specified using multiple '-d' options.
2060 2224   *
2061 2225   *       -D     Scan for previously destroyed pools or import all or only
2062 2226   *              specified destroyed pools.
2063 2227   *
2064 2228   *       -R     Temporarily import the pool, with all mountpoints relative to
2065 2229   *              the given root.  The pool will remain exported when the machine
2066 2230   *              is rebooted.
2067 2231   *
2068 2232   *       -V     Import even in the presence of faulted vdevs.  This is an
2069      - *              intentionally undocumented option for testing purposes, and
2070      - *              treats the pool configuration as complete, leaving any bad
     2233 + *              intentionally undocumented option for testing purposes, and
     2234 + *              treats the pool configuration as complete, leaving any bad
2071 2235   *              vdevs in the FAULTED state. In other words, it does verbatim
2072 2236   *              import.
2073 2237   *
2074 2238   *       -f     Force import, even if it appears that the pool is active.
2075 2239   *
2076 2240   *       -F     Attempt rewind if necessary.
2077 2241   *
2078 2242   *       -n     See if rewind would work, but don't actually rewind.
2079 2243   *
2080 2244   *       -N     Import the pool but don't mount datasets.
2081 2245   *
     2246 + *       -t     Use up to num threads to mount datasets in parallel.
     2247 + *
2082 2248   *       -T     Specify a starting txg to use for import. This option is
2083      - *              intentionally undocumented option for testing purposes.
     2249 + *              intentionally undocumented option for testing purposes.
2084 2250   *
2085 2251   *       -a     Import all pools found.
2086 2252   *
2087 2253   *       -o     Set property=value and/or temporary mount options (without '=').
2088 2254   *
2089 2255   * The import command scans for pools to import, and import pools based on pool
2090 2256   * name and GUID.  The pool can also be renamed as part of the import process.
2091 2257   */
2092 2258  int
2093 2259  zpool_do_import(int argc, char **argv)
↓ open down ↓ 16 lines elided ↑ open up ↑
2110 2276          nvlist_t *props = NULL;
2111 2277          boolean_t first;
2112 2278          int flags = ZFS_IMPORT_NORMAL;
2113 2279          uint32_t rewind_policy = ZPOOL_NO_REWIND;
2114 2280          boolean_t dryrun = B_FALSE;
2115 2281          boolean_t do_rewind = B_FALSE;
2116 2282          boolean_t xtreme_rewind = B_FALSE;
2117 2283          uint64_t pool_state, txg = -1ULL;
2118 2284          char *cachefile = NULL;
2119 2285          importargs_t idata = { 0 };
     2286 +        unsigned long n_threads = sysconf(_SC_NPROCESSORS_ONLN) * 2;
2120 2287          char *endptr;
2121 2288  
2122 2289          /* check options */
2123      -        while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
     2290 +        while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:t:T:VX")) != -1) {
2124 2291                  switch (c) {
2125 2292                  case 'a':
2126 2293                          do_all = B_TRUE;
2127 2294                          break;
2128 2295                  case 'c':
2129 2296                          cachefile = optarg;
2130 2297                          break;
2131 2298                  case 'd':
2132 2299                          if (searchdirs == NULL) {
2133 2300                                  searchdirs = safe_malloc(sizeof (char *));
↓ open down ↓ 41 lines elided ↑ open up ↑
2175 2342                              ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
2176 2343                                  goto error;
2177 2344                          if (nvlist_lookup_string(props,
2178 2345                              zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
2179 2346                              &propval) == 0)
2180 2347                                  break;
2181 2348                          if (add_prop_list(zpool_prop_to_name(
2182 2349                              ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2183 2350                                  goto error;
2184 2351                          break;
     2352 +                case 't':
     2353 +                        errno = 0;
     2354 +                        n_threads = strtol(optarg, &endptr, 10);
     2355 +                        if (errno != 0 || *endptr != '\0') {
     2356 +                                (void) fprintf(stderr,
     2357 +                                    gettext("invalid num value\n"));
     2358 +                                usage(B_FALSE);
     2359 +                        }
     2360 +                        break;
2185 2361                  case 'T':
2186 2362                          errno = 0;
2187 2363                          txg = strtoull(optarg, &endptr, 0);
2188 2364                          if (errno != 0 || *endptr != '\0') {
2189 2365                                  (void) fprintf(stderr,
2190 2366                                      gettext("invalid txg value\n"));
2191 2367                                  usage(B_FALSE);
2192 2368                          }
2193 2369                          rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
2194 2370                          break;
↓ open down ↓ 102 lines elided ↑ open up ↑
2297 2473                   */
2298 2474                  idata.unique = B_TRUE;
2299 2475          }
2300 2476  
2301 2477  
2302 2478          idata.path = searchdirs;
2303 2479          idata.paths = nsearch;
2304 2480          idata.poolname = searchname;
2305 2481          idata.guid = searchguid;
2306 2482          idata.cachefile = cachefile;
2307      -        idata.policy = policy;
2308 2483  
2309 2484          pools = zpool_search_import(g_zfs, &idata);
2310 2485  
2311 2486          if (pools != NULL && idata.exists &&
2312 2487              (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
2313 2488                  (void) fprintf(stderr, gettext("cannot import '%s': "
2314 2489                      "a pool with that name already exists\n"),
2315 2490                      argv[0]);
2316 2491                  (void) fprintf(stderr, gettext("use the form '%s "
2317 2492                      "<pool | id> <newpool>' to give it a new name\n"),
↓ open down ↓ 44 lines elided ↑ open up ↑
2362 2537                      policy) == 0);
2363 2538  
2364 2539                  if (argc == 0) {
2365 2540                          if (first)
2366 2541                                  first = B_FALSE;
2367 2542                          else if (!do_all)
2368 2543                                  (void) printf("\n");
2369 2544  
2370 2545                          if (do_all) {
2371 2546                                  err |= do_import(config, NULL, mntopts,
2372      -                                    props, flags);
     2547 +                                    props, flags, n_threads);
2373 2548                          } else {
2374 2549                                  show_import(config);
2375 2550                          }
2376 2551                  } else if (searchname != NULL) {
2377 2552                          char *name;
2378 2553  
2379 2554                          /*
2380 2555                           * We are searching for a pool based on name.
2381 2556                           */
2382 2557                          verify(nvlist_lookup_string(config,
↓ open down ↓ 28 lines elided ↑ open up ↑
2411 2586           * If we were searching for a specific pool, verify that we found a
2412 2587           * pool, and then do the import.
2413 2588           */
2414 2589          if (argc != 0 && err == 0) {
2415 2590                  if (found_config == NULL) {
2416 2591                          (void) fprintf(stderr, gettext("cannot import '%s': "
2417 2592                              "no such pool available\n"), argv[0]);
2418 2593                          err = B_TRUE;
2419 2594                  } else {
2420 2595                          err |= do_import(found_config, argc == 1 ? NULL :
2421      -                            argv[1], mntopts, props, flags);
     2596 +                            argv[1], mntopts, props, flags, n_threads);
2422 2597                  }
2423 2598          }
2424 2599  
2425 2600          /*
2426 2601           * If we were just looking for pools, report an error if none were
2427 2602           * found.
2428 2603           */
2429 2604          if (argc == 0 && first)
2430 2605                  (void) fprintf(stderr,
2431 2606                      gettext("no pools available to import\n"));
↓ open down ↓ 14 lines elided ↑ open up ↑
2446 2621          zpool_list_t *cb_list;
2447 2622  } iostat_cbdata_t;
2448 2623  
2449 2624  static void
2450 2625  print_iostat_separator(iostat_cbdata_t *cb)
2451 2626  {
2452 2627          int i = 0;
2453 2628  
2454 2629          for (i = 0; i < cb->cb_namewidth; i++)
2455 2630                  (void) printf("-");
2456      -        (void) printf("  -----  -----  -----  -----  -----  -----\n");
     2631 +        (void) printf("  -----  -----  -----  -----  -----  -----  -----  "
     2632 +            "-----\n");
2457 2633  }
2458 2634  
2459 2635  static void
2460 2636  print_iostat_header(iostat_cbdata_t *cb)
2461 2637  {
2462      -        (void) printf("%*s     capacity     operations    bandwidth\n",
2463      -            cb->cb_namewidth, "");
2464      -        (void) printf("%-*s  alloc   free   read  write   read  write\n",
2465      -            cb->cb_namewidth, "pool");
     2638 +        (void) printf("%*s     capacity     operations    bandwidth      "
     2639 +            "latency\n", cb->cb_namewidth, "");
     2640 +        (void) printf("%-*s  alloc   free   read  write   read  write   read  "
     2641 +            "write\n", cb->cb_namewidth, "pool");
2466 2642          print_iostat_separator(cb);
2467 2643  }
2468 2644  
2469 2645  /*
2470 2646   * Display a single statistic.
2471 2647   */
2472 2648  static void
2473 2649  print_one_stat(uint64_t value)
2474 2650  {
2475 2651          char buf[64];
2476 2652  
2477 2653          zfs_nicenum(value, buf, sizeof (buf));
2478 2654          (void) printf("  %5s", buf);
2479 2655  }
2480 2656  
2481 2657  /*
     2658 + * Display latency statistic (extra care needed)
     2659 + */
     2660 +static void
     2661 +print_one_latency_stat(uint64_t iotime, uint64_t ops)
     2662 +{
     2663 +        char buf[64];
     2664 +        double value = 0.0; /* latency in milliseconds */
     2665 +
     2666 +        if (ops != 0) {
     2667 +                value = (double)iotime;
     2668 +                value /= (double)ops;
     2669 +                value /= (double)(MICROSEC / MILLISEC);
     2670 +        }
     2671 +
     2672 +        (void) sprintf(buf, "%.2f", value);
     2673 +        (void) printf("  %5s", buf);
     2674 +}
     2675 +
     2676 +/*
2482 2677   * Print out all the statistics for the given vdev.  This can either be the
2483 2678   * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2484 2679   * is a verbose output, and we don't want to display the toplevel pool stats.
2485 2680   */
2486 2681  void
2487 2682  print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2488 2683      nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2489 2684  {
2490 2685          nvlist_t **oldchild, **newchild;
2491 2686          uint_t c, children;
2492 2687          vdev_stat_t *oldvs, *newvs;
2493 2688          vdev_stat_t zerovs = { 0 };
2494 2689          uint64_t tdelta;
2495 2690          double scale;
2496 2691          char *vname;
2497 2692  
2498      -        if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
2499      -                return;
2500      -
2501 2693          if (oldnv != NULL) {
2502 2694                  verify(nvlist_lookup_uint64_array(oldnv,
2503 2695                      ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2504 2696          } else {
2505 2697                  oldvs = &zerovs;
2506 2698          }
2507 2699  
2508 2700          verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2509 2701              (uint64_t **)&newvs, &c) == 0);
2510 2702  
↓ open down ↓ 23 lines elided ↑ open up ↑
2534 2726  
2535 2727          print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2536 2728              oldvs->vs_ops[ZIO_TYPE_WRITE])));
2537 2729  
2538 2730          print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2539 2731              oldvs->vs_bytes[ZIO_TYPE_READ])));
2540 2732  
2541 2733          print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2542 2734              oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2543 2735  
     2736 +        /*
     2737 +         * No scale needed here since we are dividing in
     2738 +         * print_one_latency_stat()
     2739 +         */
     2740 +
     2741 +        print_one_latency_stat(
     2742 +            newvs->vs_iotime[ZIO_TYPE_READ] - oldvs->vs_iotime[ZIO_TYPE_READ],
     2743 +            newvs->vs_ops[ZIO_TYPE_READ] - oldvs->vs_ops[ZIO_TYPE_READ]);
     2744 +
     2745 +        print_one_latency_stat(
     2746 +            newvs->vs_iotime[ZIO_TYPE_WRITE] - oldvs->vs_iotime[ZIO_TYPE_WRITE],
     2747 +            newvs->vs_ops[ZIO_TYPE_WRITE] - oldvs->vs_ops[ZIO_TYPE_WRITE]);
     2748 +
2544 2749          (void) printf("\n");
2545 2750  
2546 2751          if (!cb->cb_verbose)
2547 2752                  return;
2548 2753  
2549 2754          if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2550 2755              &newchild, &children) != 0)
2551 2756                  return;
2552 2757  
2553 2758          if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2554 2759              &oldchild, &c) != 0)
2555 2760                  return;
2556 2761  
2557 2762          for (c = 0; c < children; c++) {
2558      -                uint64_t ishole = B_FALSE, islog = B_FALSE;
     2763 +                uint64_t ishole = B_FALSE, islog = B_FALSE, isspec = B_FALSE;
2559 2764  
2560 2765                  (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2561 2766                      &ishole);
2562 2767  
2563 2768                  (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2564 2769                      &islog);
2565 2770  
2566      -                if (ishole || islog)
     2771 +                (void) nvlist_lookup_uint64(newchild[c],
     2772 +                    ZPOOL_CONFIG_IS_SPECIAL, &isspec);
     2773 +
     2774 +                if (ishole || islog || isspec)
2567 2775                          continue;
2568 2776  
2569 2777                  vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2570 2778                  print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2571 2779                      newchild[c], cb, depth + 2);
2572 2780                  free(vname);
2573 2781          }
2574 2782  
2575 2783          /*
2576 2784           * Log device section
↓ open down ↓ 10 lines elided ↑ open up ↑
2587 2795  
2588 2796                          if (islog) {
2589 2797                                  vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2590 2798                                      B_FALSE);
2591 2799                                  print_vdev_stats(zhp, vname, oldnv ?
2592 2800                                      oldchild[c] : NULL, newchild[c],
2593 2801                                      cb, depth + 2);
2594 2802                                  free(vname);
2595 2803                          }
2596 2804                  }
     2805 +        }
2597 2806  
     2807 +        /*
     2808 +         * Special device section
     2809 +         */
     2810 +
     2811 +        if (num_special(newnv) > 0) {
     2812 +                (void) printf("%-*s      -      -      -      -      -      "
     2813 +                    "-\n", cb->cb_namewidth, "special");
     2814 +
     2815 +                for (c = 0; c < children; c++) {
     2816 +                        uint64_t isspec = B_FALSE;
     2817 +                        (void) nvlist_lookup_uint64(newchild[c],
     2818 +                            ZPOOL_CONFIG_IS_SPECIAL, &isspec);
     2819 +
     2820 +                        if (isspec) {
     2821 +                                vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
     2822 +                                    B_FALSE);
     2823 +                                print_vdev_stats(zhp, vname, oldnv ?
     2824 +                                    oldchild[c] : NULL, newchild[c],
     2825 +                                    cb, depth + 2);
     2826 +                                free(vname);
     2827 +                        }
     2828 +                }
2598 2829          }
2599 2830  
2600 2831          /*
2601 2832           * Include level 2 ARC devices in iostat output
2602 2833           */
2603 2834          if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2604 2835              &newchild, &children) != 0)
2605 2836                  return;
2606 2837  
2607 2838          if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
↓ open down ↓ 489 lines elided ↑ open up ↑
3097 3328          boolean_t haslog = B_FALSE;
3098 3329          char *dashes = "%-*s      -      -      -         -      -      -\n";
3099 3330  
3100 3331          verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
3101 3332              (uint64_t **)&vs, &c) == 0);
3102 3333  
3103 3334          if (name != NULL) {
3104 3335                  boolean_t toplevel = (vs->vs_space != 0);
3105 3336                  uint64_t cap;
3106 3337  
3107      -                if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
3108      -                        return;
3109      -
3110 3338                  if (scripted)
3111 3339                          (void) printf("\t%s", name);
3112 3340                  else if (strlen(name) + depth > cb->cb_namewidth)
3113 3341                          (void) printf("%*s%s", depth, "", name);
3114 3342                  else
3115 3343                          (void) printf("%*s%s%*s", depth, "", name,
3116 3344                              (int)(cb->cb_namewidth - strlen(name) - depth), "");
3117 3345  
3118 3346                  /*
3119 3347                   * Print the properties for the individual vdevs. Some
↓ open down ↓ 111 lines elided ↑ open up ↑
3231 3459   *      -p      Diplay values in parsable (exact) format.
3232 3460   *      -T      Display a timestamp in date(1) or Unix format
3233 3461   *
3234 3462   * List all pools in the system, whether or not they're healthy.  Output space
3235 3463   * statistics for each one, as well as health status summary.
3236 3464   */
3237 3465  int
3238 3466  zpool_do_list(int argc, char **argv)
3239 3467  {
3240 3468          int c;
3241      -        int ret;
     3469 +        int ret = 0;
3242 3470          list_cbdata_t cb = { 0 };
3243 3471          static char default_props[] =
3244 3472              "name,size,allocated,free,expandsize,fragmentation,capacity,"
3245 3473              "dedupratio,health,altroot";
3246 3474          char *props = default_props;
3247 3475          unsigned long interval = 0, count = 0;
3248 3476          zpool_list_t *list;
3249 3477          boolean_t first = B_TRUE;
3250 3478  
3251 3479          /* check options */
↓ open down ↓ 723 lines elided ↑ open up ↑
3975 4203                  (void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3976 4204                      "currently unavailable\n"), zpool_get_name(zhp));
3977 4205                  return (1);
3978 4206          }
3979 4207  
3980 4208          err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
3981 4209  
3982 4210          return (err != 0);
3983 4211  }
3984 4212  
     4213 +typedef struct trim_cbdata {
     4214 +        boolean_t       cb_start;
     4215 +        uint64_t        cb_rate;
     4216 +} trim_cbdata_t;
     4217 +
     4218 +int
     4219 +trim_callback(zpool_handle_t *zhp, void *data)
     4220 +{
     4221 +        trim_cbdata_t *cb = data;
     4222 +        int err;
     4223 +
     4224 +        /*
     4225 +         * Ignore faulted pools.
     4226 +         */
     4227 +        if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
     4228 +                (void) fprintf(stderr, gettext("cannot trim '%s': pool is "
     4229 +                    "currently unavailable\n"), zpool_get_name(zhp));
     4230 +                return (1);
     4231 +        }
     4232 +
     4233 +        err = zpool_trim(zhp, cb->cb_start, cb->cb_rate);
     4234 +
     4235 +        return (err != 0);
     4236 +}
     4237 +
3985 4238  /*
3986 4239   * zpool scrub [-s | -p] <pool> ...
3987 4240   *
3988 4241   *      -s      Stop.  Stops any in-progress scrub.
3989 4242   *      -p      Pause. Pause in-progress scrub.
3990 4243   */
3991 4244  int
3992 4245  zpool_do_scrub(int argc, char **argv)
3993 4246  {
3994 4247          int c;
3995 4248          scrub_cbdata_t cb;
3996 4249  
3997 4250          cb.cb_type = POOL_SCAN_SCRUB;
3998 4251          cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
3999 4252  
4000 4253          /* check options */
4001      -        while ((c = getopt(argc, argv, "sp")) != -1) {
     4254 +        while ((c = getopt(argc, argv, "mMps")) != -1) {
4002 4255                  switch (c) {
4003 4256                  case 's':
4004      -                        cb.cb_type = POOL_SCAN_NONE;
     4257 +                        if (cb.cb_type != POOL_SCAN_SCRUB) {
     4258 +                                (void) fprintf(stderr,
     4259 +                                    gettext("incompatible options\n"));
     4260 +                                usage(B_FALSE);
     4261 +                        } else
     4262 +                                cb.cb_type = POOL_SCAN_NONE;
4005 4263                          break;
     4264 +                case 'M':
     4265 +                        if (cb.cb_type != POOL_SCAN_SCRUB) {
     4266 +                                (void) fprintf(stderr,
     4267 +                                    gettext("incompatible options\n"));
     4268 +                                usage(B_FALSE);
     4269 +                        } else
     4270 +                                cb.cb_type = POOL_SCAN_MOS;
     4271 +                        break;
     4272 +                case 'm':
     4273 +                        if (cb.cb_type != POOL_SCAN_SCRUB) {
     4274 +                                (void) fprintf(stderr,
     4275 +                                    gettext("incompatible options\n"));
     4276 +                                usage(B_FALSE);
     4277 +                        } else
     4278 +                                cb.cb_type = POOL_SCAN_META;
     4279 +                        break;
4006 4280                  case 'p':
4007 4281                          cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
4008 4282                          break;
4009 4283                  case '?':
4010 4284                          (void) fprintf(stderr, gettext("invalid option '%c'\n"),
4011 4285                              optopt);
4012 4286                          usage(B_FALSE);
4013 4287                  }
4014 4288          }
4015 4289  
↓ open down ↓ 10 lines elided ↑ open up ↑
4026 4300          argv += optind;
4027 4301  
4028 4302          if (argc < 1) {
4029 4303                  (void) fprintf(stderr, gettext("missing pool name argument\n"));
4030 4304                  usage(B_FALSE);
4031 4305          }
4032 4306  
4033 4307          return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
4034 4308  }
4035 4309  
     4310 +/*
     4311 + * zpool trim [-s|-r <rate>] <pool> ...
     4312 + *
     4313 + *      -s              Stop. Stops any in-progress trim.
     4314 + *      -r <rate>       Sets the TRIM rate.
     4315 + */
     4316 +int
     4317 +zpool_do_trim(int argc, char **argv)
     4318 +{
     4319 +        int c;
     4320 +        trim_cbdata_t cb;
     4321 +
     4322 +        cb.cb_start = B_TRUE;
     4323 +        cb.cb_rate = 0;
     4324 +
     4325 +        /* check options */
     4326 +        while ((c = getopt(argc, argv, "sr:")) != -1) {
     4327 +                switch (c) {
     4328 +                case 's':
     4329 +                        cb.cb_start = B_FALSE;
     4330 +                        break;
     4331 +                case 'r':
     4332 +                        if (zfs_nicestrtonum(NULL, optarg, &cb.cb_rate) == -1) {
     4333 +                                (void) fprintf(stderr,
     4334 +                                    gettext("invalid value for rate\n"));
     4335 +                                usage(B_FALSE);
     4336 +                        }
     4337 +                        break;
     4338 +                case '?':
     4339 +                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     4340 +                            optopt);
     4341 +                        usage(B_FALSE);
     4342 +                }
     4343 +        }
     4344 +
     4345 +        argc -= optind;
     4346 +        argv += optind;
     4347 +
     4348 +        if (argc < 1) {
     4349 +                (void) fprintf(stderr, gettext("missing pool name argument\n"));
     4350 +                usage(B_FALSE);
     4351 +        }
     4352 +
     4353 +        return (for_each_pool(argc, argv, B_TRUE, NULL, trim_callback, &cb));
     4354 +}
     4355 +
4036 4356  typedef struct status_cbdata {
4037 4357          int             cb_count;
4038 4358          boolean_t       cb_allpools;
4039 4359          boolean_t       cb_verbose;
4040 4360          boolean_t       cb_explain;
4041 4361          boolean_t       cb_first;
4042 4362          boolean_t       cb_dedup_stats;
4043 4363  } status_cbdata_t;
4044 4364  
4045 4365  /*
4046 4366   * Print out detailed scrub status.
4047 4367   */
4048      -static void
     4368 +void
4049 4369  print_scan_status(pool_scan_stat_t *ps)
4050 4370  {
4051 4371          time_t start, end, pause;
4052 4372          uint64_t elapsed, mins_left, hours_left;
4053      -        uint64_t pass_exam, examined, total;
4054      -        uint_t rate;
     4373 +        uint64_t examined, total;
     4374 +        uint64_t rate, proc_rate;
4055 4375          double fraction_done;
4056      -        char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
     4376 +        char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7],
     4377 +            issued_buf[7];
4057 4378  
4058 4379          (void) printf(gettext("  scan: "));
4059 4380  
4060 4381          /* If there's never been a scan, there's not much to say. */
4061 4382          if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
4062 4383              ps->pss_func >= POOL_SCAN_FUNCS) {
4063 4384                  (void) printf(gettext("none requested\n"));
4064 4385                  return;
4065 4386          }
4066 4387  
4067 4388          start = ps->pss_start_time;
4068 4389          end = ps->pss_end_time;
4069 4390          pause = ps->pss_pass_scrub_pause;
4070 4391          zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
4071 4392  
4072 4393          assert(ps->pss_func == POOL_SCAN_SCRUB ||
4073      -            ps->pss_func == POOL_SCAN_RESILVER);
     4394 +            ps->pss_func == POOL_SCAN_RESILVER ||
     4395 +            ps->pss_func == POOL_SCAN_MOS ||
     4396 +            ps->pss_func == POOL_SCAN_META);
4074 4397          /*
4075 4398           * Scan is finished or canceled.
4076 4399           */
4077 4400          if (ps->pss_state == DSS_FINISHED) {
4078 4401                  uint64_t minutes_taken = (end - start) / 60;
4079 4402                  char *fmt = NULL;
4080 4403  
4081 4404                  if (ps->pss_func == POOL_SCAN_SCRUB) {
4082 4405                          fmt = gettext("scrub repaired %s in %lluh%um with "
4083 4406                              "%llu errors on %s");
     4407 +                } else if (ps->pss_func == POOL_SCAN_MOS) {
     4408 +                        fmt = gettext("MOS scrub repaired %s in %lluh%um with "
     4409 +                            "%llu errors on %s");
     4410 +                } else if (ps->pss_func == POOL_SCAN_META) {
     4411 +                        fmt = gettext("meta scrub repaired %s in %lluh%um with "
     4412 +                            "%llu errors on %s");
4084 4413                  } else if (ps->pss_func == POOL_SCAN_RESILVER) {
4085 4414                          fmt = gettext("resilvered %s in %lluh%um with "
4086 4415                              "%llu errors on %s");
4087 4416                  }
4088 4417                  /* LINTED */
4089 4418                  (void) printf(fmt, processed_buf,
4090 4419                      (u_longlong_t)(minutes_taken / 60),
4091 4420                      (uint_t)(minutes_taken % 60),
4092 4421                      (u_longlong_t)ps->pss_errors,
4093 4422                      ctime((time_t *)&end));
4094 4423                  return;
4095 4424          } else if (ps->pss_state == DSS_CANCELED) {
4096 4425                  if (ps->pss_func == POOL_SCAN_SCRUB) {
4097 4426                          (void) printf(gettext("scrub canceled on %s"),
4098 4427                              ctime(&end));
     4428 +                } else if (ps->pss_func == POOL_SCAN_MOS) {
     4429 +                        (void) printf(gettext("MOS scrub canceled on %s"),
     4430 +                            ctime(&end));
     4431 +                } else if (ps->pss_func == POOL_SCAN_META) {
     4432 +                        (void) printf(gettext("meta scrub canceled on %s"),
     4433 +                            ctime(&end));
4099 4434                  } else if (ps->pss_func == POOL_SCAN_RESILVER) {
4100 4435                          (void) printf(gettext("resilver canceled on %s"),
4101 4436                              ctime(&end));
4102 4437                  }
4103 4438                  return;
4104 4439          }
4105 4440  
4106      -        assert(ps->pss_state == DSS_SCANNING);
     4441 +        assert(ps->pss_state == DSS_SCANNING || ps->pss_state == DSS_FINISHING);
4107 4442  
4108 4443          /*
4109 4444           * Scan is in progress.
4110 4445           */
4111 4446          if (ps->pss_func == POOL_SCAN_SCRUB) {
4112 4447                  if (pause == 0) {
4113 4448                          (void) printf(gettext("scrub in progress since %s"),
4114 4449                              ctime(&start));
4115 4450                  } else {
4116 4451                          char buf[32];
4117 4452                          struct tm *p = localtime(&pause);
4118 4453                          (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p);
4119 4454                          (void) printf(gettext("scrub paused since %s\n"), buf);
4120 4455                          (void) printf(gettext("\tscrub started on   %s"),
4121 4456                              ctime(&start));
4122 4457                  }
     4458 +        } else if (ps->pss_func == POOL_SCAN_MOS) {
     4459 +                (void) printf(gettext("MOS scrub in progress since %s"),
     4460 +                    ctime(&start));
     4461 +        } else if (ps->pss_func == POOL_SCAN_META) {
     4462 +                (void) printf(gettext("meta scrub in progress since %s"),
     4463 +                    ctime(&start));
4123 4464          } else if (ps->pss_func == POOL_SCAN_RESILVER) {
4124 4465                  (void) printf(gettext("resilver in progress since %s"),
4125 4466                      ctime(&start));
4126 4467          }
4127 4468  
4128      -        examined = ps->pss_examined ? ps->pss_examined : 1;
     4469 +        examined = ps->pss_examined;
4129 4470          total = ps->pss_to_examine;
4130      -        fraction_done = (double)examined / total;
     4471 +        fraction_done = (double)ps->pss_issued / total;
4131 4472  
4132 4473          /* elapsed time for this pass */
4133      -        elapsed = time(NULL) - ps->pss_pass_start;
4134      -        elapsed -= ps->pss_pass_scrub_spent_paused;
4135      -        elapsed = elapsed ? elapsed : 1;
4136      -        pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
4137      -        rate = pass_exam / elapsed;
4138      -        rate = rate ? rate : 1;
4139      -        mins_left = ((total - examined) / rate) / 60;
     4474 +        elapsed = MAX(time(NULL) - ps->pss_start_time -
     4475 +            ps->pss_pass_scrub_spent_paused, 1);
     4476 +        if (ps->pss_func == POOL_SCAN_RESILVER) {
     4477 +                rate = MAX(((ps->pss_issued + ps->pss_processed) / 2) /
     4478 +                    elapsed, 1);
     4479 +        } else {
     4480 +                rate = MAX(ps->pss_issued / elapsed, 1);
     4481 +        }
     4482 +        proc_rate = MAX(ps->pss_processed / elapsed, 1);
     4483 +        if (ps->pss_func == POOL_SCAN_RESILVER)
     4484 +                mins_left = ((total - ps->pss_issued) / proc_rate) / 60;
     4485 +        else
     4486 +                mins_left = ((total - ps->pss_issued) / rate) / 60;
4140 4487          hours_left = mins_left / 60;
4141 4488  
4142 4489          zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
     4490 +        zfs_nicenum(ps->pss_issued, issued_buf, sizeof (issued_buf));
4143 4491          zfs_nicenum(total, total_buf, sizeof (total_buf));
     4492 +        zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4144 4493  
     4494 +        if (pause == 0) {
     4495 +                (void) printf(gettext("        %s scanned, %s verified "
     4496 +                    "out of %s at %s/s, %.2f%% done\n"), examined_buf,
     4497 +                    issued_buf, total_buf, rate_buf, 100 * fraction_done);
     4498 +        }
     4499 +
     4500 +        if (ps->pss_func == POOL_SCAN_RESILVER) {
     4501 +                char proc_rate_buf[7];
     4502 +                zfs_nicenum(proc_rate, proc_rate_buf,
     4503 +                    sizeof (proc_rate_buf));
     4504 +                (void) printf(gettext("        %s resilvered at %s/s"),
     4505 +                    processed_buf, proc_rate_buf);
     4506 +        } else if (ps->pss_func == POOL_SCAN_SCRUB ||
     4507 +            ps->pss_func == POOL_SCAN_MOS ||
     4508 +                    ps->pss_func == POOL_SCAN_META) {
     4509 +                (void) printf(gettext("        %s repaired"),
     4510 +                    processed_buf);
     4511 +        }
     4512 +
4145 4513          /*
4146 4514           * do not print estimated time if hours_left is more than 30 days
4147 4515           * or we have a paused scrub
4148 4516           */
4149 4517          if (pause == 0) {
4150      -                zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4151      -                (void) printf(gettext("\t%s scanned out of %s at %s/s"),
4152      -                    examined_buf, total_buf, rate_buf);
4153 4518                  if (hours_left < (30 * 24)) {
4154 4519                          (void) printf(gettext(", %lluh%um to go\n"),
4155 4520                              (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
4156 4521                  } else {
4157 4522                          (void) printf(gettext(
4158 4523                              ", (scan is slow, no estimated time)\n"));
4159 4524                  }
4160 4525          } else {
4161      -                (void) printf(gettext("\t%s scanned out of %s\n"),
4162      -                    examined_buf, total_buf);
     4526 +                (void) printf(gettext("\t%s scanned, %s verified out of %s\n"),
     4527 +                    examined_buf, issued_buf, total_buf);
4163 4528          }
4164      -
4165      -        if (ps->pss_func == POOL_SCAN_RESILVER) {
4166      -                (void) printf(gettext("    %s resilvered, %.2f%% done\n"),
4167      -                    processed_buf, 100 * fraction_done);
4168      -        } else if (ps->pss_func == POOL_SCAN_SCRUB) {
4169      -                (void) printf(gettext("    %s repaired, %.2f%% done\n"),
4170      -                    processed_buf, 100 * fraction_done);
4171      -        }
4172 4529  }
4173 4530  
4174      -/*
4175      - * Print out detailed removal status.
4176      - */
4177 4531  static void
4178      -print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
     4532 +print_trim_status(uint64_t trim_prog, uint64_t total_size, uint64_t rate,
     4533 +    uint64_t start_time_u64, uint64_t end_time_u64)
4179 4534  {
4180      -        char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
4181      -        time_t start, end;
4182      -        nvlist_t *config, *nvroot;
4183      -        nvlist_t **child;
4184      -        uint_t children;
4185      -        char *vdev_name;
     4535 +        time_t start_time = start_time_u64, end_time = end_time_u64;
     4536 +        char *buf;
4186 4537  
4187      -        if (prs == NULL || prs->prs_state == DSS_NONE)
4188      -                return;
4189      -
4190      -        /*
4191      -         * Determine name of vdev.
4192      -         */
4193      -        config = zpool_get_config(zhp, NULL);
4194      -        nvroot = fnvlist_lookup_nvlist(config,
4195      -            ZPOOL_CONFIG_VDEV_TREE);
4196      -        verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
4197      -            &child, &children) == 0);
4198      -        assert(prs->prs_removing_vdev < children);
4199      -        vdev_name = zpool_vdev_name(g_zfs, zhp,
4200      -            child[prs->prs_removing_vdev], B_TRUE);
4201      -
4202      -        (void) printf(gettext("remove: "));
4203      -
4204      -        start = prs->prs_start_time;
4205      -        end = prs->prs_end_time;
4206      -        zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
4207      -
4208      -        /*
4209      -         * Removal is finished or canceled.
4210      -         */
4211      -        if (prs->prs_state == DSS_FINISHED) {
4212      -                uint64_t minutes_taken = (end - start) / 60;
4213      -
4214      -                (void) printf(gettext("Removal of vdev %llu copied %s "
4215      -                    "in %lluh%um, completed on %s"),
4216      -                    (longlong_t)prs->prs_removing_vdev,
4217      -                    copied_buf,
4218      -                    (u_longlong_t)(minutes_taken / 60),
4219      -                    (uint_t)(minutes_taken % 60),
4220      -                    ctime((time_t *)&end));
4221      -        } else if (prs->prs_state == DSS_CANCELED) {
4222      -                (void) printf(gettext("Removal of %s canceled on %s"),
4223      -                    vdev_name, ctime(&end));
     4538 +        assert(trim_prog <= total_size);
     4539 +        if (trim_prog != 0 && trim_prog != total_size) {
     4540 +                buf = ctime(&start_time);
     4541 +                buf[strlen(buf) - 1] = '\0';    /* strip trailing newline */
     4542 +                if (rate != 0) {
     4543 +                        char rate_str[32];
     4544 +                        zfs_nicenum(rate, rate_str, sizeof (rate_str));
     4545 +                        (void) printf("  trim: %.02f%%\tstarted: %s\t"
     4546 +                            "(rate: %s/s)\n", (((double)trim_prog) /
     4547 +                            total_size) * 100, buf, rate_str);
     4548 +                } else {
     4549 +                        (void) printf("  trim: %.02f%%\tstarted: %s\t"
     4550 +                            "(rate: max)\n", (((double)trim_prog) /
     4551 +                            total_size) * 100, buf);
     4552 +                }
4224 4553          } else {
4225      -                uint64_t copied, total, elapsed, mins_left, hours_left;
4226      -                double fraction_done;
4227      -                uint_t rate;
     4554 +                if (start_time != 0) {
     4555 +                        /*
     4556 +                         * Non-zero start time means we were run at some point
     4557 +                         * in the past.
     4558 +                         */
     4559 +                        if (end_time != 0) {
     4560 +                                /* Non-zero end time means we completed */
     4561 +                                time_t diff = end_time - start_time;
     4562 +                                int hrs, mins;
4228 4563  
4229      -                assert(prs->prs_state == DSS_SCANNING);
4230      -
4231      -                /*
4232      -                 * Removal is in progress.
4233      -                 */
4234      -                (void) printf(gettext(
4235      -                    "Evacuation of %s in progress since %s"),
4236      -                    vdev_name, ctime(&start));
4237      -
4238      -                copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
4239      -                total = prs->prs_to_copy;
4240      -                fraction_done = (double)copied / total;
4241      -
4242      -                /* elapsed time for this pass */
4243      -                elapsed = time(NULL) - prs->prs_start_time;
4244      -                elapsed = elapsed > 0 ? elapsed : 1;
4245      -                rate = copied / elapsed;
4246      -                rate = rate > 0 ? rate : 1;
4247      -                mins_left = ((total - copied) / rate) / 60;
4248      -                hours_left = mins_left / 60;
4249      -
4250      -                zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
4251      -                zfs_nicenum(total, total_buf, sizeof (total_buf));
4252      -                zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4253      -
4254      -                /*
4255      -                 * do not print estimated time if hours_left is more than
4256      -                 * 30 days
4257      -                 */
4258      -                (void) printf(gettext("    %s copied out of %s at %s/s, "
4259      -                    "%.2f%% done"),
4260      -                    examined_buf, total_buf, rate_buf, 100 * fraction_done);
4261      -                if (hours_left < (30 * 24)) {
4262      -                        (void) printf(gettext(", %lluh%um to go\n"),
4263      -                            (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
     4564 +                                buf = ctime(&end_time);
     4565 +                                buf[strlen(buf) - 1] = '\0';
     4566 +                                hrs = diff / 3600;
     4567 +                                mins = (diff % 3600) / 60;
     4568 +                                (void) printf(gettext("  trim: completed on %s "
     4569 +                                    "(after %dh%dm)\n"), buf, hrs, mins);
     4570 +                        } else {
     4571 +                                buf = ctime(&start_time);
     4572 +                                buf[strlen(buf) - 1] = '\0';
     4573 +                                /* Zero end time means we were interrupted */
     4574 +                                (void) printf(gettext("  trim: interrupted\t"
     4575 +                                    "(started %s)\n"), buf);
     4576 +                        }
4264 4577                  } else {
4265      -                        (void) printf(gettext(
4266      -                            ", (copy is slow, no estimated time)\n"));
     4578 +                        /* trim was never run */
     4579 +                        (void) printf(gettext("  trim: none requested\n"));
4267 4580                  }
4268 4581          }
4269      -
4270      -        if (prs->prs_mapping_memory > 0) {
4271      -                char mem_buf[7];
4272      -                zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
4273      -                (void) printf(gettext("    %s memory used for "
4274      -                    "removed device mappings\n"),
4275      -                    mem_buf);
4276      -        }
4277 4582  }
4278 4583  
4279 4584  static void
4280 4585  print_error_log(zpool_handle_t *zhp)
4281 4586  {
4282 4587          nvlist_t *nverrlist = NULL;
4283 4588          nvpair_t *elem;
4284 4589          char *pathname;
4285 4590          size_t len = MAXPATHLEN * 2;
4286 4591  
↓ open down ↓ 94 lines elided ↑ open up ↑
4381 4686              (u_longlong_t)ddo->ddo_mspace);
4382 4687  
4383 4688          verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
4384 4689              (uint64_t **)&dds, &c) == 0);
4385 4690          verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
4386 4691              (uint64_t **)&ddh, &c) == 0);
4387 4692          zpool_dump_ddt(dds, ddh);
4388 4693  }
4389 4694  
4390 4695  /*
     4696 + * Calculates the total space available on log devices on the pool.
     4697 + * For whatever reason, this is not counted in the root vdev's space stats.
     4698 + */
     4699 +static uint64_t
     4700 +zpool_slog_space(nvlist_t *nvroot)
     4701 +{
     4702 +        nvlist_t **newchild;
     4703 +        uint_t c, children;
     4704 +        uint64_t space = 0;
     4705 +
     4706 +        verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
     4707 +            &newchild, &children) == 0);
     4708 +
     4709 +        for (c = 0; c < children; c++) {
     4710 +                uint64_t islog = B_FALSE;
     4711 +                vdev_stat_t *vs;
     4712 +                uint_t n;
     4713 +                uint_t n_subchildren = 1;
     4714 +                nvlist_t **subchild;
     4715 +
     4716 +                (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
     4717 +                    &islog);
     4718 +                if (!islog)
     4719 +                        continue;
     4720 +                verify(nvlist_lookup_uint64_array(newchild[c],
     4721 +                    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &n) == 0);
     4722 +
     4723 +                /* vdev can be non-leaf, so multiply by number of children */
     4724 +                (void) nvlist_lookup_nvlist_array(newchild[c],
     4725 +                    ZPOOL_CONFIG_CHILDREN, &subchild, &n_subchildren);
     4726 +                space += n_subchildren * vs->vs_space;
     4727 +        }
     4728 +
     4729 +        return (space);
     4730 +}
     4731 +
     4732 +/*
4391 4733   * Display a summary of pool status.  Displays a summary such as:
4392 4734   *
4393 4735   *        pool: tank
4394 4736   *      status: DEGRADED
4395 4737   *      reason: One or more devices ...
4396 4738   *         see: http://illumos.org/msg/ZFS-xxxx-01
4397 4739   *      config:
4398 4740   *              mirror          DEGRADED
4399 4741   *                c1t0d0        OK
4400 4742   *                c2t0d0        UNAVAIL
↓ open down ↓ 32 lines elided ↑ open up ↑
4433 4775                                  cbp->cb_first = B_FALSE;
4434 4776                  }
4435 4777                  return (0);
4436 4778          }
4437 4779  
4438 4780          if (cbp->cb_first)
4439 4781                  cbp->cb_first = B_FALSE;
4440 4782          else
4441 4783                  (void) printf("\n");
4442 4784  
4443      -        nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
     4785 +        verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
     4786 +            &nvroot) == 0);
4444 4787          verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
4445 4788              (uint64_t **)&vs, &c) == 0);
4446 4789          health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
4447 4790  
4448 4791          (void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
4449 4792          (void) printf(gettext(" state: %s\n"), health);
4450 4793  
4451 4794          switch (reason) {
4452 4795          case ZPOOL_STATUS_MISSING_DEV_R:
4453 4796                  (void) printf(gettext("status: One or more devices could not "
↓ open down ↓ 187 lines elided ↑ open up ↑
4641 4984          if (msgid != NULL)
4642 4985                  (void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4643 4986                      msgid);
4644 4987  
4645 4988          if (config != NULL) {
4646 4989                  int namewidth;
4647 4990                  uint64_t nerr;
4648 4991                  nvlist_t **spares, **l2cache;
4649 4992                  uint_t nspares, nl2cache;
4650 4993                  pool_scan_stat_t *ps = NULL;
4651      -                pool_removal_stat_t *prs = NULL;
     4994 +                uint64_t trim_prog, trim_rate, trim_start_time, trim_stop_time;
4652 4995  
4653 4996                  (void) nvlist_lookup_uint64_array(nvroot,
4654 4997                      ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
4655 4998                  print_scan_status(ps);
4656 4999  
4657      -                (void) nvlist_lookup_uint64_array(nvroot,
4658      -                    ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
4659      -                print_removal_status(zhp, prs);
     5000 +                /* Grab trim stats if the pool supports it */
     5001 +                if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_PROG,
     5002 +                    &trim_prog) == 0 &&
     5003 +                    nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_RATE,
     5004 +                    &trim_rate) == 0 &&
     5005 +                    nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_START_TIME,
     5006 +                    &trim_start_time) == 0 &&
     5007 +                    nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_STOP_TIME,
     5008 +                    &trim_stop_time) == 0) {
     5009 +                        /*
     5010 +                         * For whatever reason, root vdev_stats_t don't
     5011 +                         * include log devices.
     5012 +                         */
     5013 +                        print_trim_status(trim_prog, vs->vs_space +
     5014 +                            zpool_slog_space(nvroot), trim_rate,
     5015 +                            trim_start_time, trim_stop_time);
     5016 +                }
4660 5017  
4661 5018                  namewidth = max_width(zhp, nvroot, 0, 0);
4662 5019                  if (namewidth < 10)
4663 5020                          namewidth = 10;
4664 5021  
4665 5022                  (void) printf(gettext("config:\n\n"));
4666 5023                  (void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4667 5024                      "NAME", "STATE", "READ", "WRITE", "CKSUM");
4668 5025                  print_status_config(zhp, zpool_get_name(zhp), nvroot,
4669 5026                      namewidth, 0, B_FALSE);
4670 5027  
     5028 +                if (num_special(nvroot) > 0)
     5029 +                        print_special(zhp, nvroot, namewidth, B_TRUE);
4671 5030                  if (num_logs(nvroot) > 0)
4672 5031                          print_logs(zhp, nvroot, namewidth, B_TRUE);
4673 5032                  if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4674 5033                      &l2cache, &nl2cache) == 0)
4675 5034                          print_l2cache(zhp, l2cache, nl2cache, namewidth);
4676 5035  
4677 5036                  if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
4678 5037                      &spares, &nspares) == 0)
4679 5038                          print_spares(zhp, spares, nspares, namewidth);
4680 5039  
↓ open down ↓ 159 lines elided ↑ open up ↑
4840 5199  
4841 5200  static int
4842 5201  upgrade_enable_all(zpool_handle_t *zhp, int *countp)
4843 5202  {
4844 5203          int i, ret, count;
4845 5204          boolean_t firstff = B_TRUE;
4846 5205          nvlist_t *enabled = zpool_get_features(zhp);
4847 5206  
4848 5207          count = 0;
4849 5208          for (i = 0; i < SPA_FEATURES; i++) {
4850      -                const char *fname = spa_feature_table[i].fi_uname;
4851      -                const char *fguid = spa_feature_table[i].fi_guid;
     5209 +                zfeature_info_t *finfo = &spa_feature_table[i];
     5210 +                const char *fname = finfo->fi_uname;
     5211 +                const char *fguid = finfo->fi_guid;
4852 5212                  if (!nvlist_exists(enabled, fguid)) {
4853 5213                          char *propname;
     5214 +
     5215 +                        /*
     5216 +                         * SPA_FEATURE_WBC can be enabled only
     5217 +                         * if 'special' vdev available
     5218 +                         */
     5219 +                        if (finfo->fi_feature == SPA_FEATURE_WBC)
     5220 +                                continue;
     5221 +
4854 5222                          verify(-1 != asprintf(&propname, "feature@%s", fname));
4855 5223                          ret = zpool_set_prop(zhp, propname,
4856 5224                              ZFS_FEATURE_ENABLED);
4857 5225                          if (ret != 0) {
4858 5226                                  free(propname);
4859 5227                                  return (ret);
4860 5228                          }
4861 5229                          count++;
4862 5230  
4863 5231                          if (firstff) {
↓ open down ↓ 737 lines elided ↑ open up ↑
5601 5969  
5602 5970          if (cb.cb_proplist == &fake_name)
5603 5971                  zprop_free_list(fake_name.pl_next);
5604 5972          else
5605 5973                  zprop_free_list(cb.cb_proplist);
5606 5974  
5607 5975          return (ret);
5608 5976  }
5609 5977  
5610 5978  typedef struct set_cbdata {
5611      -        char *cb_propname;
5612      -        char *cb_value;
     5979 +        nvlist_t *cb_nvl;
5613 5980          boolean_t cb_any_successful;
5614 5981  } set_cbdata_t;
5615 5982  
5616 5983  int
5617 5984  set_callback(zpool_handle_t *zhp, void *data)
5618 5985  {
5619 5986          int error;
5620 5987          set_cbdata_t *cb = (set_cbdata_t *)data;
5621 5988  
5622      -        error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
5623      -
     5989 +        error = zpool_set_proplist(zhp, cb->cb_nvl);
5624 5990          if (!error)
5625 5991                  cb->cb_any_successful = B_TRUE;
5626 5992  
5627 5993          return (error);
5628 5994  }
5629 5995  
     5996 +static void
     5997 +parse_props(char *propname, nvlist_t **nvl, zfs_type_t prop_type)
     5998 +{
     5999 +        char *propval;
     6000 +        char *delim;
     6001 +        int err;
     6002 +
     6003 +        do {
     6004 +                delim = strchr(propname, ',');
     6005 +                if (delim != NULL)
     6006 +                        *delim++ = '\0';
     6007 +
     6008 +                propval = strchr(propname, '=');
     6009 +                if (propval == NULL) {
     6010 +                        (void) fprintf(stderr, gettext("missing value "
     6011 +                            "in property=value argument\n"));
     6012 +                        if (*nvl != NULL)
     6013 +                                nvlist_free(*nvl);
     6014 +                        usage(B_FALSE);
     6015 +                }
     6016 +                *propval++ = '\0';
     6017 +                switch (prop_type) {
     6018 +                case ZFS_TYPE_VDEV:
     6019 +                        err = add_vdev_prop_list(propname, propval, nvl);
     6020 +                        break;
     6021 +                case ZFS_TYPE_COS:
     6022 +                        err = add_cos_prop_list(propname, propval, nvl);
     6023 +                        break;
     6024 +                default:
     6025 +                        err = add_prop_list(propname, propval, nvl, B_TRUE);
     6026 +                }
     6027 +
     6028 +                if (err) {
     6029 +                        if (*nvl != NULL)
     6030 +                                nvlist_free(*nvl);
     6031 +                        usage(B_FALSE);
     6032 +                }
     6033 +
     6034 +                propname = delim;
     6035 +        } while (delim != NULL);
     6036 +}
     6037 +
5630 6038  int
5631 6039  zpool_do_set(int argc, char **argv)
5632 6040  {
5633 6041          set_cbdata_t cb = { 0 };
5634 6042          int error;
5635 6043  
5636 6044          if (argc > 1 && argv[1][0] == '-') {
5637 6045                  (void) fprintf(stderr, gettext("invalid option '%c'\n"),
5638 6046                      argv[1][1]);
5639 6047                  usage(B_FALSE);
↓ open down ↓ 8 lines elided ↑ open up ↑
5648 6056          if (argc < 3) {
5649 6057                  (void) fprintf(stderr, gettext("missing pool name\n"));
5650 6058                  usage(B_FALSE);
5651 6059          }
5652 6060  
5653 6061          if (argc > 3) {
5654 6062                  (void) fprintf(stderr, gettext("too many pool names\n"));
5655 6063                  usage(B_FALSE);
5656 6064          }
5657 6065  
5658      -        cb.cb_propname = argv[1];
5659      -        cb.cb_value = strchr(cb.cb_propname, '=');
5660      -        if (cb.cb_value == NULL) {
5661      -                (void) fprintf(stderr, gettext("missing value in "
5662      -                    "property=value argument\n"));
     6066 +        parse_props(argv[1], &cb.cb_nvl, ZFS_TYPE_POOL);
     6067 +
     6068 +        error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
     6069 +            set_callback, &cb);
     6070 +
     6071 +        return (error);
     6072 +}
     6073 +
     6074 +typedef struct vdev_cbdata {
     6075 +        char *vcb_vdev;
     6076 +        nvlist_t *vcb_nvl; /* values */
     6077 +        boolean_t vcb_any_successful;
     6078 +} vdev_cbdata_t;
     6079 +
     6080 +typedef struct vdev_get_cbdata {
     6081 +        zprop_get_cbdata_t vcb_zprop_get_cbdata;
     6082 +        char *vcb_vdev;
     6083 +        nvlist_t *vcb_nvl; /* values */
     6084 +        boolean_t vcb_any_successful;
     6085 +} vdev_get_cbdata_t;
     6086 +
     6087 +static int
     6088 +vdev_get_callback(zpool_handle_t *zhp, void *data)
     6089 +{
     6090 +        int err;
     6091 +        boolean_t l2cache, avail_space;
     6092 +        vdev_get_cbdata_t *vcb = (vdev_get_cbdata_t *)data;
     6093 +        zprop_get_cbdata_t *cb = &vcb->vcb_zprop_get_cbdata;
     6094 +        char value[MAXNAMELEN];
     6095 +        zprop_list_t *pl;
     6096 +
     6097 +        (void) zpool_find_vdev(zhp, vcb->vcb_vdev, &avail_space,
     6098 +            &l2cache, NULL, NULL);
     6099 +        for (pl = cb->cb_proplist; pl != NULL; pl = pl->pl_next) {
     6100 +                if ((err = vdev_get_prop(zhp, vcb->vcb_vdev,
     6101 +                    pl->pl_prop, value, sizeof (value))) != 0)
     6102 +                        return (err);
     6103 +
     6104 +                /* don't show L2ARC prop for non L2ARC dev, can't set anyway */
     6105 +                if (!l2cache && pl->pl_prop == VDEV_PROP_L2ADDDT)
     6106 +                        continue;
     6107 +                vdev_print_one_property(zpool_get_name(zhp), vcb->vcb_vdev, cb,
     6108 +                    vdev_prop_to_name(pl->pl_prop), value);
     6109 +        }
     6110 +
     6111 +        return (0);
     6112 +}
     6113 +
     6114 +
     6115 +int
     6116 +zpool_do_vdev_get(int argc, char **argv)
     6117 +{
     6118 +        vdev_get_cbdata_t vcb = { 0 };
     6119 +        zprop_get_cbdata_t *cb = &vcb.vcb_zprop_get_cbdata;
     6120 +        int error;
     6121 +
     6122 +        if (argc > 1 && argv[1][0] == '-') {
     6123 +                (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     6124 +                    argv[1][1]);
5663 6125                  usage(B_FALSE);
5664 6126          }
5665 6127  
5666      -        *(cb.cb_value) = '\0';
5667      -        cb.cb_value++;
     6128 +        if (argc < 2) {
     6129 +                (void) fprintf(stderr, gettext("missing property name\n"));
     6130 +                usage(B_FALSE);
     6131 +        }
5668 6132  
5669      -        error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
5670      -            set_callback, &cb);
     6133 +        if (argc < 3) {
     6134 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6135 +                usage(B_FALSE);
     6136 +        }
5671 6137  
     6138 +        if (argc < 4) {
     6139 +                (void) fprintf(stderr,
     6140 +                    gettext("at least one vdev name or guid is required\n"));
     6141 +                usage(B_FALSE);
     6142 +        }
     6143 +
     6144 +        cb->cb_first = B_TRUE;
     6145 +        cb->cb_sources = ZPROP_SRC_ALL;
     6146 +        cb->cb_columns[0] = GET_COL_NAME;
     6147 +        cb->cb_columns[1] = GET_COL_SOURCE;
     6148 +        cb->cb_columns[2] = GET_COL_PROPERTY;
     6149 +        cb->cb_columns[3] = GET_COL_VALUE;
     6150 +        cb->cb_type = ZFS_TYPE_VDEV;
     6151 +
     6152 +        if (vdev_get_proplist(g_zfs, argv[1], &cb->cb_proplist) != 0)
     6153 +                usage(B_FALSE);
     6154 +
     6155 +        vcb.vcb_vdev = argv[3];
     6156 +        error = for_each_pool(1, argv + 2, B_TRUE, NULL,
     6157 +            vdev_get_callback, &vcb);
     6158 +
     6159 +        zprop_free_list(cb->cb_proplist);
     6160 +
5672 6161          return (error);
5673 6162  }
5674 6163  
     6164 +int
     6165 +vdev_set_callback(zpool_handle_t *zhp, void *data)
     6166 +{
     6167 +        int error;
     6168 +        vdev_cbdata_t *cb = (vdev_cbdata_t *)data;
     6169 +
     6170 +        error = vdev_set_proplist(zhp, cb->vcb_vdev, cb->vcb_nvl);
     6171 +        if (!error)
     6172 +                cb->vcb_any_successful = B_TRUE;
     6173 +
     6174 +        return (error);
     6175 +}
     6176 +
     6177 +int
     6178 +zpool_do_vdev_set(int argc, char **argv)
     6179 +{
     6180 +        vdev_cbdata_t cb = { 0 };
     6181 +        int error;
     6182 +
     6183 +        if (argc > 1 && argv[1][0] == '-') {
     6184 +                (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     6185 +                    argv[1][1]);
     6186 +                usage(B_FALSE);
     6187 +        }
     6188 +
     6189 +        if (argc < 2) {
     6190 +                (void) fprintf(stderr, gettext("missing property=value "
     6191 +                    "argument\n"));
     6192 +                usage(B_FALSE);
     6193 +        }
     6194 +
     6195 +        if (argc < 3) {
     6196 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6197 +                usage(B_FALSE);
     6198 +        }
     6199 +
     6200 +        if (argc < 4) {
     6201 +                (void) fprintf(stderr,
     6202 +                    gettext("at least one vdev name or guid is required\n"));
     6203 +                usage(B_FALSE);
     6204 +        }
     6205 +
     6206 +        parse_props(argv[1], &cb.vcb_nvl, ZFS_TYPE_VDEV);
     6207 +
     6208 +        cb.vcb_vdev = argv[3];
     6209 +        error = for_each_pool(1, argv + 2, B_TRUE, NULL,
     6210 +            vdev_set_callback, &cb);
     6211 +
     6212 +        return (error);
     6213 +}
     6214 +
     6215 +typedef struct cos_af_cbdata {
     6216 +        char *cb_cos;
     6217 +        uint64_t cb_guid;
     6218 +        boolean_t cb_alloc;
     6219 +        boolean_t cb_any_successful;
     6220 +        boolean_t cb_force;
     6221 +        nvlist_t *cb_nvl;
     6222 +} cos_af_cbdata_t;
     6223 +
     6224 +int
     6225 +cos_alloc_callback(zpool_handle_t *zhp, void *data)
     6226 +{
     6227 +        int error;
     6228 +        cos_af_cbdata_t *cb = (cos_af_cbdata_t *)data;
     6229 +
     6230 +        if (cb->cb_alloc)
     6231 +                error = cos_alloc(zhp, cb->cb_cos, cb->cb_nvl);
     6232 +        else
     6233 +                error = cos_free(zhp, cb->cb_cos, cb->cb_guid, cb->cb_force);
     6234 +        if (!error)
     6235 +                cb->cb_any_successful = B_TRUE;
     6236 +
     6237 +        if (error == ENOTSUP) {
     6238 +                (void) fprintf(stderr, gettext("operation failed: "
     6239 +                    "CoS feature is disabled.\n"));
     6240 +        }
     6241 +
     6242 +        return (error);
     6243 +}
     6244 +
     6245 +int
     6246 +zpool_do_cos_alloc(int argc, char **argv)
     6247 +{
     6248 +        nvlist_t *nvl;
     6249 +        cos_af_cbdata_t cb = { 0 };
     6250 +        int error;
     6251 +
     6252 +        if (!nexenta_meta_enable())
     6253 +                return (-1);
     6254 +
     6255 +        if (argc < 2) {
     6256 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6257 +                usage(B_FALSE);
     6258 +        }
     6259 +
     6260 +        if (argc < 3) {
     6261 +                (void) fprintf(stderr,
     6262 +                    gettext("at least one cos name or id is required\n"));
     6263 +                usage(B_FALSE);
     6264 +        }
     6265 +
     6266 +        if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
     6267 +                (void) fprintf(stderr,
     6268 +                    gettext("internal error: out of memory\n"));
     6269 +                return (1);
     6270 +        }
     6271 +
     6272 +        cb.cb_cos = argv[2];
     6273 +        cb.cb_alloc = B_TRUE;
     6274 +        cb.cb_nvl = nvl;
     6275 +        error = for_each_pool(1, argv + 1, B_TRUE, NULL,
     6276 +            cos_alloc_callback, &cb);
     6277 +
     6278 +        nvlist_free(nvl);
     6279 +
     6280 +        return (error);
     6281 +}
     6282 +
     6283 +int
     6284 +zpool_do_cos_free(int argc, char **argv)
     6285 +{
     6286 +        cos_af_cbdata_t cb = { 0 };
     6287 +        char *endp;
     6288 +        int error;
     6289 +
     6290 +        if (!nexenta_meta_enable())
     6291 +                return (-1);
     6292 +
     6293 +        if (argc > 1 && strncmp(argv[1], "-f", sizeof ("-f")) == 0) {
     6294 +                /* -f - force option */
     6295 +                cb.cb_force = B_TRUE;
     6296 +                argc--;
     6297 +                argv++;
     6298 +        }
     6299 +
     6300 +        if (argc < 2) {
     6301 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6302 +                usage(B_FALSE);
     6303 +        }
     6304 +
     6305 +        if (argc < 3) {
     6306 +                (void) fprintf(stderr,
     6307 +                    gettext("at least one cos name or id is required\n"));
     6308 +                usage(B_FALSE);
     6309 +        }
     6310 +
     6311 +        cb.cb_guid = strtoll(argv[2], &endp, 10);
     6312 +        if (endp <  argv[2] + strlen(argv[2])) {
     6313 +                cb.cb_guid = 0;
     6314 +        }
     6315 +
     6316 +        if (cb.cb_guid == 0)
     6317 +                cb.cb_cos = argv[2];
     6318 +        else
     6319 +                cb.cb_cos = "";
     6320 +
     6321 +        error = for_each_pool(1, argv + 1, B_TRUE, NULL,
     6322 +            cos_alloc_callback, &cb);
     6323 +
     6324 +        return (error);
     6325 +}
     6326 +
     6327 +
5675 6328  static int
     6329 +cos_list_callback(zpool_handle_t *zhp, void *data)
     6330 +{
     6331 +        int err, i;
     6332 +        nvlist_t *nvl = (nvlist_t *)data;
     6333 +        nvpair_t *nvp;
     6334 +
     6335 +        if ((err = cos_list(zhp, &nvl)) == 0) {
     6336 +                (void) printf("%-*s %s\n", MAXCOSNAMELEN, gettext("COSNAME"),
     6337 +                    gettext("COSID"));
     6338 +                for (i = 0, nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
     6339 +                    nvp = nvlist_next_nvpair(nvl, nvp), i++) {
     6340 +                        uint64_t cosid;
     6341 +                        char *cosname = nvpair_name(nvp);
     6342 +                        if (nvpair_value_uint64(nvp, &cosid) == 0)
     6343 +                                (void) printf("%-*s %llu\n", MAXCOSNAMELEN,
     6344 +                                    cosname, cosid);
     6345 +                }
     6346 +
     6347 +                if (!i)
     6348 +                        (void) printf("%s\n", gettext("<no classes found>"));
     6349 +        }
     6350 +        return (err);
     6351 +}
     6352 +
     6353 +int
     6354 +zpool_do_cos_list(int argc, char **argv)
     6355 +{
     6356 +        nvlist_t *nvl;
     6357 +        int error;
     6358 +
     6359 +        if (!nexenta_meta_enable())
     6360 +                return (-1);
     6361 +
     6362 +        if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
     6363 +                (void) fprintf(stderr,
     6364 +                    gettext("internal error: out of memory\n"));
     6365 +                return (1);
     6366 +        }
     6367 +
     6368 +        if (argc < 2) {
     6369 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6370 +                usage(B_FALSE);
     6371 +        }
     6372 +
     6373 +        error = for_each_pool(1, argv+1, B_TRUE, NULL,
     6374 +            cos_list_callback, nvl);
     6375 +
     6376 +        nvlist_free(nvl);
     6377 +
     6378 +        return (error);
     6379 +
     6380 +}
     6381 +
     6382 +typedef struct cos_cbdata {
     6383 +        char *vcb_cos;
     6384 +        nvlist_t *vcb_nvl; /* values */
     6385 +        boolean_t vcb_any_successful;
     6386 +} cos_cbdata_t;
     6387 +
     6388 +typedef struct cos_get_cbdata {
     6389 +        zprop_get_cbdata_t vcb_zprop_get_cbdata;
     6390 +        char *vcb_cos;
     6391 +        nvlist_t *vcb_nvl; /* values */
     6392 +        boolean_t vcb_any_successful;
     6393 +} cos_get_cbdata_t;
     6394 +
     6395 +static int
     6396 +cos_get_callback(zpool_handle_t *zhp, void *data)
     6397 +{
     6398 +        int err;
     6399 +        cos_get_cbdata_t *vcb = (cos_get_cbdata_t *)data;
     6400 +        zprop_get_cbdata_t *cb = &vcb->vcb_zprop_get_cbdata;
     6401 +        char value[MAXNAMELEN];
     6402 +        zprop_list_t *pl;
     6403 +        nvlist_t *nvl = NULL;
     6404 +
     6405 +        for (pl = cb->cb_proplist; pl != NULL; pl = pl->pl_next) {
     6406 +                if ((err = cos_get_prop(zhp, vcb->vcb_cos,
     6407 +                    pl->pl_prop, value, sizeof (value), &nvl)) != 0)
     6408 +                        return (err);
     6409 +
     6410 +                cos_print_one_property(zpool_get_name(zhp), vcb->vcb_cos, cb,
     6411 +                    cos_prop_to_name(pl->pl_prop), value);
     6412 +        }
     6413 +
     6414 +        return (0);
     6415 +}
     6416 +
     6417 +
     6418 +int
     6419 +zpool_do_cos_get(int argc, char **argv)
     6420 +{
     6421 +        cos_get_cbdata_t vcb = { 0 };
     6422 +        zprop_get_cbdata_t *cb = &vcb.vcb_zprop_get_cbdata;
     6423 +        int error;
     6424 +
     6425 +        if (!nexenta_meta_enable())
     6426 +                return (-1);
     6427 +
     6428 +        if (argc > 1 && argv[1][0] == '-') {
     6429 +                (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     6430 +                    argv[1][1]);
     6431 +                usage(B_FALSE);
     6432 +        }
     6433 +
     6434 +        if (argc < 2) {
     6435 +                (void) fprintf(stderr, gettext("missing property name\n"));
     6436 +                usage(B_FALSE);
     6437 +        }
     6438 +
     6439 +        if (argc < 3) {
     6440 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6441 +                usage(B_FALSE);
     6442 +        }
     6443 +
     6444 +        if (argc < 4) {
     6445 +                (void) fprintf(stderr,
     6446 +                    gettext("at least one cos name or guid is required\n"));
     6447 +                usage(B_FALSE);
     6448 +        }
     6449 +
     6450 +        cb->cb_first = B_TRUE;
     6451 +        cb->cb_sources = ZPROP_SRC_ALL;
     6452 +        cb->cb_columns[0] = GET_COL_NAME;
     6453 +        cb->cb_columns[1] = GET_COL_SOURCE;
     6454 +        cb->cb_columns[2] = GET_COL_PROPERTY;
     6455 +        cb->cb_columns[3] = GET_COL_VALUE;
     6456 +        cb->cb_type = ZFS_TYPE_COS;
     6457 +
     6458 +        if (cos_get_proplist(g_zfs, argv[1],  &cb->cb_proplist) != 0)
     6459 +                usage(B_FALSE);
     6460 +
     6461 +        vcb.vcb_cos = argv[3];
     6462 +        error = for_each_pool(1, argv + 2, B_TRUE, NULL,
     6463 +            cos_get_callback, &vcb);
     6464 +
     6465 +        zprop_free_list(cb->cb_proplist);
     6466 +
     6467 +        return (error);
     6468 +
     6469 +}
     6470 +
     6471 +int
     6472 +cos_set_callback(zpool_handle_t *zhp, void *data)
     6473 +{
     6474 +        int error;
     6475 +        cos_cbdata_t *cb = (cos_cbdata_t *)data;
     6476 +
     6477 +        error = cos_set_proplist(zhp, cb->vcb_cos, cb->vcb_nvl);
     6478 +        if (!error)
     6479 +                cb->vcb_any_successful = B_TRUE;
     6480 +
     6481 +        return (error);
     6482 +}
     6483 +
     6484 +int
     6485 +zpool_do_cos_set(int argc, char **argv)
     6486 +{
     6487 +        cos_cbdata_t cb = { 0 };
     6488 +        int error;
     6489 +
     6490 +        if (!nexenta_meta_enable())
     6491 +                return (-1);
     6492 +
     6493 +        if (argc > 1 && argv[1][0] == '-') {
     6494 +                (void) fprintf(stderr, gettext("invalid option '%c'\n"),
     6495 +                    argv[1][1]);
     6496 +                usage(B_FALSE);
     6497 +        }
     6498 +
     6499 +        if (argc < 2) {
     6500 +                (void) fprintf(stderr, gettext("missing property=value "
     6501 +                    "argument\n"));
     6502 +                usage(B_FALSE);
     6503 +        }
     6504 +
     6505 +        if (argc < 3) {
     6506 +                (void) fprintf(stderr, gettext("missing pool name\n"));
     6507 +                usage(B_FALSE);
     6508 +        }
     6509 +
     6510 +        if (argc < 4) {
     6511 +                (void) fprintf(stderr,
     6512 +                    gettext("at least one cos name or id is required\n"));
     6513 +                usage(B_FALSE);
     6514 +        }
     6515 +
     6516 +        parse_props(argv[1], &cb.vcb_nvl, ZFS_TYPE_COS);
     6517 +
     6518 +        cb.vcb_cos = argv[3];
     6519 +        error = for_each_pool(1, argv + 2, B_TRUE, NULL,
     6520 +            cos_set_callback, &cb);
     6521 +
     6522 +        return (error);
     6523 +}
     6524 +
     6525 +static int
5676 6526  find_command_idx(char *command, int *idx)
5677 6527  {
5678 6528          int i;
5679 6529  
5680 6530          for (i = 0; i < NCOMMAND; i++) {
5681 6531                  if (command_table[i].name == NULL)
5682 6532                          continue;
5683 6533  
5684 6534                  if (strcmp(command, command_table[i].name) == 0) {
5685 6535                          *idx = i;
↓ open down ↓ 33 lines elided ↑ open up ↑
5719 6569  
5720 6570          cmdname = argv[1];
5721 6571  
5722 6572          /*
5723 6573           * Special case '-?'
5724 6574           */
5725 6575          if (strcmp(cmdname, "-?") == 0)
5726 6576                  usage(B_TRUE);
5727 6577  
5728 6578          zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
     6579 +        verify(zpool_stage_history(g_zfs, history_str) == 0);
5729 6580  
5730 6581          /*
5731 6582           * Run the appropriate command.
5732 6583           */
5733 6584          if (find_command_idx(cmdname, &i) == 0) {
5734 6585                  current_command = &command_table[i];
5735 6586                  ret = command_table[i].func(argc - 1, argv + 1);
5736 6587          } else if (strchr(cmdname, '=')) {
5737 6588                  verify(find_command_idx("set", &i) == 0);
5738 6589                  current_command = &command_table[i];
↓ open down ↓ 32 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX