diff options
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_pool.c')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 110 |
1 files changed, 91 insertions, 19 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index db03bd6c03..78c21fc49d 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2015 by Delphix. All rights reserved. + * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> @@ -1332,6 +1332,13 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) (void) zfs_error(hdl, EZFS_BADDEV, msg); break; + case EINVAL: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "invalid config; a pool with removing/removed " + "vdevs does not support adding raidz vdevs")); + (void) zfs_error(hdl, EZFS_BADDEV, msg); + break; + case EOVERFLOW: /* * This occurrs when one of the devices is below @@ -2655,7 +2662,7 @@ zpool_vdev_attach(zpool_handle_t *zhp, (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, - &islog)) == 0) + &islog)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); if (avail_spare) @@ -2754,7 +2761,8 @@ zpool_vdev_attach(zpool_handle_t *zhp, break; case EBUSY: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy, " + "or pool has removing/removed vdevs"), new_disk); (void) zfs_error(hdl, EZFS_BADDEV, msg); break; @@ -2808,7 +2816,7 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path) (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, - NULL)) == 0) + NULL)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); if (avail_spare) @@ -3097,8 +3105,7 @@ out: } /* - * Remove the given device. Currently, this is supported only for hot spares - * and level 2 cache devices. + * Remove the given device. */ int zpool_vdev_remove(zpool_handle_t *zhp, const char *path) @@ -3115,26 +3122,61 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path) (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, - &islog)) == 0) - return (zfs_error(hdl, EZFS_NODEVICE, msg)); - /* - * XXX - this should just go away. - */ - if (!avail_spare && !l2cache && !islog) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "only inactive hot spares, cache, top-level, " - "or log devices can be removed")); + &islog)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); - } version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); if (islog && version < SPA_VERSION_HOLES) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "pool must be upgrade to support log removal")); + "pool must be upgraded to support log removal")); return (zfs_error(hdl, EZFS_BADVERSION, msg)); } - verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); + if (!islog && !avail_spare && !l2cache && zpool_is_bootable(zhp)) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "root pool can not have removed devices, " + "because GRUB does not understand them")); + return (zfs_error(hdl, EINVAL, msg)); + } + + zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID); + + if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) + return (0); + + switch (errno) { + + case EINVAL: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "invalid config; all top-level vdevs must " + "have the same sector size and not be raidz.")); + (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); + break; + + case EBUSY: + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "Pool busy; removal may already be in progress")); + (void) zfs_error(hdl, EZFS_BUSY, msg); + break; + + default: + (void) zpool_standard_error(hdl, errno, msg); + } + return (-1); +} + +int +zpool_vdev_remove_cancel(zpool_handle_t *zhp) +{ + zfs_cmd_t zc = { 0 }; + char msg[1024]; + libzfs_handle_t *hdl = zhp->zpool_hdl; + + (void) snprintf(msg, sizeof (msg), + dgettext(TEXT_DOMAIN, "cannot cancel removal")); + + (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); + zc.zc_cookie = 1; if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) return (0); @@ -3142,6 +3184,36 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path) return (zpool_standard_error(hdl, errno, msg)); } +int +zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path, + uint64_t *sizep) +{ + char msg[1024]; + nvlist_t *tgt; + boolean_t avail_spare, l2cache, islog; + libzfs_handle_t *hdl = zhp->zpool_hdl; + + (void) snprintf(msg, sizeof (msg), + dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"), + path); + + if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, + &islog)) == NULL) + return (zfs_error(hdl, EZFS_NODEVICE, msg)); + + if (avail_spare || l2cache || islog) { + *sizep = 0; + return (0); + } + + if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "indirect size not available")); + return (zfs_error(hdl, EINVAL, msg)); + } + return (0); +} + /* * Clear the errors for the pool, or the particular device if specified. */ @@ -3169,7 +3241,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if (path) { if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, - &l2cache, NULL)) == 0) + &l2cache, NULL)) == NULL) return (zfs_error(hdl, EZFS_NODEVICE, msg)); /* |