Print this page
NEX-14252 zpool remove incorrect message: special device contains metadata
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-5736 implement autoreplace matching based on FRU slot number
NEX-6200 hot spares are not reactivated after reinserting into enclosure
NEX-9403 need to update FRU for spare and l2cache devices
NEX-9404 remove lofi autoreplace support from syseventd
NEX-9409 hotsparing doesn't work for vdevs without FRU
NEX-9424 zfs`vdev_online() needs better notification about state changes
Portions contributed by: Alek Pinchuk <alek@nexenta.com>
Portions contributed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@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-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-5019 wrcache activation races vs. 'zpool create -O wrc_mode='
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Steve Peng <steve.peng@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>
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>
6298 zfs_create_008_neg and zpool_create_023_neg need to be updated for large block support
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-4582 update wrc test cases for allow to use write back cache per tree of datasets
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
5960 zfs recv should prefetch indirect blocks
5925 zfs receive -o origin=
Reviewed by: Prakash Surya <prakash.surya@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.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-2325 I/O drop to '0' when FC cable unplugged: path_to_devid() unnecessarily invokes Test Unit Ready which can incorrectly invalidate label causing I/Os failures (fix compile)
NEX-2325 I/O drop to '0' when FC cable unplugged: path_to_devid() unnecessarily invokes Test Unit Ready which can incorrectly invalidate label causing I/Os failures
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3025 support root pools on EFI labeled disks
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-2997 Memory leaks in libzfs import implementation
Reviewed by: Dan Fields <dan.fields@nexenta.com>
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
OS-80 support for vdev and CoS properties for the new I/O scheduler
OS-95 lint warning introduced by OS-61
Moved closed ZFS files to open repo, changed Makefiles accordingly
Removed unneeded weak symbols
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 #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)
Bug 11205: add missing libzfs_closed_stubs.c to fix opensource-only build.
ZFS plus work: special vdevs, cos, cos/vdev properties

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs/common/libzfs_pool.c
          +++ new/usr/src/lib/libzfs/common/libzfs_pool.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, 2017 by Delphix. All rights reserved.
       24 + * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  26      - * Copyright 2016 Nexenta Systems, Inc.
  27   26   * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
       27 + * Copyright 2017 Nexenta Systems, Inc.
  28   28   * Copyright (c) 2017 Datto Inc.
  29   29   */
  30   30  
  31   31  #include <ctype.h>
  32   32  #include <errno.h>
  33   33  #include <devid.h>
  34   34  #include <fcntl.h>
  35   35  #include <libintl.h>
  36   36  #include <stdio.h>
  37   37  #include <stdlib.h>
↓ open down ↓ 5 lines elided ↑ open up ↑
  43   43  #include <sys/zfs_ioctl.h>
  44   44  #include <dlfcn.h>
  45   45  
  46   46  #include "zfs_namecheck.h"
  47   47  #include "zfs_prop.h"
  48   48  #include "libzfs_impl.h"
  49   49  #include "zfs_comutil.h"
  50   50  #include "zfeature_common.h"
  51   51  
  52   52  static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
  53      -static boolean_t zpool_vdev_is_interior(const char *name);
  54   53  
  55   54  #define BACKUP_SLICE    "s2"
  56   55  
  57   56  typedef struct prop_flags {
  58   57          int create:1;   /* Validate property on creation */
  59   58          int import:1;   /* Validate property on import */
  60   59  } prop_flags_t;
  61   60  
  62   61  /*
  63   62   * ====================================================================
↓ open down ↓ 353 lines elided ↑ open up ↑
 417  416  }
 418  417  
 419  418  
 420  419  /*
 421  420   * Given an nvlist of zpool properties to be set, validate that they are
 422  421   * correct, and parse any numeric properties (index, boolean, etc) if they are
 423  422   * specified as strings.
 424  423   */
 425  424  static nvlist_t *
 426  425  zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
 427      -    nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
      426 +    nvlist_t *props, uint64_t version, prop_flags_t flags, const char *errbuf)
 428  427  {
 429  428          nvpair_t *elem;
 430  429          nvlist_t *retprops;
 431  430          zpool_prop_t prop;
 432  431          char *strval;
 433  432          uint64_t intval;
 434  433          char *slash, *check;
 435  434          struct stat64 statbuf;
 436  435          zpool_handle_t *zhp;
 437  436  
 438  437          if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
 439  438                  (void) no_memory(hdl);
 440  439                  return (NULL);
 441  440          }
 442  441  
 443  442          elem = NULL;
 444  443          while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 445  444                  const char *propname = nvpair_name(elem);
 446  445  
 447  446                  prop = zpool_name_to_prop(propname);
 448      -                if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
      447 +                if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
 449  448                          int err;
 450  449                          char *fname = strchr(propname, '@') + 1;
 451  450  
 452  451                          err = zfeature_lookup_name(fname, NULL);
 453  452                          if (err != 0) {
 454  453                                  ASSERT3U(err, ==, ENOENT);
 455  454                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 456  455                                      "invalid feature '%s'"), fname);
 457  456                                  (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 458  457                                  goto error;
↓ open down ↓ 18 lines elided ↑ open up ↑
 477  476                          if (nvlist_add_uint64(retprops, propname, 0) != 0) {
 478  477                                  (void) no_memory(hdl);
 479  478                                  goto error;
 480  479                          }
 481  480                          continue;
 482  481                  }
 483  482  
 484  483                  /*
 485  484                   * Make sure this property is valid and applies to this type.
 486  485                   */
 487      -                if (prop == ZPOOL_PROP_INVAL) {
      486 +                if (prop == ZPROP_INVAL) {
 488  487                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 489  488                              "invalid property '%s'"), propname);
 490  489                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 491  490                          goto error;
 492  491                  }
 493  492  
 494  493                  if (zpool_prop_readonly(prop)) {
 495  494                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
 496  495                              "is readonly"), propname);
 497  496                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
↓ open down ↓ 219 lines elided ↑ open up ↑
 717  716          nvlist_free(nvl);
 718  717  
 719  718          if (ret)
 720  719                  (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
 721  720          else
 722  721                  (void) zpool_props_refresh(zhp);
 723  722  
 724  723          return (ret);
 725  724  }
 726  725  
      726 +/*
      727 + * Set zpool properties nvlist
      728 + */
 727  729  int
      730 +zpool_set_proplist(zpool_handle_t *zhp, nvlist_t *nvl)
      731 +{
      732 +        zfs_cmd_t zc = { 0 };
      733 +        int ret = -1;
      734 +        char errbuf[1024];
      735 +        nvlist_t *realprops;
      736 +        uint64_t version;
      737 +        prop_flags_t flags = { 0 };
      738 +
      739 +        assert(nvl != NULL);
      740 +
      741 +        (void) snprintf(errbuf, sizeof (errbuf),
      742 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
      743 +            zhp->zpool_name);
      744 +
      745 +        version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
      746 +        if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
      747 +            zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
      748 +                nvlist_free(nvl);
      749 +                return (-1);
      750 +        }
      751 +
      752 +        nvlist_free(nvl);
      753 +        nvl = realprops;
      754 +
      755 +        /*
      756 +         * Execute the corresponding ioctl() to set this property.
      757 +         */
      758 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
      759 +
      760 +        if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
      761 +                nvlist_free(nvl);
      762 +                return (-1);
      763 +        }
      764 +
      765 +        ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
      766 +
      767 +        zcmd_free_nvlists(&zc);
      768 +        nvlist_free(nvl);
      769 +
      770 +        if (ret)
      771 +                (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
      772 +        else
      773 +                (void) zpool_props_refresh(zhp);
      774 +
      775 +        return (ret);
      776 +}
      777 +
      778 +int
 728  779  zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
 729  780  {
 730  781          libzfs_handle_t *hdl = zhp->zpool_hdl;
 731  782          zprop_list_t *entry;
 732  783          char buf[ZFS_MAXPROPLEN];
 733  784          nvlist_t *features = NULL;
 734  785          zprop_list_t **last;
 735  786          boolean_t firstexpand = (NULL == *plp);
 736  787  
 737  788          if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
↓ open down ↓ 372 lines elided ↑ open up ↑
1110 1161   */
1111 1162  int
1112 1163  zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
1113 1164      nvlist_t *props, nvlist_t *fsprops)
1114 1165  {
1115 1166          zfs_cmd_t zc = { 0 };
1116 1167          nvlist_t *zc_fsprops = NULL;
1117 1168          nvlist_t *zc_props = NULL;
1118 1169          char msg[1024];
1119 1170          int ret = -1;
     1171 +        boolean_t wbc_mode_prop_exists = B_FALSE;
1120 1172  
1121 1173          (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1122 1174              "cannot create '%s'"), pool);
1123 1175  
1124 1176          if (!zpool_name_valid(hdl, B_FALSE, pool))
1125 1177                  return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
1126 1178  
1127 1179          if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
1128 1180                  return (-1);
1129 1181  
↓ open down ↓ 11 lines elided ↑ open up ↑
1141 1193                  char *zonestr;
1142 1194  
1143 1195                  zoned = ((nvlist_lookup_string(fsprops,
1144 1196                      zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
1145 1197                      strcmp(zonestr, "on") == 0);
1146 1198  
1147 1199                  if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
1148 1200                      fsprops, zoned, NULL, NULL, msg)) == NULL) {
1149 1201                          goto create_failed;
1150 1202                  }
     1203 +
     1204 +                if (nvlist_exists(zc_fsprops,
     1205 +                    zfs_prop_to_name(ZFS_PROP_WBC_MODE))) {
     1206 +                        wbc_mode_prop_exists = B_TRUE;
     1207 +                }
     1208 +
1151 1209                  if (!zc_props &&
1152 1210                      (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
1153 1211                          goto create_failed;
1154 1212                  }
1155 1213                  if (nvlist_add_nvlist(zc_props,
1156 1214                      ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
1157 1215                          goto create_failed;
1158 1216                  }
1159 1217          }
1160 1218  
↓ open down ↓ 56 lines elided ↑ open up ↑
1217 1275                  case ENOSPC:
1218 1276                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1219 1277                              "one or more devices is out of space"));
1220 1278                          return (zfs_error(hdl, EZFS_BADDEV, msg));
1221 1279  
1222 1280                  case ENOTBLK:
1223 1281                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1224 1282                              "cache device must be a disk or disk slice"));
1225 1283                          return (zfs_error(hdl, EZFS_BADDEV, msg));
1226 1284  
     1285 +                case EALREADY:
     1286 +                        if (wbc_mode_prop_exists) {
     1287 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     1288 +                                    "WBC is already in the OFF state"));
     1289 +                                return (zfs_error(hdl, EZFS_WBCALREADY, msg));
     1290 +                        }
     1291 +
1227 1292                  default:
1228 1293                          return (zpool_standard_error(hdl, errno, msg));
1229 1294                  }
1230 1295          }
1231 1296  
1232 1297  create_failed:
1233 1298          zcmd_free_nvlists(&zc);
1234 1299          nvlist_free(zc_props);
1235 1300          nvlist_free(zc_fsprops);
1236 1301          return (ret);
↓ open down ↓ 89 lines elided ↑ open up ↑
1326 1391                           * This can happen if the user has specified the same
1327 1392                           * device multiple times.  We can't reliably detect this
1328 1393                           * until we try to add it and see we already have a
1329 1394                           * label.
1330 1395                           */
1331 1396                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1332 1397                              "one or more vdevs refer to the same device"));
1333 1398                          (void) zfs_error(hdl, EZFS_BADDEV, msg);
1334 1399                          break;
1335 1400  
1336      -                case EINVAL:
1337      -                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1338      -                            "invalid config; a pool with removing/removed "
1339      -                            "vdevs does not support adding raidz vdevs"));
1340      -                        (void) zfs_error(hdl, EZFS_BADDEV, msg);
1341      -                        break;
1342      -
1343 1401                  case EOVERFLOW:
1344 1402                          /*
1345 1403                           * This occurrs when one of the devices is below
1346 1404                           * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1347 1405                           * device was the problem device since there's no
1348 1406                           * reliable way to determine device size from userland.
1349 1407                           */
1350 1408                          {
1351 1409                                  char buf[64];
1352 1410  
↓ open down ↓ 38 lines elided ↑ open up ↑
1391 1449  
1392 1450          return (ret);
1393 1451  }
1394 1452  
1395 1453  /*
1396 1454   * Exports the pool from the system.  The caller must ensure that there are no
1397 1455   * mounted datasets in the pool.
1398 1456   */
1399 1457  static int
1400 1458  zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
1401      -    const char *log_str)
     1459 +    boolean_t saveconfig, const char *log_str)
1402 1460  {
1403 1461          zfs_cmd_t zc = { 0 };
1404 1462          char msg[1024];
1405 1463  
1406 1464          (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1407 1465              "cannot export '%s'"), zhp->zpool_name);
1408 1466  
1409 1467          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1410 1468          zc.zc_cookie = force;
1411 1469          zc.zc_guid = hardforce;
     1470 +        zc.zc_obj = saveconfig;
1412 1471          zc.zc_history = (uint64_t)(uintptr_t)log_str;
1413 1472  
1414 1473          if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
1415 1474                  switch (errno) {
1416 1475                  case EXDEV:
1417 1476                          zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
1418 1477                              "use '-f' to override the following errors:\n"
1419 1478                              "'%s' has an active shared spare which could be"
1420 1479                              " used by other pools once '%s' is exported."),
1421 1480                              zhp->zpool_name, zhp->zpool_name);
↓ open down ↓ 2 lines elided ↑ open up ↑
1424 1483                  default:
1425 1484                          return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
1426 1485                              msg));
1427 1486                  }
1428 1487          }
1429 1488  
1430 1489          return (0);
1431 1490  }
1432 1491  
1433 1492  int
1434      -zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
     1493 +zpool_export(zpool_handle_t *zhp, boolean_t force, boolean_t saveconfig,
     1494 +    const char *log_str)
1435 1495  {
1436      -        return (zpool_export_common(zhp, force, B_FALSE, log_str));
     1496 +        return (zpool_export_common(zhp, force, B_FALSE, saveconfig, log_str));
1437 1497  }
1438 1498  
1439 1499  int
1440      -zpool_export_force(zpool_handle_t *zhp, const char *log_str)
     1500 +zpool_export_force(zpool_handle_t *zhp, boolean_t saveconfig,
     1501 +    const char *log_str)
1441 1502  {
1442      -        return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
     1503 +        return (zpool_export_common(zhp, B_TRUE, B_TRUE, saveconfig, log_str));
1443 1504  }
1444 1505  
1445 1506  static void
1446 1507  zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
1447 1508      nvlist_t *config)
1448 1509  {
1449 1510          nvlist_t *nv = NULL;
1450 1511          uint64_t rewindto;
1451 1512          int64_t loss = -1;
1452 1513          struct tm t;
↓ open down ↓ 348 lines elided ↑ open up ↑
1801 1862                              "one or more devices is read only"));
1802 1863                          (void) zfs_error(hdl, EZFS_BADDEV, desc);
1803 1864                          break;
1804 1865  
1805 1866                  case ENXIO:
1806 1867                          if (nv && nvlist_lookup_nvlist(nv,
1807 1868                              ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
1808 1869                              nvlist_lookup_nvlist(nvinfo,
1809 1870                              ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) {
1810 1871                                  (void) printf(dgettext(TEXT_DOMAIN,
1811      -                                    "The devices below are missing or "
1812      -                                    "corrupted, use '-m' to import the pool "
1813      -                                    "anyway:\n"));
     1872 +                                    "The devices below are missing, use "
     1873 +                                    "'-m' to import the pool anyway:\n"));
1814 1874                                  print_vdev_tree(hdl, NULL, missing, 2);
1815 1875                                  (void) printf("\n");
1816 1876                          }
1817 1877                          (void) zpool_standard_error(hdl, error, desc);
1818 1878                          break;
1819 1879  
1820 1880                  case EEXIST:
1821 1881                          (void) zpool_standard_error(hdl, error, desc);
1822 1882                          break;
1823 1883                  case ENAMETOOLONG:
↓ open down ↓ 96 lines elided ↑ open up ↑
1920 1980                          return (zfs_error(hdl, EZFS_RESILVERING, msg));
1921 1981                  }
1922 1982          } else if (err == ENOENT) {
1923 1983                  return (zfs_error(hdl, EZFS_NO_SCRUB, msg));
1924 1984          } else {
1925 1985                  return (zpool_standard_error(hdl, err, msg));
1926 1986          }
1927 1987  }
1928 1988  
1929 1989  /*
     1990 + * Trim the pool.
     1991 + */
     1992 +int
     1993 +zpool_trim(zpool_handle_t *zhp, boolean_t start, uint64_t rate)
     1994 +{
     1995 +        zfs_cmd_t zc = { 0 };
     1996 +        char msg[1024];
     1997 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     1998 +        trim_cmd_info_t tci = { .tci_start = start, .tci_rate = rate };
     1999 +
     2000 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     2001 +        zc.zc_cookie = (uintptr_t)&tci;
     2002 +
     2003 +        if (zfs_ioctl(hdl, ZFS_IOC_POOL_TRIM, &zc) == 0)
     2004 +                return (0);
     2005 +
     2006 +        return (zpool_standard_error(hdl, errno, msg));
     2007 +}
     2008 +
     2009 +/*
1930 2010   * This provides a very minimal check whether a given string is likely a
1931 2011   * c#t#d# style string.  Users of this are expected to do their own
1932 2012   * verification of the s# part.
1933 2013   */
1934 2014  #define CTD_CHECK(str)  (str && str[0] == 'c' && isdigit(str[1]))
1935 2015  
1936 2016  /*
1937 2017   * More elaborate version for ones which may start with "/dev/dsk/"
1938 2018   * and the like.
1939 2019   */
↓ open down ↓ 20 lines elided ↑ open up ↑
1960 2040  }
1961 2041  
1962 2042  /*
1963 2043   * Find a vdev that matches the search criteria specified. We use the
1964 2044   * the nvpair name to determine how we should look for the device.
1965 2045   * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
1966 2046   * spare; but FALSE if its an INUSE spare.
1967 2047   */
1968 2048  static nvlist_t *
1969 2049  vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
1970      -    boolean_t *l2cache, boolean_t *log)
     2050 +    boolean_t *l2cache, boolean_t *log, boolean_t *special)
1971 2051  {
1972 2052          uint_t c, children;
1973 2053          nvlist_t **child;
1974 2054          nvlist_t *ret;
1975      -        uint64_t is_log;
     2055 +        uint64_t is_log, is_special;
1976 2056          char *srchkey;
1977 2057          nvpair_t *pair = nvlist_next_nvpair(search, NULL);
1978 2058  
1979 2059          /* Nothing to look for */
1980 2060          if (search == NULL || pair == NULL)
1981 2061                  return (NULL);
1982 2062  
1983 2063          /* Obtain the key we will use to search */
1984 2064          srchkey = nvpair_name(pair);
1985 2065  
↓ open down ↓ 88 lines elided ↑ open up ↑
2074 2154                          *p = '\0';
2075 2155  
2076 2156                          /*
2077 2157                           * If the types don't match then keep looking.
2078 2158                           */
2079 2159                          if (strncmp(val, type, strlen(val)) != 0) {
2080 2160                                  free(type);
2081 2161                                  break;
2082 2162                          }
2083 2163  
2084      -                        verify(zpool_vdev_is_interior(type));
     2164 +                        verify(strncmp(type, VDEV_TYPE_RAIDZ,
     2165 +                            strlen(VDEV_TYPE_RAIDZ)) == 0 ||
     2166 +                            strncmp(type, VDEV_TYPE_MIRROR,
     2167 +                            strlen(VDEV_TYPE_MIRROR)) == 0);
2085 2168                          verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
2086 2169                              &id) == 0);
2087 2170  
2088 2171                          errno = 0;
2089 2172                          vdev_id = strtoull(idx, &end, 10);
2090 2173  
2091 2174                          free(type);
2092 2175                          if (errno != 0)
2093 2176                                  return (NULL);
2094 2177  
↓ open down ↓ 15 lines elided ↑ open up ↑
2110 2193          default:
2111 2194                  break;
2112 2195          }
2113 2196  
2114 2197          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2115 2198              &child, &children) != 0)
2116 2199                  return (NULL);
2117 2200  
2118 2201          for (c = 0; c < children; c++) {
2119 2202                  if ((ret = vdev_to_nvlist_iter(child[c], search,
2120      -                    avail_spare, l2cache, NULL)) != NULL) {
     2203 +                    avail_spare, l2cache, NULL, NULL)) != NULL) {
2121 2204                          /*
2122 2205                           * The 'is_log' value is only set for the toplevel
2123 2206                           * vdev, not the leaf vdevs.  So we always lookup the
2124 2207                           * log device from the root of the vdev tree (where
2125 2208                           * 'log' is non-NULL).
2126 2209                           */
2127 2210                          if (log != NULL &&
2128 2211                              nvlist_lookup_uint64(child[c],
2129 2212                              ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
2130 2213                              is_log) {
2131 2214                                  *log = B_TRUE;
2132 2215                          }
     2216 +
     2217 +                        if (special != NULL &&
     2218 +                            nvlist_lookup_uint64(child[c],
     2219 +                            ZPOOL_CONFIG_IS_SPECIAL, &is_special) == 0 &&
     2220 +                            is_special) {
     2221 +                                *special = B_TRUE;
     2222 +                        }
     2223 +
2133 2224                          return (ret);
2134 2225                  }
2135 2226          }
2136 2227  
2137 2228          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
2138 2229              &child, &children) == 0) {
2139 2230                  for (c = 0; c < children; c++) {
2140 2231                          if ((ret = vdev_to_nvlist_iter(child[c], search,
2141      -                            avail_spare, l2cache, NULL)) != NULL) {
     2232 +                            avail_spare, l2cache, NULL, NULL)) != NULL) {
2142 2233                                  *avail_spare = B_TRUE;
2143 2234                                  return (ret);
2144 2235                          }
2145 2236                  }
2146 2237          }
2147 2238  
2148 2239          if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2149 2240              &child, &children) == 0) {
2150 2241                  for (c = 0; c < children; c++) {
2151 2242                          if ((ret = vdev_to_nvlist_iter(child[c], search,
2152      -                            avail_spare, l2cache, NULL)) != NULL) {
     2243 +                            avail_spare, l2cache, NULL, NULL)) != NULL) {
2153 2244                                  *l2cache = B_TRUE;
2154 2245                                  return (ret);
2155 2246                          }
2156 2247                  }
2157 2248          }
2158 2249  
2159 2250          return (NULL);
2160 2251  }
2161 2252  
2162 2253  /*
↓ open down ↓ 9 lines elided ↑ open up ↑
2172 2263          verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
2173 2264          verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
2174 2265  
2175 2266          verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
2176 2267              &nvroot) == 0);
2177 2268  
2178 2269          *avail_spare = B_FALSE;
2179 2270          *l2cache = B_FALSE;
2180 2271          if (log != NULL)
2181 2272                  *log = B_FALSE;
2182      -        ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
     2273 +        ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
     2274 +            NULL);
2183 2275          nvlist_free(search);
2184 2276  
2185 2277          return (ret);
2186 2278  }
2187 2279  
2188 2280  /*
2189 2281   * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
2190 2282   */
2191      -static boolean_t
     2283 +boolean_t
2192 2284  zpool_vdev_is_interior(const char *name)
2193 2285  {
2194 2286          if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
2195      -            strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
2196      -            strncmp(name,
2197      -            VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
2198 2287              strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
2199 2288                  return (B_TRUE);
2200 2289          return (B_FALSE);
2201 2290  }
2202 2291  
2203 2292  nvlist_t *
2204 2293  zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
2205      -    boolean_t *l2cache, boolean_t *log)
     2294 +    boolean_t *l2cache, boolean_t *log, boolean_t *special)
2206 2295  {
2207 2296          char buf[MAXPATHLEN];
2208 2297          char *end;
2209 2298          nvlist_t *nvroot, *search, *ret;
2210 2299          uint64_t guid;
2211 2300  
2212 2301          verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
2213 2302  
2214 2303          guid = strtoull(path, &end, 10);
2215 2304          if (guid != 0 && *end == '\0') {
↓ open down ↓ 8 lines elided ↑ open up ↑
2224 2313                  verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
2225 2314          }
2226 2315  
2227 2316          verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
2228 2317              &nvroot) == 0);
2229 2318  
2230 2319          *avail_spare = B_FALSE;
2231 2320          *l2cache = B_FALSE;
2232 2321          if (log != NULL)
2233 2322                  *log = B_FALSE;
2234      -        ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
     2323 +
     2324 +        if (special != NULL)
     2325 +                *special = B_FALSE;
     2326 +
     2327 +        ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
     2328 +            special);
2235 2329          nvlist_free(search);
2236 2330  
2237 2331          return (ret);
2238 2332  }
2239 2333  
2240 2334  static int
2241 2335  vdev_online(nvlist_t *nv)
2242 2336  {
2243 2337          uint64_t ival;
2244 2338  
↓ open down ↓ 197 lines elided ↑ open up ↑
2442 2536          if (flags & ZFS_ONLINE_EXPAND) {
2443 2537                  (void) snprintf(msg, sizeof (msg),
2444 2538                      dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
2445 2539          } else {
2446 2540                  (void) snprintf(msg, sizeof (msg),
2447 2541                      dgettext(TEXT_DOMAIN, "cannot online %s"), path);
2448 2542          }
2449 2543  
2450 2544          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2451 2545          if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2452      -            &islog)) == NULL)
     2546 +            &islog, NULL)) == NULL)
2453 2547                  return (zfs_error(hdl, EZFS_NODEVICE, msg));
2454 2548  
2455 2549          verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2456 2550  
2457      -        if (avail_spare)
2458      -                return (zfs_error(hdl, EZFS_ISSPARE, msg));
2459      -
2460 2551          if ((flags & ZFS_ONLINE_EXPAND ||
2461 2552              zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) &&
2462 2553              nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) {
2463 2554                  uint64_t wholedisk = 0;
2464 2555  
2465 2556                  (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
2466 2557                      &wholedisk);
2467 2558  
2468 2559                  /*
2469 2560                   * XXX - L2ARC 1.0 devices can't support expansion.
↓ open down ↓ 37 lines elided ↑ open up ↑
2507 2598          char msg[1024];
2508 2599          nvlist_t *tgt;
2509 2600          boolean_t avail_spare, l2cache;
2510 2601          libzfs_handle_t *hdl = zhp->zpool_hdl;
2511 2602  
2512 2603          (void) snprintf(msg, sizeof (msg),
2513 2604              dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
2514 2605  
2515 2606          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2516 2607          if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2517      -            NULL)) == NULL)
     2608 +            NULL, NULL)) == NULL)
2518 2609                  return (zfs_error(hdl, EZFS_NODEVICE, msg));
2519 2610  
2520 2611          verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2521 2612  
2522 2613          if (avail_spare)
2523 2614                  return (zfs_error(hdl, EZFS_ISSPARE, msg));
2524 2615  
2525 2616          zc.zc_cookie = VDEV_STATE_OFFLINE;
2526 2617          zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
2527 2618  
↓ open down ↓ 129 lines elided ↑ open up ↑
2657 2748  
2658 2749          if (replacing)
2659 2750                  (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2660 2751                      "cannot replace %s with %s"), old_disk, new_disk);
2661 2752          else
2662 2753                  (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2663 2754                      "cannot attach %s to %s"), new_disk, old_disk);
2664 2755  
2665 2756          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2666 2757          if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
2667      -            &islog)) == NULL)
     2758 +            &islog, NULL)) == 0)
2668 2759                  return (zfs_error(hdl, EZFS_NODEVICE, msg));
2669 2760  
2670 2761          if (avail_spare)
2671 2762                  return (zfs_error(hdl, EZFS_ISSPARE, msg));
2672 2763  
2673 2764          if (l2cache)
2674 2765                  return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2675 2766  
2676 2767          verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2677 2768          zc.zc_cookie = replacing;
↓ open down ↓ 11 lines elided ↑ open up ↑
2689 2780          if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL)
2690 2781                  return (-1);
2691 2782  
2692 2783          /*
2693 2784           * If the target is a hot spare that has been swapped in, we can only
2694 2785           * replace it with another hot spare.
2695 2786           */
2696 2787          if (replacing &&
2697 2788              nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
2698 2789              (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
2699      -            NULL) == NULL || !avail_spare) &&
     2790 +            NULL, NULL) == NULL || !avail_spare) &&
2700 2791              is_replacing_spare(config_root, tgt, 1)) {
2701 2792                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2702 2793                      "can only be replaced by another hot spare"));
2703 2794                  free(newname);
2704 2795                  return (zfs_error(hdl, EZFS_BADTARGET, msg));
2705 2796          }
2706 2797  
2707 2798          free(newname);
2708 2799  
2709 2800          if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
↓ open down ↓ 46 lines elided ↑ open up ↑
2756 2847          case EINVAL:
2757 2848                  /*
2758 2849                   * The new device must be a single disk.
2759 2850                   */
2760 2851                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2761 2852                      "new device must be a single disk"));
2762 2853                  (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
2763 2854                  break;
2764 2855  
2765 2856          case EBUSY:
2766      -                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy, "
2767      -                    "or pool has removing/removed vdevs"),
     2857 +                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
2768 2858                      new_disk);
2769 2859                  (void) zfs_error(hdl, EZFS_BADDEV, msg);
2770 2860                  break;
2771 2861  
2772 2862          case EOVERFLOW:
2773 2863                  /*
2774 2864                   * The new device is too small.
2775 2865                   */
2776 2866                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2777 2867                      "device is too small"));
↓ open down ↓ 33 lines elided ↑ open up ↑
2811 2901          char msg[1024];
2812 2902          nvlist_t *tgt;
2813 2903          boolean_t avail_spare, l2cache;
2814 2904          libzfs_handle_t *hdl = zhp->zpool_hdl;
2815 2905  
2816 2906          (void) snprintf(msg, sizeof (msg),
2817 2907              dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
2818 2908  
2819 2909          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2820 2910          if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2821      -            NULL)) == NULL)
     2911 +            NULL, NULL)) == 0)
2822 2912                  return (zfs_error(hdl, EZFS_NODEVICE, msg));
2823 2913  
2824 2914          if (avail_spare)
2825 2915                  return (zfs_error(hdl, EZFS_ISSPARE, msg));
2826 2916  
2827 2917          if (l2cache)
2828 2918                  return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2829 2919  
2830 2920          verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2831 2921  
↓ open down ↓ 268 lines elided ↑ open up ↑
3100 3190          if (retval != 0)
3101 3191                  return (retval);
3102 3192  
3103 3193          if (memory_err)
3104 3194                  return (no_memory(hdl));
3105 3195  
3106 3196          return (0);
3107 3197  }
3108 3198  
3109 3199  /*
3110      - * Remove the given device.
     3200 + * Remove the given device.  Currently, this is supported only for hot spares
     3201 + * and level 2 cache devices.
3111 3202   */
3112 3203  int
3113 3204  zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
3114 3205  {
3115 3206          zfs_cmd_t zc = { 0 };
3116 3207          char msg[1024];
3117 3208          nvlist_t *tgt;
3118      -        boolean_t avail_spare, l2cache, islog;
     3209 +        boolean_t avail_spare, l2cache, islog, isspecial;
3119 3210          libzfs_handle_t *hdl = zhp->zpool_hdl;
3120 3211          uint64_t version;
3121 3212  
3122 3213          (void) snprintf(msg, sizeof (msg),
3123 3214              dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
3124 3215  
3125 3216          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3126 3217          if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
3127      -            &islog)) == NULL)
     3218 +            &islog, &isspecial)) == 0)
3128 3219                  return (zfs_error(hdl, EZFS_NODEVICE, msg));
     3220 +        /*
     3221 +         * XXX - this should just go away.
     3222 +         */
     3223 +        if (!avail_spare && !l2cache && !islog && !isspecial) {
     3224 +                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     3225 +                    "only inactive hot spares, cache, top-level, "
     3226 +                    "log, or special devices can be removed"));
     3227 +                return (zfs_error(hdl, EZFS_NODEVICE, msg));
     3228 +        }
3129 3229  
3130 3230          version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3131 3231          if (islog && version < SPA_VERSION_HOLES) {
3132 3232                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3133      -                    "pool must be upgraded to support log removal"));
     3233 +                    "pool must be upgrade to support log removal"));
3134 3234                  return (zfs_error(hdl, EZFS_BADVERSION, msg));
3135 3235          }
3136 3236  
3137      -        if (!islog && !avail_spare && !l2cache && zpool_is_bootable(zhp)) {
3138      -                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3139      -                    "root pool can not have removed devices, "
3140      -                    "because GRUB does not understand them"));
3141      -                return (zfs_error(hdl, EINVAL, msg));
3142      -        }
     3237 +        verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
3143 3238  
3144      -        zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
3145      -
3146 3239          if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
3147 3240                  return (0);
3148 3241  
3149      -        switch (errno) {
3150      -
3151      -        case EINVAL:
     3242 +        if (isspecial && errno == EEXIST) {
3152 3243                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3153      -                    "invalid config; all top-level vdevs must "
3154      -                    "have the same sector size and not be raidz."));
3155      -                (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
3156      -                break;
3157      -
3158      -        case EBUSY:
     3244 +                    "special device contains metadata"));
     3245 +                return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
     3246 +        } else if (isspecial && errno == EBUSY) {
3159 3247                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3160      -                    "Pool busy; removal may already be in progress"));
3161      -                (void) zfs_error(hdl, EZFS_BUSY, msg);
3162      -                break;
3163      -
3164      -        default:
3165      -                (void) zpool_standard_error(hdl, errno, msg);
     3248 +                    "wbc feature flag is active"));
     3249 +                return (zfs_error(hdl, EZFS_WBCCHILD, msg));
3166 3250          }
3167      -        return (-1);
3168      -}
3169 3251  
3170      -int
3171      -zpool_vdev_remove_cancel(zpool_handle_t *zhp)
3172      -{
3173      -        zfs_cmd_t zc = { 0 };
3174      -        char msg[1024];
3175      -        libzfs_handle_t *hdl = zhp->zpool_hdl;
3176      -
3177      -        (void) snprintf(msg, sizeof (msg),
3178      -            dgettext(TEXT_DOMAIN, "cannot cancel removal"));
3179      -
3180      -        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3181      -        zc.zc_cookie = 1;
3182      -
3183      -        if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
3184      -                return (0);
3185      -
3186 3252          return (zpool_standard_error(hdl, errno, msg));
3187 3253  }
3188 3254  
3189      -int
3190      -zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path,
3191      -    uint64_t *sizep)
3192      -{
3193      -        char msg[1024];
3194      -        nvlist_t *tgt;
3195      -        boolean_t avail_spare, l2cache, islog;
3196      -        libzfs_handle_t *hdl = zhp->zpool_hdl;
3197      -
3198      -        (void) snprintf(msg, sizeof (msg),
3199      -            dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"),
3200      -            path);
3201      -
3202      -        if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
3203      -            &islog)) == NULL)
3204      -                return (zfs_error(hdl, EZFS_NODEVICE, msg));
3205      -
3206      -        if (avail_spare || l2cache || islog) {
3207      -                *sizep = 0;
3208      -                return (0);
3209      -        }
3210      -
3211      -        if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) {
3212      -                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3213      -                    "indirect size not available"));
3214      -                return (zfs_error(hdl, EINVAL, msg));
3215      -        }
3216      -        return (0);
3217      -}
3218      -
3219 3255  /*
3220 3256   * Clear the errors for the pool, or the particular device if specified.
3221 3257   */
3222 3258  int
3223 3259  zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
3224 3260  {
3225 3261          zfs_cmd_t zc = { 0 };
3226 3262          char msg[1024];
3227 3263          nvlist_t *tgt;
3228 3264          zpool_rewind_policy_t policy;
↓ open down ↓ 7 lines elided ↑ open up ↑
3236 3272                      dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
3237 3273                      path);
3238 3274          else
3239 3275                  (void) snprintf(msg, sizeof (msg),
3240 3276                      dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
3241 3277                      zhp->zpool_name);
3242 3278  
3243 3279          (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3244 3280          if (path) {
3245 3281                  if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
3246      -                    &l2cache, NULL)) == NULL)
     3282 +                    &l2cache, NULL, NULL)) == 0)
3247 3283                          return (zfs_error(hdl, EZFS_NODEVICE, msg));
3248 3284  
3249 3285                  /*
3250 3286                   * Don't allow error clearing for hot spares.  Do allow
3251 3287                   * error clearing for l2cache devices.
3252 3288                   */
3253 3289                  if (avail_spare)
3254 3290                          return (zfs_error(hdl, EZFS_ISSPARE, msg));
3255 3291  
3256 3292                  verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
↓ open down ↓ 135 lines elided ↑ open up ↑
3392 3428  /*
3393 3429   * Convert from a path to a devid string.
3394 3430   */
3395 3431  static char *
3396 3432  path_to_devid(const char *path)
3397 3433  {
3398 3434          int fd;
3399 3435          ddi_devid_t devid;
3400 3436          char *minor, *ret;
3401 3437  
3402      -        if ((fd = open(path, O_RDONLY)) < 0)
     3438 +        if ((fd = open(path, O_RDONLY | O_NDELAY)) < 0)
3403 3439                  return (NULL);
3404 3440  
3405 3441          minor = NULL;
3406 3442          ret = NULL;
3407 3443          if (devid_get(fd, &devid) == 0) {
3408 3444                  if (devid_get_minor_name(fd, &minor) == 0)
3409 3445                          ret = devid_str_encode(devid, minor);
3410 3446                  if (minor != NULL)
3411 3447                          devid_str_free(minor);
3412 3448                  devid_free(devid);
↓ open down ↓ 296 lines elided ↑ open up ↑
3709 3745          args = fnvlist_alloc();
3710 3746          fnvlist_add_string(args, "message", message);
3711 3747          err = zcmd_write_src_nvlist(hdl, &zc, args);
3712 3748          if (err == 0)
3713 3749                  err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
3714 3750          nvlist_free(args);
3715 3751          zcmd_free_nvlists(&zc);
3716 3752          return (err);
3717 3753  }
3718 3754  
     3755 +int
     3756 +zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
     3757 +{
     3758 +        if (history_str == NULL)
     3759 +                return (EINVAL);
     3760 +
     3761 +        if (hdl->libzfs_log_str != NULL)
     3762 +                free(hdl->libzfs_log_str);
     3763 +
     3764 +        if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
     3765 +                return (no_memory(hdl));
     3766 +
     3767 +        return (0);
     3768 +}
     3769 +
3719 3770  /*
3720 3771   * Perform ioctl to get some command history of a pool.
3721 3772   *
3722 3773   * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
3723 3774   * logical offset of the history buffer to start reading from.
3724 3775   *
3725 3776   * Upon return, 'off' is the next logical offset to read from and
3726 3777   * 'len' is the actual amount of bytes read into 'buf'.
3727 3778   */
3728 3779  static int
↓ open down ↓ 550 lines elided ↑ open up ↑
4279 4330                  goto out;
4280 4331          }
4281 4332          ret = 0;
4282 4333  
4283 4334  out:
4284 4335          if (zhp)
4285 4336                  zpool_close(zhp);
4286 4337          libzfs_fini(hdl);
4287 4338          return (ret);
4288 4339  }
     4340 +
     4341 +/*
     4342 + * Vdev props
     4343 + */
     4344 +static int
     4345 +vdev_get_guid(zpool_handle_t *zhp, const char *path, uint64_t *guid)
     4346 +{
     4347 +        nvlist_t *nvl;
     4348 +        boolean_t avail_spare, l2cache, islog;
     4349 +
     4350 +        if ((nvl = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
     4351 +            &islog, NULL)) == NULL)
     4352 +                return (1);
     4353 +        verify(nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, guid) == 0);
     4354 +        return (0);
     4355 +}
     4356 +
     4357 +/*
     4358 + * Given an nvlist of vdev properties to be set, validate that they are
     4359 + * correct, and parse any numeric properties (index, boolean, etc) if they are
     4360 + * specified as strings.
     4361 + */
     4362 +/*ARGSUSED*/
     4363 +static nvlist_t *
     4364 +vdev_valid_proplist(libzfs_handle_t *hdl, nvlist_t *props,
     4365 +    uint64_t version, prop_flags_t flags, const char *errbuf)
     4366 +{
     4367 +        nvpair_t *elem;
     4368 +        nvlist_t *retprops;
     4369 +        vdev_prop_t prop;
     4370 +        char *strval;
     4371 +        uint64_t intval;
     4372 +
     4373 +        if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
     4374 +                (void) no_memory(hdl);
     4375 +                return (NULL);
     4376 +        }
     4377 +
     4378 +        elem = NULL;
     4379 +        while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
     4380 +                const char *propname = nvpair_name(elem);
     4381 +
     4382 +                /*
     4383 +                 * Make sure this property is valid and applies to this type.
     4384 +                 */
     4385 +                if ((prop = vdev_name_to_prop(propname)) == ZPROP_INVAL) {
     4386 +                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4387 +                            "invalid vdev property '%s'"), propname);
     4388 +                        (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
     4389 +                        goto error;
     4390 +                }
     4391 +
     4392 +                if (vdev_prop_readonly(prop)) {
     4393 +                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
     4394 +                            "is readonly"), propname);
     4395 +                        (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
     4396 +                        goto error;
     4397 +                }
     4398 +
     4399 +                if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_VDEV, retprops,
     4400 +                    &strval, &intval, errbuf) != 0)
     4401 +                        goto error;
     4402 +
     4403 +                /*
     4404 +                 * Perform additional checking for specific properties.
     4405 +                 */
     4406 +                switch (prop) {
     4407 +                case VDEV_PROP_PREFERRED_READ:
     4408 +                        if (intval > 100) {
     4409 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4410 +                                    "'%s' must be from 0 to 100"), propname);
     4411 +                                (void) zfs_error(hdl, EZFS_BADPROP,
     4412 +                                    errbuf);
     4413 +                                goto error;
     4414 +                        }
     4415 +                        break;
     4416 +                case VDEV_PROP_READ_MINACTIVE:
     4417 +                case VDEV_PROP_READ_MAXACTIVE:
     4418 +                case VDEV_PROP_AREAD_MINACTIVE:
     4419 +                case VDEV_PROP_AREAD_MAXACTIVE:
     4420 +                case VDEV_PROP_WRITE_MINACTIVE:
     4421 +                case VDEV_PROP_WRITE_MAXACTIVE:
     4422 +                case VDEV_PROP_AWRITE_MINACTIVE:
     4423 +                case VDEV_PROP_AWRITE_MAXACTIVE:
     4424 +                case VDEV_PROP_SCRUB_MINACTIVE:
     4425 +                case VDEV_PROP_SCRUB_MAXACTIVE:
     4426 +                        if (intval > 1000) {
     4427 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4428 +                                    "'%s' must be from 0 to 1000"), propname);
     4429 +                                (void) zfs_error(hdl, EZFS_BADPROP,
     4430 +                                    errbuf);
     4431 +                                goto error;
     4432 +                        }
     4433 +                        break;
     4434 +                default:
     4435 +                        break;
     4436 +                }
     4437 +        }
     4438 +
     4439 +        return (retprops);
     4440 +error:
     4441 +        nvlist_free(retprops);
     4442 +        return (NULL);
     4443 +}
     4444 +
     4445 +static int
     4446 +vdev_get_all_props(zpool_handle_t *zhp, uint64_t vdev_guid, nvlist_t **nvp)
     4447 +{
     4448 +        zfs_cmd_t zc = { 0 };
     4449 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4450 +
     4451 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4452 +
     4453 +        if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
     4454 +                return (-1);
     4455 +
     4456 +        zc.zc_guid = vdev_guid;
     4457 +        while (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_GET_PROPS, &zc) != 0) {
     4458 +                if (errno == ENOMEM) {
     4459 +                        if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
     4460 +                                zcmd_free_nvlists(&zc);
     4461 +                                return (-1);
     4462 +                        }
     4463 +                } else {
     4464 +                        zcmd_free_nvlists(&zc);
     4465 +                        (void) zfs_error(hdl, EZFS_BADDEV,
     4466 +                            "failed to get vdev properties");
     4467 +                        return (-1);
     4468 +                }
     4469 +        }
     4470 +
     4471 +        if (zcmd_read_dst_nvlist(hdl, &zc, nvp) != 0) {
     4472 +                zcmd_free_nvlists(&zc);
     4473 +                return (-1);
     4474 +        }
     4475 +
     4476 +        zcmd_free_nvlists(&zc);
     4477 +
     4478 +        return (0);
     4479 +}
     4480 +
     4481 +int
     4482 +vdev_get_prop(zpool_handle_t *zhp,  const char *vdev, vdev_prop_t prop,
     4483 +    char *buf, size_t len)
     4484 +{
     4485 +        uint64_t vdev_guid;
     4486 +        uint64_t intval;
     4487 +        const char *strval;
     4488 +        nvlist_t *nvl;
     4489 +        char errbuf[1024];
     4490 +
     4491 +        (void) snprintf(errbuf, sizeof (errbuf),
     4492 +            dgettext(TEXT_DOMAIN, "cannot get property for '%s'"),
     4493 +            zhp->zpool_name);
     4494 +
     4495 +        if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL)
     4496 +                return (-1);
     4497 +
     4498 +        if (vdev_get_guid(zhp, vdev, &vdev_guid) != 0) {
     4499 +                (void) zfs_error(zhp->zpool_hdl, EZFS_BADDEV, errbuf);
     4500 +                return (-1);
     4501 +        }
     4502 +
     4503 +        if (vdev_get_all_props(zhp, vdev_guid, &nvl) != 0)
     4504 +                return (-1);
     4505 +
     4506 +        switch (vdev_prop_get_type(prop)) {
     4507 +        case PROP_TYPE_STRING:
     4508 +                if (nvlist_lookup_string(nvl, vdev_prop_to_name(prop),
     4509 +                    (char **)&strval) != 0)
     4510 +                        if ((strval = (char *)vdev_prop_default_string(prop))
     4511 +                            == NULL)
     4512 +                                strval = "-";
     4513 +
     4514 +                (void) strlcpy(buf, strval, len);
     4515 +                break;
     4516 +
     4517 +        case PROP_TYPE_NUMBER:
     4518 +                if (nvlist_lookup_uint64(nvl, vdev_prop_to_name(prop),
     4519 +                    &intval) != 0)
     4520 +                        intval = vdev_prop_default_numeric(prop);
     4521 +                (void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
     4522 +                break;
     4523 +
     4524 +        case PROP_TYPE_INDEX:
     4525 +                if (nvlist_lookup_uint64(nvl, vdev_prop_to_name(prop),
     4526 +                    &intval) != 0)
     4527 +                        intval = vdev_prop_default_numeric(prop);
     4528 +                if (vdev_prop_index_to_string(prop, intval, &strval) != 0) {
     4529 +                        (void) zfs_error(zhp->zpool_hdl, EZFS_BADPROP, errbuf);
     4530 +                        nvlist_free(nvl);
     4531 +                        return (-1);
     4532 +                }
     4533 +                (void) strlcpy(buf, strval, len);
     4534 +                break;
     4535 +
     4536 +        default:
     4537 +                abort();
     4538 +        }
     4539 +
     4540 +        nvlist_free(nvl);
     4541 +
     4542 +        return (0);
     4543 +}
     4544 +
     4545 +/*
     4546 + * Set vdev property : propname=propval.
     4547 + */
     4548 +int
     4549 +vdev_set_prop(zpool_handle_t *zhp, const char *vdev,
     4550 +    const char *propname, const char *propval)
     4551 +{
     4552 +        zfs_cmd_t zc = { 0 };
     4553 +        int ret = -1;
     4554 +        char errbuf[1024];
     4555 +        nvlist_t *nvl = NULL;
     4556 +        nvlist_t *realprops;
     4557 +        uint64_t version;
     4558 +        uint64_t guid;
     4559 +        prop_flags_t flags = { 0 };
     4560 +
     4561 +        (void) snprintf(errbuf, sizeof (errbuf),
     4562 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
     4563 +            zhp->zpool_name);
     4564 +
     4565 +        if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
     4566 +                return (no_memory(zhp->zpool_hdl));
     4567 +
     4568 +        if (nvlist_add_string(nvl, propname, propval) != 0) {
     4569 +                nvlist_free(nvl);
     4570 +                return (no_memory(zhp->zpool_hdl));
     4571 +        }
     4572 +
     4573 +        if (vdev_get_guid(zhp, vdev, &guid) != 0) {
     4574 +                (void) zfs_error(zhp->zpool_hdl, EZFS_BADDEV, errbuf);
     4575 +                return (-1);
     4576 +        }
     4577 +
     4578 +        version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
     4579 +        if ((realprops = vdev_valid_proplist(zhp->zpool_hdl, nvl,
     4580 +            version, flags, errbuf)) == NULL) {
     4581 +                nvlist_free(nvl);
     4582 +                return (-1);
     4583 +        }
     4584 +
     4585 +        nvlist_free(nvl);
     4586 +        nvl = realprops;
     4587 +
     4588 +        /*
     4589 +         * Execute the corresponding ioctl() to set this property.
     4590 +         */
     4591 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4592 +        zc.zc_guid = guid;
     4593 +
     4594 +        if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
     4595 +                nvlist_free(nvl);
     4596 +                return (-1);
     4597 +        }
     4598 +
     4599 +        ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_PROPS, &zc);
     4600 +
     4601 +        zcmd_free_nvlists(&zc);
     4602 +        nvlist_free(nvl);
     4603 +
     4604 +        if (ret)
     4605 +                (void) zpool_vprop_standard_error(zhp->zpool_hdl,
     4606 +                    errno, errbuf);
     4607 +
     4608 +        return (ret);
     4609 +}
     4610 +
     4611 +/*
     4612 + * Set vdev properties nvlist
     4613 + */
     4614 +int
     4615 +vdev_set_proplist(zpool_handle_t *zhp, const char *vdev, nvlist_t *nvl)
     4616 +{
     4617 +        zfs_cmd_t zc = { 0 };
     4618 +        int ret = -1;
     4619 +        char errbuf[1024];
     4620 +        nvlist_t *realprops;
     4621 +        uint64_t version;
     4622 +        uint64_t guid;
     4623 +        prop_flags_t flags = { 0 };
     4624 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4625 +
     4626 +        assert(nvl != NULL);
     4627 +
     4628 +        (void) snprintf(errbuf, sizeof (errbuf),
     4629 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
     4630 +            zhp->zpool_name);
     4631 +
     4632 +        if (vdev_get_guid(zhp, vdev, &guid) != 0) {
     4633 +                (void) zfs_error(hdl, EZFS_BADDEV, errbuf);
     4634 +                return (-1);
     4635 +        }
     4636 +
     4637 +        version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
     4638 +        if ((realprops = vdev_valid_proplist(zhp->zpool_hdl, nvl,
     4639 +            version, flags, errbuf)) == NULL) {
     4640 +                nvlist_free(nvl);
     4641 +                return (-1);
     4642 +        }
     4643 +
     4644 +        nvlist_free(nvl);
     4645 +        nvl = realprops;
     4646 +
     4647 +        /*
     4648 +         * Execute the corresponding ioctl() to set this property.
     4649 +         */
     4650 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4651 +        zc.zc_guid = guid;
     4652 +
     4653 +        if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) {
     4654 +                nvlist_free(nvl);
     4655 +                return (-1);
     4656 +        }
     4657 +
     4658 +        ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_PROPS, &zc);
     4659 +
     4660 +        zcmd_free_nvlists(&zc);
     4661 +        nvlist_free(nvl);
     4662 +
     4663 +        if (ret)
     4664 +                (void) zpool_vprop_standard_error(hdl, errno, errbuf);
     4665 +
     4666 +        return (ret);
     4667 +}
     4668 +
     4669 +typedef struct vdev_cb {
     4670 +        zpool_handle_t          *vcb_zhp;
     4671 +        char                    *vcb_name;
     4672 +        uint64_t                vcb_guid;
     4673 +        boolean_t               vcb_is_leaf;
     4674 +        boolean_t               vcb_success;
     4675 +        void                    *vcb_data;
     4676 +} vdev_cb_t;
     4677 +
     4678 +typedef int (*vdev_callback_t)(vdev_cb_t *);
     4679 +
     4680 +/*
     4681 + * Invoke dev_callback for all vdevs in the pool
     4682 + */
     4683 +int
     4684 +for_each_vdev(zpool_handle_t *zhp, nvlist_t *root,
     4685 +    vdev_callback_t vdev_callback, vdev_cb_t *cb)
     4686 +{
     4687 +        int ret = 0;
     4688 +        nvlist_t *config, *nvroot, **child, **child_list;
     4689 +        uint32_t children, child_children, c;
     4690 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4691 +
     4692 +        if (!root) {
     4693 +                config = zpool_get_config(zhp, NULL);
     4694 +                verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
     4695 +                    &nvroot) == 0);
     4696 +        } else {
     4697 +                nvroot = root;
     4698 +        }
     4699 +
     4700 +        if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
     4701 +            &child, &children) != 0) {
     4702 +                (void) fprintf(stderr, gettext("Failed to get the vdev "
     4703 +                    "children details from the root nvlist\n"));
     4704 +                return (-1);
     4705 +        }
     4706 +
     4707 +        cb->vcb_zhp = zhp;
     4708 +        for (c = 0; c < children; c++) {
     4709 +                cb->vcb_is_leaf = B_TRUE;
     4710 +                if (nvlist_lookup_nvlist_array(child[c], ZPOOL_CONFIG_CHILDREN,
     4711 +                    &child_list, &child_children) == 0 &&
     4712 +                    child_children > 0) {
     4713 +                        ret = for_each_vdev(zhp, child[c], vdev_callback, cb);
     4714 +                        if (ret)
     4715 +                                return (ret);
     4716 +                        cb->vcb_is_leaf = B_FALSE;
     4717 +                }
     4718 +
     4719 +                cb->vcb_name = zpool_vdev_name(hdl, NULL, child[c], B_TRUE);
     4720 +                verify(nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_GUID,
     4721 +                    &cb->vcb_guid) == 0);
     4722 +
     4723 +                ret |= vdev_callback(cb);
     4724 +                free(cb->vcb_name);
     4725 +                if (ret)
     4726 +                        return (ret);
     4727 +        }
     4728 +
     4729 +        return (0);
     4730 +}
     4731 +
     4732 +int
     4733 +get_vdev_guid_callback(vdev_cb_t *cb)
     4734 +{
     4735 +        if (!cb->vcb_is_leaf)
     4736 +                return (0);
     4737 +
     4738 +        if (strncmp(cb->vcb_name, (char *)cb->vcb_data,
     4739 +            strlen(cb->vcb_name)) == 0) {
     4740 +                cb->vcb_success = B_TRUE;
     4741 +        }
     4742 +
     4743 +        return (0);
     4744 +}
     4745 +
     4746 +/*
     4747 + * Class of Storage (COS)
     4748 + */
     4749 +/*ARGSUSED*/
     4750 +static nvlist_t *
     4751 +cos_valid_proplist(libzfs_handle_t *hdl, nvlist_t *props,
     4752 +    uint64_t version, prop_flags_t flags, const char *errbuf)
     4753 +{
     4754 +        nvpair_t *elem;
     4755 +        nvlist_t *retprops;
     4756 +        cos_prop_t prop;
     4757 +        char *strval;
     4758 +        uint64_t intval;
     4759 +
     4760 +        if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
     4761 +                (void) no_memory(hdl);
     4762 +                return (NULL);
     4763 +        }
     4764 +
     4765 +        elem = NULL;
     4766 +        while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
     4767 +                const char *propname = nvpair_name(elem);
     4768 +
     4769 +                /*
     4770 +                 * Make sure this property is valid and applies to this type.
     4771 +                 */
     4772 +                if ((prop = cos_name_to_prop(propname)) == ZPROP_INVAL) {
     4773 +                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4774 +                            "invalid cos property '%s'"), propname);
     4775 +                        (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
     4776 +                        goto error;
     4777 +                }
     4778 +
     4779 +                if (cos_prop_readonly(prop)) {
     4780 +                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
     4781 +                            "is readonly"), propname);
     4782 +                        (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
     4783 +                        goto error;
     4784 +                }
     4785 +
     4786 +                if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_COS, retprops,
     4787 +                    &strval, &intval, errbuf) != 0)
     4788 +                        goto error;
     4789 +
     4790 +                /*
     4791 +                 * Perform additional checking for specific properties.
     4792 +                 */
     4793 +                switch (prop) {
     4794 +                case COS_PROP_PREFERRED_READ:
     4795 +                        if (intval > 100) {
     4796 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4797 +                                    "'%s' must be from 0 to 100"), propname);
     4798 +                                (void) zfs_error(hdl, EZFS_BADPROP,
     4799 +                                    errbuf);
     4800 +                                goto error;
     4801 +                        }
     4802 +                        break;
     4803 +                case COS_PROP_READ_MINACTIVE:
     4804 +                case COS_PROP_AREAD_MINACTIVE:
     4805 +                case COS_PROP_WRITE_MINACTIVE:
     4806 +                case COS_PROP_AWRITE_MINACTIVE:
     4807 +                case COS_PROP_SCRUB_MINACTIVE:
     4808 +                case COS_PROP_READ_MAXACTIVE:
     4809 +                case COS_PROP_AREAD_MAXACTIVE:
     4810 +                case COS_PROP_WRITE_MAXACTIVE:
     4811 +                case COS_PROP_AWRITE_MAXACTIVE:
     4812 +                case COS_PROP_SCRUB_MAXACTIVE:
     4813 +                        if (intval > 1000) {
     4814 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
     4815 +                                    "'%s' must be from 0 to 1000"), propname);
     4816 +                                (void) zfs_error(hdl, EZFS_BADPROP,
     4817 +                                    errbuf);
     4818 +                                goto error;
     4819 +                        }
     4820 +                        break;
     4821 +                default:
     4822 +                        break;
     4823 +                }
     4824 +        }
     4825 +
     4826 +        return (retprops);
     4827 +error:
     4828 +        nvlist_free(retprops);
     4829 +        return (NULL);
     4830 +}
     4831 +
     4832 +int
     4833 +cos_alloc(zpool_handle_t *zhp, char *cosname, nvlist_t *nvl)
     4834 +{
     4835 +        zfs_cmd_t zc = { 0 };
     4836 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4837 +        char errbuf[1024];
     4838 +        int error = 0;
     4839 +
     4840 +        (void) snprintf(errbuf, sizeof (errbuf),
     4841 +            dgettext(TEXT_DOMAIN, "cannot allocate CoS descriptor for '%s'"),
     4842 +            zhp->zpool_name);
     4843 +
     4844 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4845 +        (void) strlcpy(zc.zc_string, cosname, sizeof (zc.zc_string));
     4846 +
     4847 +        if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
     4848 +                nvlist_free(nvl);
     4849 +                return (-1);
     4850 +        }
     4851 +
     4852 +        error = ioctl(hdl->libzfs_fd, ZFS_IOC_COS_ALLOC, &zc);
     4853 +
     4854 +        if (error)
     4855 +                (void) zpool_vprop_standard_error(hdl, errno, errbuf);
     4856 +
     4857 +        return (error);
     4858 +}
     4859 +
     4860 +int
     4861 +cos_free(zpool_handle_t *zhp, char *cosname, uint64_t guid, boolean_t force)
     4862 +{
     4863 +        zfs_cmd_t zc = { 0 };
     4864 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4865 +        char errbuf[1024];
     4866 +        int error = 0;
     4867 +
     4868 +        (void) snprintf(errbuf, sizeof (errbuf),
     4869 +            dgettext(TEXT_DOMAIN, "cannot free CoS descriptor for '%s'"),
     4870 +            zhp->zpool_name);
     4871 +
     4872 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4873 +        (void) strlcpy(zc.zc_string, cosname, sizeof (zc.zc_string));
     4874 +        zc.zc_guid = guid;
     4875 +
     4876 +        zc.zc_cookie = (uint64_t)force;
     4877 +
     4878 +        error = ioctl(hdl->libzfs_fd, ZFS_IOC_COS_FREE, &zc);
     4879 +
     4880 +        if (error)
     4881 +                (void) zpool_vprop_standard_error(hdl, errno, errbuf);
     4882 +
     4883 +        return (error);
     4884 +}
     4885 +
     4886 +int
     4887 +cos_list(zpool_handle_t *zhp, nvlist_t **nvp)
     4888 +{
     4889 +        zfs_cmd_t zc = { 0 };
     4890 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4891 +
     4892 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4893 +
     4894 +        if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
     4895 +                return (-1);
     4896 +
     4897 +        while (ioctl(hdl->libzfs_fd, ZFS_IOC_COS_LIST, &zc) != 0) {
     4898 +                if (errno == ENOMEM) {
     4899 +                        if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
     4900 +                                zcmd_free_nvlists(&zc);
     4901 +                                return (-1);
     4902 +                        }
     4903 +                } else {
     4904 +                        zcmd_free_nvlists(&zc);
     4905 +                        return (-1);
     4906 +                }
     4907 +        }
     4908 +
     4909 +        if (zcmd_read_dst_nvlist(hdl, &zc, nvp) != 0) {
     4910 +                zcmd_free_nvlists(&zc);
     4911 +                return (-1);
     4912 +        }
     4913 +
     4914 +        zcmd_free_nvlists(&zc);
     4915 +
     4916 +        return (0);
     4917 +}
     4918 +
     4919 +int
     4920 +cos_get_all_props(zpool_handle_t *zhp, const char *cos, nvlist_t **nvp)
     4921 +{
     4922 +        uint64_t cos_id;
     4923 +        zfs_cmd_t zc = { 0 };
     4924 +        libzfs_handle_t *hdl = zhp->zpool_hdl;
     4925 +        char *endp;
     4926 +        char errbuf[1024];
     4927 +
     4928 +        (void) snprintf(errbuf, sizeof (errbuf),
     4929 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
     4930 +            zhp->zpool_name);
     4931 +
     4932 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     4933 +
     4934 +        if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
     4935 +                return (-1);
     4936 +
     4937 +        cos_id = strtoll(cos, &endp, 10);
     4938 +        zc.zc_guid = cos_id;
     4939 +        if (cos_id == 0 && cos == endp)
     4940 +                (void) strlcpy(zc.zc_string, cos, sizeof (zc.zc_string));
     4941 +        else
     4942 +                zc.zc_string[0] = '\0';
     4943 +
     4944 +        while (ioctl(hdl->libzfs_fd, ZFS_IOC_COS_GET_PROPS, &zc) != 0) {
     4945 +                if (errno == ENOMEM) {
     4946 +                        if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
     4947 +                                zcmd_free_nvlists(&zc);
     4948 +                                return (-1);
     4949 +                        }
     4950 +                } else {
     4951 +                        zcmd_free_nvlists(&zc);
     4952 +                        (void) zpool_standard_error(hdl, errno, errbuf);
     4953 +                        return (-1);
     4954 +                }
     4955 +        }
     4956 +
     4957 +        if (zcmd_read_dst_nvlist(hdl, &zc, nvp) != 0) {
     4958 +                zcmd_free_nvlists(&zc);
     4959 +                return (-1);
     4960 +        }
     4961 +
     4962 +        zcmd_free_nvlists(&zc);
     4963 +
     4964 +        return (0);
     4965 +}
     4966 +
     4967 +int
     4968 +cos_get_prop(zpool_handle_t *zhp,  const char *cos, cos_prop_t prop,
     4969 +    char *buf, size_t len, nvlist_t **nvp)
     4970 +{
     4971 +        uint64_t intval;
     4972 +        const char *strval;
     4973 +        nvlist_t *nvl;
     4974 +        char errbuf[1024];
     4975 +
     4976 +        (void) snprintf(errbuf, sizeof (errbuf),
     4977 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
     4978 +            zhp->zpool_name);
     4979 +
     4980 +        assert(nvp != NULL);
     4981 +
     4982 +        if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL)
     4983 +                return (-1);
     4984 +
     4985 +        if (*nvp == NULL && cos_get_all_props(zhp, cos, nvp) != 0)
     4986 +                return (-1);
     4987 +        nvl = *nvp;
     4988 +
     4989 +        switch (cos_prop_get_type(prop)) {
     4990 +        case PROP_TYPE_STRING:
     4991 +                if (nvlist_lookup_string(nvl, cos_prop_to_name(prop),
     4992 +                    (char **)&strval) != 0)
     4993 +                        if ((strval = (char *)cos_prop_default_string(prop))
     4994 +                            == NULL)
     4995 +                                strval = "-";
     4996 +
     4997 +                (void) strlcpy(buf, strval, len);
     4998 +                break;
     4999 +
     5000 +        case PROP_TYPE_NUMBER:
     5001 +                if (nvlist_lookup_uint64(nvl, cos_prop_to_name(prop),
     5002 +                    &intval) != 0)
     5003 +                        intval = cos_prop_default_numeric(prop);
     5004 +                (void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
     5005 +                break;
     5006 +
     5007 +        case PROP_TYPE_INDEX:
     5008 +                if (nvlist_lookup_uint64(nvl, cos_prop_to_name(prop),
     5009 +                    &intval) != 0)
     5010 +                        intval = cos_prop_default_numeric(prop);
     5011 +                if (cos_prop_index_to_string(prop, intval, &strval) != 0) {
     5012 +                        (void) zfs_error(zhp->zpool_hdl, EZFS_BADPROP, errbuf);
     5013 +                        return (-1);
     5014 +                }
     5015 +                (void) strlcpy(buf, strval, len);
     5016 +                break;
     5017 +
     5018 +        default:
     5019 +                abort();
     5020 +        }
     5021 +
     5022 +        return (0);
     5023 +}
     5024 +
     5025 +/*
     5026 + * Set cos properties nvlist
     5027 + */
     5028 +int
     5029 +cos_set_proplist(zpool_handle_t *zhp, const char *cos, nvlist_t *nvl)
     5030 +{
     5031 +        zfs_cmd_t zc = { 0 };
     5032 +        int ret = -1;
     5033 +        char errbuf[1024];
     5034 +        char *endp;
     5035 +        nvlist_t *realprops;
     5036 +        uint64_t version;
     5037 +        uint64_t cos_id;
     5038 +        prop_flags_t flags = { 0 };
     5039 +
     5040 +        assert(nvl != NULL);
     5041 +
     5042 +        (void) snprintf(errbuf, sizeof (errbuf),
     5043 +            dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
     5044 +            zhp->zpool_name);
     5045 +
     5046 +        version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
     5047 +        if ((realprops = cos_valid_proplist(zhp->zpool_hdl, nvl,
     5048 +            version, flags, errbuf)) == NULL) {
     5049 +                nvlist_free(nvl);
     5050 +                return (-1);
     5051 +        }
     5052 +
     5053 +        nvlist_free(nvl);
     5054 +        nvl = realprops;
     5055 +
     5056 +        /*
     5057 +         * Execute the corresponding ioctl() to set this property.
     5058 +         */
     5059 +        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
     5060 +
     5061 +        cos_id = strtoll(cos, &endp, 10);
     5062 +        zc.zc_guid = cos_id;
     5063 +        if (cos_id == 0 && cos == endp)
     5064 +                (void) strlcpy(zc.zc_string, cos, sizeof (zc.zc_string));
     5065 +        else
     5066 +                zc.zc_string[0] = '\0';
     5067 +
     5068 +        if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
     5069 +                nvlist_free(nvl);
     5070 +                return (-1);
     5071 +        }
     5072 +
     5073 +        ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_COS_SET_PROPS, &zc);
     5074 +
     5075 +        zcmd_free_nvlists(&zc);
     5076 +        nvlist_free(nvl);
     5077 +
     5078 +        if (ret)
     5079 +                (void) zpool_vprop_standard_error_fmt(zhp->zpool_hdl,
     5080 +                    errno, errbuf);
     5081 +
     5082 +        return (ret);
     5083 +}
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX