示例#1
0
/*
 * Clear the errors for the pool, or the particular device if specified.
 */
int
zpool_clear(zpool_handle_t *zhp, const char *path)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	nvlist_t *tgt;
	boolean_t avail_spare;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	if (path)
		(void) snprintf(msg, sizeof (msg),
		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
		    zc.zc_prop_value);
	else
		(void) snprintf(msg, sizeof (msg),
		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
		    zhp->zpool_name);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if (path) {
		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
			return (zfs_error(hdl, EZFS_NODEVICE, msg));

		if (avail_spare)
			return (zfs_error(hdl, EZFS_ISSPARE, msg));

		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
		    &zc.zc_guid) == 0);
	}

	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
		return (0);

	return (zpool_standard_error(hdl, errno, msg));
}
示例#2
0
/*
 * Bring the specified vdev online
 */
int
zpool_vdev_online(zpool_handle_t *zhp, const char *path)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	nvlist_t *tgt;
	boolean_t avail_spare;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	(void) snprintf(msg, sizeof (msg),
	    dgettext(TEXT_DOMAIN, "cannot online %s"), path);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);

	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
		return (zfs_error(hdl, EZFS_ISSPARE, msg));

	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0)
		return (0);

	return (zpool_standard_error(hdl, errno, msg));
}
示例#3
0
/*
 * Remove the given device.  Currently, this is supported only for hot spares.
 */
int
zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	nvlist_t *tgt;
	boolean_t avail_spare;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	(void) snprintf(msg, sizeof (msg),
	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	if (!avail_spare) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "only hot spares can be removed"));
		return (zfs_error(hdl, EZFS_NODEVICE, msg));
	}

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);

	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
		return (0);

	return (zpool_standard_error(hdl, errno, msg));
}
示例#4
0
/**
 * Attach a vdev to a given zpool
 * @return 0 in case of success, the error code overwise
 */
int libzfs_zpool_vdev_attach(zpool_handle_t *p_zpool, const char *psz_current_dev, nvlist_t *pnv_root, int i_replacing, const char **ppsz_error)
{
        spa_t *p_spa;
        nvlist_t *pnv_tgt;
        boolean_t avail_spare, l2cache;
        uint64_t guid;
        int i_error;

        if((pnv_tgt = zpool_find_vdev(p_zpool, psz_current_dev,
                                      &avail_spare, &l2cache, NULL)) == 0)
        {
                *ppsz_error = "no vdev corresponding to the one given";
                return ENOENT;
        }
        assert(nvlist_lookup_uint64(pnv_tgt, ZPOOL_CONFIG_GUID, &guid) == 0);

        // Do not attach hot spares or L2 cache
        if(avail_spare)
        {
                *ppsz_error = "could not attach hot spares";
                return EINVAL;
        }
        if(l2cache)
        {
                *ppsz_error = "could not attach to a device actually used as a cache";
                return EINVAL;
        }


        if((i_error = spa_open(p_zpool->zpool_name, &p_spa, FTAG)))
                return i_error;

        i_error = spa_vdev_attach(p_spa, guid, pnv_root, i_replacing);
        spa_close(p_spa, FTAG);

        switch(i_error)
        {
        case ENOTSUP:
                *ppsz_error = "can only attach to mirror and top-level disks";
                break;
        case EINVAL:
                *ppsz_error = "new device must be a single disk";
                break;
        case EBUSY:
                *ppsz_error = "the device is busy";
                break;
        case EOVERFLOW:
                *ppsz_error = "devices is too small";
                break;
        case EDOM:
                *ppsz_error = "devices have different sector alignment";
                break;
        default:
                *ppsz_error ="unable to attach the new device";
        }

        return i_error;
}
示例#5
0
/**
 * Detach the given vdev from the given pool
 * @param p_zpool: the zpool handler
 * @param psz_device: the device name
 * @param ppsz_error: the error message if any
 * @return 0 in case of success, the error code overwise
 */
int libzfs_zpool_vdev_detach(zpool_handle_t *p_zpool, const char *psz_device, const char **ppsz_error)
{
        spa_t *p_spa;
        nvlist_t *pnv_tgt;
        boolean_t avail_spare, l2cache;
        uint64_t guid;
        int i_error;

        if((pnv_tgt = zpool_find_vdev(p_zpool, psz_device,
                                      &avail_spare, &l2cache, NULL)) == 0)
        {
                *ppsz_error = "no vdev corresponding to the one given";
                return ENOENT;
        }

        // Do not detach hot spares or L2 cache
        if(avail_spare)
        {
                *ppsz_error = "could not detach hot spares";
                return EINVAL;
        }
        if(l2cache)
        {
                *ppsz_error = "could not detach device actually used as a cache";
                return EINVAL;
        }

        assert(nvlist_lookup_uint64(pnv_tgt, ZPOOL_CONFIG_GUID, &guid) == 0);

        if((i_error = spa_open(p_zpool->zpool_name, &p_spa, FTAG)))
        {
                *ppsz_error = "unable to open the given zpool";
                return i_error;
        }

        if((i_error = spa_vdev_detach(p_spa, guid, 0, 0)))
        {
                switch(i_error)
                {
                case ENOTSUP:
                        *ppsz_error = "'detach' is only applicable to mirror and to replace vdevs";
                        break;
                case EBUSY:
                        *ppsz_error = "the device is actually in use";
                        break;
                default:
                        *ppsz_error = "unable to detach the given vdev";
                }
        }
        spa_close(p_spa, FTAG);

        return i_error;
}
示例#6
0
/*
 * Detach the specified device.
 */
int
zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	nvlist_t *tgt;
	boolean_t avail_spare;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	(void) snprintf(msg, sizeof (msg),
	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	if (avail_spare)
		return (zfs_error(hdl, EZFS_ISSPARE, msg));

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);

	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0)
		return (0);

	switch (errno) {

	case ENOTSUP:
		/*
		 * Can't detach from this type of vdev.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
		    "applicable to mirror and replacing vdevs"));
		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
		break;

	case EBUSY:
		/*
		 * There are no other replicas of this device.
		 */
		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
		break;

	default:
		(void) zpool_standard_error(hdl, errno, msg);
	}

	return (-1);
}
示例#7
0
/**
 * Remove the given vdev from the pool
 * @param p_zpool: the zpool handler
 * @param psz_name: the name of the device to remove
 * @param ppsz_error: the error message if any
 * @return 0 in case of success, the error code overwise
 */
int libzfs_zpool_vdev_remove(zpool_handle_t *p_zpool, const char *psz_name, const char **ppsz_error)
{
        nvlist_t *pnv_tgt;
        spa_t *p_spa;
        boolean_t avail_spare, l2cache, islog;
        uint64_t guid;
        int i_error;

        if((pnv_tgt = zpool_find_vdev(p_zpool, psz_name,
                                      &avail_spare, &l2cache, &islog)) == 0)
        {
                *ppsz_error = "no vdev corresponding to the one given";
                return ENOENT;
        }

        assert(nvlist_lookup_uint64(pnv_tgt, ZPOOL_CONFIG_GUID, &guid) == 0);

        if((i_error = spa_open(p_zpool->zpool_name, &p_spa, FTAG)))
        {
                *ppsz_error = "unable to open the spa";
                return i_error;
        }
        i_error = spa_vdev_remove(p_spa, guid, B_FALSE);
        spa_close(p_spa, FTAG);

        switch(i_error)
        {
        case 0:
                return 0;
        case ENOTSUP:
                *ppsz_error = "only spares, slogs, and level 2 ARC devices can be removed";
                break;
        case ENOENT:
                *ppsz_error = "no vdev corresponding to the one given";
                break;
        }

        return i_error;
}
示例#8
0
/*
 * Take the specified vdev offline
 */
int
zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	nvlist_t *tgt;
	boolean_t avail_spare;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	(void) snprintf(msg, sizeof (msg),
	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);

	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
		return (zfs_error(hdl, EZFS_ISSPARE, msg));

	zc.zc_cookie = istmp;

	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0)
		return (0);

	switch (errno) {
	case EBUSY:

		/*
		 * There are no other replicas of this device.
		 */
		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));

	default:
		return (zpool_standard_error(hdl, errno, msg));
	}
}
示例#9
0
/*
 * Attach new_disk (fully described by nvroot) to old_disk.
 * If 'replacing' is specified, tne new disk will replace the old one.
 */
int
zpool_vdev_attach(zpool_handle_t *zhp,
    const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
{
	zfs_cmd_t zc = { 0 };
	char msg[1024];
	char *packed;
	int ret;
	size_t len;
	nvlist_t *tgt;
	boolean_t avail_spare;
	uint64_t val;
	char *path;
	nvlist_t **child;
	uint_t children;
	nvlist_t *config_root;
	libzfs_handle_t *hdl = zhp->zpool_hdl;

	if (replacing)
		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
		    "cannot replace %s with %s"), old_disk, new_disk);
	else
		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
		    "cannot attach %s to %s"), new_disk, old_disk);

	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0)
		return (zfs_error(hdl, EZFS_NODEVICE, msg));

	if (avail_spare)
		return (zfs_error(hdl, EZFS_ISSPARE, msg));

	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
	zc.zc_cookie = replacing;

	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
	    &child, &children) != 0 || children != 1) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "new device must be a single disk"));
		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
	}

	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);

	/*
	 * If the target is a hot spare that has been swapped in, we can only
	 * replace it with another hot spare.
	 */
	if (replacing &&
	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
	    (zpool_find_vdev(zhp, path, &avail_spare) == NULL ||
	    !avail_spare) && is_replacing_spare(config_root, tgt, 1)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "can only be replaced by another hot spare"));
		return (zfs_error(hdl, EZFS_BADTARGET, msg));
	}

	/*
	 * If we are attempting to replace a spare, it canot be applied to an
	 * already spared device.
	 */
	if (replacing &&
	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
	    zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare &&
	    is_replacing_spare(config_root, tgt, 0)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "device has already been replaced with a spare"));
		return (zfs_error(hdl, EZFS_BADTARGET, msg));
	}

	verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);

	if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
		return (-1);

	verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);

	zc.zc_config_src = (uint64_t)(uintptr_t)packed;
	zc.zc_config_src_size = len;

	ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);

	free(packed);

	if (ret == 0)
		return (0);

	switch (errno) {
	case ENOTSUP:
		/*
		 * Can't attach to or replace this type of vdev.
		 */
		if (replacing)
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "cannot replace a replacing device"));
		else
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "can only attach to mirrors and top-level "
			    "disks"));
		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
		break;

	case EINVAL:
		/*
		 * The new device must be a single disk.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "new device must be a single disk"));
		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
		break;

	case EBUSY:
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
		    new_disk);
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case EOVERFLOW:
		/*
		 * The new device is too small.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "device is too small"));
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case EDOM:
		/*
		 * The new device has a different alignment requirement.
		 */
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "devices have different sector alignment"));
		(void) zfs_error(hdl, EZFS_BADDEV, msg);
		break;

	case ENAMETOOLONG:
		/*
		 * The resulting top-level vdev spec won't fit in the label.
		 */
		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
		break;

	default:
		(void) zpool_standard_error(hdl, errno, msg);
	}

	return (-1);
}