Print this page
2619 asynchronous destruction of ZFS file systems
2747 SPA versioning with zfs feature flags
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <gwilson@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
Approved by: Dan McDonald <danmcd@nexenta.com>

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 ↓ 35 lines elided ↑ open up ↑
  36   36  #include <unistd.h>
  37   37  #include <sys/efi_partition.h>
  38   38  #include <sys/vtoc.h>
  39   39  #include <sys/zfs_ioctl.h>
  40   40  #include <dlfcn.h>
  41   41  
  42   42  #include "zfs_namecheck.h"
  43   43  #include "zfs_prop.h"
  44   44  #include "libzfs_impl.h"
  45   45  #include "zfs_comutil.h"
       46 +#include "zfeature_common.h"
  46   47  
  47   48  static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
  48   49  
  49   50  #define DISK_ROOT       "/dev/dsk"
  50   51  #define RDISK_ROOT      "/dev/rdsk"
  51   52  #define BACKUP_SLICE    "s2"
  52   53  
  53   54  typedef struct prop_flags {
  54   55          int create:1;   /* Validate property on creation */
  55   56          int import:1;   /* Validate property on import */
↓ open down ↓ 210 lines elided ↑ open up ↑
 266  267                      len);
 267  268                  break;
 268  269  
 269  270          case PROP_TYPE_NUMBER:
 270  271                  intval = zpool_get_prop_int(zhp, prop, &src);
 271  272  
 272  273                  switch (prop) {
 273  274                  case ZPOOL_PROP_SIZE:
 274  275                  case ZPOOL_PROP_ALLOCATED:
 275  276                  case ZPOOL_PROP_FREE:
      277 +                case ZPOOL_PROP_FREEING:
 276  278                  case ZPOOL_PROP_EXPANDSZ:
 277  279                          (void) zfs_nicenum(intval, buf, len);
 278  280                          break;
 279  281  
 280  282                  case ZPOOL_PROP_CAPACITY:
 281  283                          (void) snprintf(buf, len, "%llu%%",
 282  284                              (u_longlong_t)intval);
 283  285                          break;
 284  286  
 285  287                  case ZPOOL_PROP_DEDUPRATIO:
↓ open down ↓ 5 lines elided ↑ open up ↑
 291  293                  case ZPOOL_PROP_HEALTH:
 292  294                          verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
 293  295                              ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
 294  296                          verify(nvlist_lookup_uint64_array(nvroot,
 295  297                              ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
 296  298                              == 0);
 297  299  
 298  300                          (void) strlcpy(buf, zpool_state_to_name(intval,
 299  301                              vs->vs_aux), len);
 300  302                          break;
      303 +                case ZPOOL_PROP_VERSION:
      304 +                        if (intval >= SPA_VERSION_FEATURES) {
      305 +                                (void) snprintf(buf, len, "-");
      306 +                                break;
      307 +                        }
      308 +                        /* FALLTHROUGH */
 301  309                  default:
 302  310                          (void) snprintf(buf, len, "%llu", intval);
 303  311                  }
 304  312                  break;
 305  313  
 306  314          case PROP_TYPE_INDEX:
 307  315                  intval = zpool_get_prop_int(zhp, prop, &src);
 308  316                  if (zpool_prop_index_to_string(prop, intval, &strval)
 309  317                      != 0)
 310  318                          return (-1);
↓ open down ↓ 82 lines elided ↑ open up ↑
 393  401  
 394  402          if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
 395  403                  (void) no_memory(hdl);
 396  404                  return (NULL);
 397  405          }
 398  406  
 399  407          elem = NULL;
 400  408          while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
 401  409                  const char *propname = nvpair_name(elem);
 402  410  
      411 +                prop = zpool_name_to_prop(propname);
      412 +                if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
      413 +                        int err;
      414 +                        zfeature_info_t *feature;
      415 +                        char *fname = strchr(propname, '@') + 1;
      416 +
      417 +                        err = zfeature_lookup_name(fname, &feature);
      418 +                        if (err != 0) {
      419 +                                ASSERT3U(err, ==, ENOENT);
      420 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
      421 +                                    "invalid feature '%s'"), fname);
      422 +                                (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
      423 +                                goto error;
      424 +                        }
      425 +
      426 +                        if (nvpair_type(elem) != DATA_TYPE_STRING) {
      427 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
      428 +                                    "'%s' must be a string"), propname);
      429 +                                (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
      430 +                                goto error;
      431 +                        }
      432 +
      433 +                        (void) nvpair_value_string(elem, &strval);
      434 +                        if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
      435 +                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
      436 +                                    "property '%s' can only be set to "
      437 +                                    "'enabled'"), propname);
      438 +                                (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
      439 +                                goto error;
      440 +                        }
      441 +
      442 +                        if (nvlist_add_uint64(retprops, propname, 0) != 0) {
      443 +                                (void) no_memory(hdl);
      444 +                                goto error;
      445 +                        }
      446 +                        continue;
      447 +                }
      448 +
 403  449                  /*
 404  450                   * Make sure this property is valid and applies to this type.
 405  451                   */
 406      -                if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
      452 +                if (prop == ZPROP_INVAL) {
 407  453                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 408  454                              "invalid property '%s'"), propname);
 409  455                          (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 410  456                          goto error;
 411  457                  }
 412  458  
 413  459                  if (zpool_prop_readonly(prop)) {
 414  460                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
 415  461                              "is readonly"), propname);
 416  462                          (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
↓ open down ↓ 2 lines elided ↑ open up ↑
 419  465  
 420  466                  if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
 421  467                      &strval, &intval, errbuf) != 0)
 422  468                          goto error;
 423  469  
 424  470                  /*
 425  471                   * Perform additional checking for specific properties.
 426  472                   */
 427  473                  switch (prop) {
 428  474                  case ZPOOL_PROP_VERSION:
 429      -                        if (intval < version || intval > SPA_VERSION) {
      475 +                        if (intval < version ||
      476 +                            !SPA_VERSION_IS_SUPPORTED(intval)) {
 430  477                                  zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 431  478                                      "property '%s' number %d is invalid."),
 432  479                                      propname, intval);
 433  480                                  (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
 434  481                                  goto error;
 435  482                          }
 436  483                          break;
 437  484  
 438  485                  case ZPOOL_PROP_BOOTFS:
 439  486                          if (flags.create || flags.import) {
↓ open down ↓ 201 lines elided ↑ open up ↑
 641  688  
 642  689          return (ret);
 643  690  }
 644  691  
 645  692  int
 646  693  zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
 647  694  {
 648  695          libzfs_handle_t *hdl = zhp->zpool_hdl;
 649  696          zprop_list_t *entry;
 650  697          char buf[ZFS_MAXPROPLEN];
      698 +        nvlist_t *features = NULL;
      699 +        zprop_list_t **last;
      700 +        boolean_t firstexpand = (NULL == *plp);
 651  701  
 652  702          if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
 653  703                  return (-1);
 654  704  
      705 +        last = plp;
      706 +        while (*last != NULL)
      707 +                last = &(*last)->pl_next;
      708 +
      709 +        if ((*plp)->pl_all)
      710 +                features = zpool_get_features(zhp);
      711 +
      712 +        if ((*plp)->pl_all && firstexpand) {
      713 +                for (int i = 0; i < SPA_FEATURES; i++) {
      714 +                        zprop_list_t *entry = zfs_alloc(hdl,
      715 +                            sizeof (zprop_list_t));
      716 +                        entry->pl_prop = ZPROP_INVAL;
      717 +                        entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
      718 +                            spa_feature_table[i].fi_uname);
      719 +                        entry->pl_width = strlen(entry->pl_user_prop);
      720 +                        entry->pl_all = B_TRUE;
      721 +
      722 +                        *last = entry;
      723 +                        last = &entry->pl_next;
      724 +                }
      725 +        }
      726 +
      727 +        /* add any unsupported features */
      728 +        for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL);
      729 +            nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
      730 +                char *propname;
      731 +                boolean_t found;
      732 +                zprop_list_t *entry;
      733 +
      734 +                if (zfeature_is_supported(nvpair_name(nvp)))
      735 +                        continue;
      736 +
      737 +                propname = zfs_asprintf(hdl, "unsupported@%s",
      738 +                    nvpair_name(nvp));
      739 +
      740 +                /*
      741 +                 * Before adding the property to the list make sure that no
      742 +                 * other pool already added the same property.
      743 +                 */
      744 +                found = B_FALSE;
      745 +                entry = *plp;
      746 +                while (entry != NULL) {
      747 +                        if (entry->pl_user_prop != NULL &&
      748 +                            strcmp(propname, entry->pl_user_prop) == 0) {
      749 +                                found = B_TRUE;
      750 +                                break;
      751 +                        }
      752 +                        entry = entry->pl_next;
      753 +                }
      754 +                if (found) {
      755 +                        free(propname);
      756 +                        continue;
      757 +                }
      758 +
      759 +                entry = zfs_alloc(hdl, sizeof (zprop_list_t));
      760 +                entry->pl_prop = ZPROP_INVAL;
      761 +                entry->pl_user_prop = propname;
      762 +                entry->pl_width = strlen(entry->pl_user_prop);
      763 +                entry->pl_all = B_TRUE;
      764 +
      765 +                *last = entry;
      766 +                last = &entry->pl_next;
      767 +        }
      768 +
 655  769          for (entry = *plp; entry != NULL; entry = entry->pl_next) {
 656  770  
 657  771                  if (entry->pl_fixed)
 658  772                          continue;
 659  773  
 660  774                  if (entry->pl_prop != ZPROP_INVAL &&
 661  775                      zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
 662  776                      NULL) == 0) {
 663  777                          if (strlen(buf) > entry->pl_width)
 664  778                                  entry->pl_width = strlen(buf);
 665  779                  }
 666  780          }
 667  781  
 668  782          return (0);
 669  783  }
 670  784  
      785 +/*
      786 + * Get the state for the given feature on the given ZFS pool.
      787 + */
      788 +int
      789 +zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
      790 +    size_t len)
      791 +{
      792 +        uint64_t refcount;
      793 +        boolean_t found = B_FALSE;
      794 +        nvlist_t *features = zpool_get_features(zhp);
      795 +        boolean_t supported;
      796 +        const char *feature = strchr(propname, '@') + 1;
 671  797  
      798 +        supported = zpool_prop_feature(propname);
      799 +        ASSERT(supported || zfs_prop_unsupported(propname));
      800 +
      801 +        /*
      802 +         * Convert from feature name to feature guid. This conversion is
      803 +         * unecessary for unsupported@... properties because they already
      804 +         * use guids.
      805 +         */
      806 +        if (supported) {
      807 +                int ret;
      808 +                zfeature_info_t *fi;
      809 +
      810 +                ret = zfeature_lookup_name(feature, &fi);
      811 +                if (ret != 0) {
      812 +                        (void) strlcpy(buf, "-", len);
      813 +                        return (ENOTSUP);
      814 +                }
      815 +                feature = fi->fi_guid;
      816 +        }
      817 +
      818 +        if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
      819 +                found = B_TRUE;
      820 +
      821 +        if (supported) {
      822 +                if (!found) {
      823 +                        (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
      824 +                } else  {
      825 +                        if (refcount == 0)
      826 +                                (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
      827 +                        else
      828 +                                (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
      829 +                }
      830 +        } else {
      831 +                if (found) {
      832 +                        if (refcount == 0) {
      833 +                                (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
      834 +                        } else {
      835 +                                (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
      836 +                        }
      837 +                } else {
      838 +                        (void) strlcpy(buf, "-", len);
      839 +                        return (ENOTSUP);
      840 +                }
      841 +        }
      842 +
      843 +        return (0);
      844 +}
      845 +
 672  846  /*
 673  847   * Don't start the slice at the default block of 34; many storage
 674  848   * devices will use a stripe width of 128k, so start there instead.
 675  849   */
 676  850  #define NEW_START_BLOCK 256
 677  851  
 678  852  /*
 679  853   * Validate the given pool name, optionally putting an extended error message in
 680  854   * 'buf'.
 681  855   */
↓ open down ↓ 565 lines elided ↑ open up ↑
1247 1421  {
1248 1422          nvlist_t *nv = NULL;
1249 1423          uint64_t rewindto;
1250 1424          int64_t loss = -1;
1251 1425          struct tm t;
1252 1426          char timestr[128];
1253 1427  
1254 1428          if (!hdl->libzfs_printerr || config == NULL)
1255 1429                  return;
1256 1430  
1257      -        if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0)
     1431 +        if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
     1432 +            nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
1258 1433                  return;
     1434 +        }
1259 1435  
1260 1436          if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1261 1437                  return;
1262 1438          (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
1263 1439  
1264 1440          if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1265 1441              strftime(timestr, 128, 0, &t) != 0) {
1266 1442                  if (dryrun) {
1267 1443                          (void) printf(dgettext(TEXT_DOMAIN,
1268 1444                              "Would be able to return %s "
↓ open down ↓ 35 lines elided ↑ open up ↑
1304 1480          if (!hdl->libzfs_printerr)
1305 1481                  return;
1306 1482  
1307 1483          if (reason >= 0)
1308 1484                  (void) printf(dgettext(TEXT_DOMAIN, "action: "));
1309 1485          else
1310 1486                  (void) printf(dgettext(TEXT_DOMAIN, "\t"));
1311 1487  
1312 1488          /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
1313 1489          if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
     1490 +            nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
1314 1491              nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1315 1492                  goto no_info;
1316 1493  
1317 1494          (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
1318 1495          (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
1319 1496              &edata);
1320 1497  
1321 1498          (void) printf(dgettext(TEXT_DOMAIN,
1322 1499              "Recovery is possible, but will result in some data loss.\n"));
1323 1500  
↓ open down ↓ 102 lines elided ↑ open up ↑
1426 1603              &child, &children) != 0)
1427 1604                  return;
1428 1605  
1429 1606          for (c = 0; c < children; c++) {
1430 1607                  vname = zpool_vdev_name(hdl, NULL, child[c], B_TRUE);
1431 1608                  print_vdev_tree(hdl, vname, child[c], indent + 2);
1432 1609                  free(vname);
1433 1610          }
1434 1611  }
1435 1612  
     1613 +void
     1614 +zpool_print_unsup_feat(nvlist_t *config)
     1615 +{
     1616 +        nvlist_t *nvinfo, *unsup_feat;
     1617 +
     1618 +        verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
     1619 +            0);
     1620 +        verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
     1621 +            &unsup_feat) == 0);
     1622 +
     1623 +        for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
     1624 +            nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
     1625 +                char *desc;
     1626 +
     1627 +                verify(nvpair_type(nvp) == DATA_TYPE_STRING);
     1628 +                verify(nvpair_value_string(nvp, &desc) == 0);
     1629 +
     1630 +                if (strlen(desc) > 0)
     1631 +                        (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
     1632 +                else
     1633 +                        (void) printf("\t%s\n", nvpair_name(nvp));
     1634 +        }
     1635 +}
     1636 +
1436 1637  /*
1437 1638   * Import the given pool using the known configuration and a list of
1438 1639   * properties to be set. The configuration should have come from
1439 1640   * zpool_find_import(). The 'newname' parameters control whether the pool
1440 1641   * is imported with a different name.
1441 1642   */
1442 1643  int
1443 1644  zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1444 1645      nvlist_t *props, int flags)
1445 1646  {
↓ open down ↓ 86 lines elided ↑ open up ↑
1532 1733                          (void) snprintf(desc, sizeof (desc),
1533 1734                              dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1534 1735                              thename);
1535 1736                  else
1536 1737                          (void) snprintf(desc, sizeof (desc),
1537 1738                              dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
1538 1739                              origname, thename);
1539 1740  
1540 1741                  switch (error) {
1541 1742                  case ENOTSUP:
     1743 +                        if (nv != NULL && nvlist_lookup_nvlist(nv,
     1744 +                            ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
     1745 +                            nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
     1746 +                                (void) printf(dgettext(TEXT_DOMAIN, "This "
     1747 +                                    "pool uses the following feature(s) not "
     1748 +                                    "supported by this system:\n"));
     1749 +                                zpool_print_unsup_feat(nv);
     1750 +                                if (nvlist_exists(nvinfo,
     1751 +                                    ZPOOL_CONFIG_CAN_RDONLY)) {
     1752 +                                        (void) printf(dgettext(TEXT_DOMAIN,
     1753 +                                            "All unsupported features are only "
     1754 +                                            "required for writing to the pool."
     1755 +                                            "\nThe pool can be imported using "
     1756 +                                            "'-o readonly=on'.\n"));
     1757 +                                }
     1758 +                        }
1542 1759                          /*
1543 1760                           * Unsupported version.
1544 1761                           */
1545 1762                          (void) zfs_error(hdl, EZFS_BADVERSION, desc);
1546 1763                          break;
1547 1764  
1548 1765                  case EINVAL:
1549 1766                          (void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
1550 1767                          break;
1551 1768  
↓ open down ↓ 2316 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX