41 |
41 |
42 #include "zfs_namecheck.h" |
42 #include "zfs_namecheck.h" |
43 #include "zfs_prop.h" |
43 #include "zfs_prop.h" |
44 #include "libzfs_impl.h" |
44 #include "libzfs_impl.h" |
45 #include "zfs_comutil.h" |
45 #include "zfs_comutil.h" |
|
46 #include "zfeature_common.h" |
46 |
47 |
47 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); |
48 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); |
48 |
49 |
49 #define DISK_ROOT "/dev/dsk" |
50 #define DISK_ROOT "/dev/dsk" |
50 #define RDISK_ROOT "/dev/rdsk" |
51 #define RDISK_ROOT "/dev/rdsk" |
271 |
272 |
272 switch (prop) { |
273 switch (prop) { |
273 case ZPOOL_PROP_SIZE: |
274 case ZPOOL_PROP_SIZE: |
274 case ZPOOL_PROP_ALLOCATED: |
275 case ZPOOL_PROP_ALLOCATED: |
275 case ZPOOL_PROP_FREE: |
276 case ZPOOL_PROP_FREE: |
|
277 case ZPOOL_PROP_FREEING: |
276 case ZPOOL_PROP_EXPANDSZ: |
278 case ZPOOL_PROP_EXPANDSZ: |
277 (void) zfs_nicenum(intval, buf, len); |
279 (void) zfs_nicenum(intval, buf, len); |
278 break; |
280 break; |
279 |
281 |
280 case ZPOOL_PROP_CAPACITY: |
282 case ZPOOL_PROP_CAPACITY: |
296 == 0); |
298 == 0); |
297 |
299 |
298 (void) strlcpy(buf, zpool_state_to_name(intval, |
300 (void) strlcpy(buf, zpool_state_to_name(intval, |
299 vs->vs_aux), len); |
301 vs->vs_aux), len); |
300 break; |
302 break; |
|
303 case ZPOOL_PROP_VERSION: |
|
304 if (intval >= SPA_VERSION_FEATURES) { |
|
305 (void) snprintf(buf, len, "-"); |
|
306 break; |
|
307 } |
|
308 /* FALLTHROUGH */ |
301 default: |
309 default: |
302 (void) snprintf(buf, len, "%llu", intval); |
310 (void) snprintf(buf, len, "%llu", intval); |
303 } |
311 } |
304 break; |
312 break; |
305 |
313 |
398 |
406 |
399 elem = NULL; |
407 elem = NULL; |
400 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { |
408 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { |
401 const char *propname = nvpair_name(elem); |
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 * Make sure this property is valid and applies to this type. |
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 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
453 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
408 "invalid property '%s'"), propname); |
454 "invalid property '%s'"), propname); |
409 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); |
455 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); |
410 goto error; |
456 goto error; |
411 } |
457 } |
424 /* |
470 /* |
425 * Perform additional checking for specific properties. |
471 * Perform additional checking for specific properties. |
426 */ |
472 */ |
427 switch (prop) { |
473 switch (prop) { |
428 case ZPOOL_PROP_VERSION: |
474 case ZPOOL_PROP_VERSION: |
429 if (intval < version || intval > SPA_VERSION) { |
475 if (intval < version || |
|
476 !SPA_VERSION_IS_SUPPORTED(intval)) { |
430 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
477 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
431 "property '%s' number %d is invalid."), |
478 "property '%s' number %d is invalid."), |
432 propname, intval); |
479 propname, intval); |
433 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); |
480 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); |
434 goto error; |
481 goto error; |
646 zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) |
693 zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) |
647 { |
694 { |
648 libzfs_handle_t *hdl = zhp->zpool_hdl; |
695 libzfs_handle_t *hdl = zhp->zpool_hdl; |
649 zprop_list_t *entry; |
696 zprop_list_t *entry; |
650 char buf[ZFS_MAXPROPLEN]; |
697 char buf[ZFS_MAXPROPLEN]; |
|
698 nvlist_t *features = NULL; |
|
699 zprop_list_t **last; |
|
700 boolean_t firstexpand = (NULL == *plp); |
651 |
701 |
652 if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) |
702 if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) |
653 return (-1); |
703 return (-1); |
|
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 } |
654 |
768 |
655 for (entry = *plp; entry != NULL; entry = entry->pl_next) { |
769 for (entry = *plp; entry != NULL; entry = entry->pl_next) { |
656 |
770 |
657 if (entry->pl_fixed) |
771 if (entry->pl_fixed) |
658 continue; |
772 continue; |
666 } |
780 } |
667 |
781 |
668 return (0); |
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; |
|
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 } |
671 |
845 |
672 /* |
846 /* |
673 * Don't start the slice at the default block of 34; many storage |
847 * Don't start the slice at the default block of 34; many storage |
674 * devices will use a stripe width of 128k, so start there instead. |
848 * devices will use a stripe width of 128k, so start there instead. |
675 */ |
849 */ |
1252 char timestr[128]; |
1426 char timestr[128]; |
1253 |
1427 |
1254 if (!hdl->libzfs_printerr || config == NULL) |
1428 if (!hdl->libzfs_printerr || config == NULL) |
1255 return; |
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 return; |
1433 return; |
|
1434 } |
1259 |
1435 |
1260 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) |
1436 if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) |
1261 return; |
1437 return; |
1262 (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); |
1438 (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); |
1263 |
1439 |
1309 else |
1485 else |
1310 (void) printf(dgettext(TEXT_DOMAIN, "\t")); |
1486 (void) printf(dgettext(TEXT_DOMAIN, "\t")); |
1311 |
1487 |
1312 /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ |
1488 /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ |
1313 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || |
1489 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || |
|
1490 nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 || |
1314 nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) |
1491 nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) |
1315 goto no_info; |
1492 goto no_info; |
1316 |
1493 |
1317 (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); |
1494 (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); |
1318 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS, |
1495 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS, |
1431 print_vdev_tree(hdl, vname, child[c], indent + 2); |
1608 print_vdev_tree(hdl, vname, child[c], indent + 2); |
1432 free(vname); |
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 * Import the given pool using the known configuration and a list of |
1638 * Import the given pool using the known configuration and a list of |
1438 * properties to be set. The configuration should have come from |
1639 * properties to be set. The configuration should have come from |
1439 * zpool_find_import(). The 'newname' parameters control whether the pool |
1640 * zpool_find_import(). The 'newname' parameters control whether the pool |
1440 * is imported with a different name. |
1641 * is imported with a different name. |
1537 dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), |
1738 dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), |
1538 origname, thename); |
1739 origname, thename); |
1539 |
1740 |
1540 switch (error) { |
1741 switch (error) { |
1541 case ENOTSUP: |
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 * Unsupported version. |
1760 * Unsupported version. |
1544 */ |
1761 */ |
1545 (void) zfs_error(hdl, EZFS_BADVERSION, desc); |
1762 (void) zfs_error(hdl, EZFS_BADVERSION, desc); |
1546 break; |
1763 break; |