1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 238525SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #include <ctype.h> 28789Sahrens #include <errno.h> 29789Sahrens #include <devid.h> 30789Sahrens #include <fcntl.h> 31789Sahrens #include <libintl.h> 32789Sahrens #include <stdio.h> 33789Sahrens #include <stdlib.h> 343126Sahl #include <strings.h> 35789Sahrens #include <unistd.h> 364276Staylor #include <sys/efi_partition.h> 374276Staylor #include <sys/vtoc.h> 38789Sahrens #include <sys/zfs_ioctl.h> 399816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 40789Sahrens 41789Sahrens #include "zfs_namecheck.h" 423912Slling #include "zfs_prop.h" 43789Sahrens #include "libzfs_impl.h" 44789Sahrens 457042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 465094Slling 477965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 487965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 497965SGeorge.Wilson@Sun.COM #else 507965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 517965SGeorge.Wilson@Sun.COM #endif 527965SGeorge.Wilson@Sun.COM 539816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 549816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 559816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 569816SGeorge.Wilson@Sun.COM 575094Slling /* 585094Slling * ==================================================================== 595094Slling * zpool property functions 605094Slling * ==================================================================== 615094Slling */ 625094Slling 635094Slling static int 645094Slling zpool_get_all_props(zpool_handle_t *zhp) 655094Slling { 665094Slling zfs_cmd_t zc = { 0 }; 675094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 685094Slling 695094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 705094Slling 715094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 725094Slling return (-1); 735094Slling 745094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 755094Slling if (errno == ENOMEM) { 765094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 775094Slling zcmd_free_nvlists(&zc); 785094Slling return (-1); 795094Slling } 805094Slling } else { 815094Slling zcmd_free_nvlists(&zc); 825094Slling return (-1); 835094Slling } 845094Slling } 855094Slling 865094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 875094Slling zcmd_free_nvlists(&zc); 885094Slling return (-1); 895094Slling } 905094Slling 915094Slling zcmd_free_nvlists(&zc); 925094Slling 935094Slling return (0); 945094Slling } 955094Slling 965094Slling static int 975094Slling zpool_props_refresh(zpool_handle_t *zhp) 985094Slling { 995094Slling nvlist_t *old_props; 1005094Slling 1015094Slling old_props = zhp->zpool_props; 1025094Slling 1035094Slling if (zpool_get_all_props(zhp) != 0) 1045094Slling return (-1); 1055094Slling 1065094Slling nvlist_free(old_props); 1075094Slling return (0); 1085094Slling } 1095094Slling 1105094Slling static char * 1115094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1125094Slling zprop_source_t *src) 1135094Slling { 1145094Slling nvlist_t *nv, *nvl; 1155094Slling uint64_t ival; 1165094Slling char *value; 1175094Slling zprop_source_t source; 1185094Slling 1195094Slling nvl = zhp->zpool_props; 1205094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1215094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1225094Slling source = ival; 1235094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1245094Slling } else { 1255094Slling source = ZPROP_SRC_DEFAULT; 1265094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1275094Slling value = "-"; 1285094Slling } 1295094Slling 1305094Slling if (src) 1315094Slling *src = source; 1325094Slling 1335094Slling return (value); 1345094Slling } 1355094Slling 1365094Slling uint64_t 1375094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1385094Slling { 1395094Slling nvlist_t *nv, *nvl; 1405094Slling uint64_t value; 1415094Slling zprop_source_t source; 1425094Slling 1437294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1447294Sperrin /* 1457294Sperrin * zpool_get_all_props() has most likely failed because 1467294Sperrin * the pool is faulted, but if all we need is the top level 1477294Sperrin * vdev's guid then get it from the zhp config nvlist. 1487294Sperrin */ 1497294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1507294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1517294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1527294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1537294Sperrin == 0)) { 1547294Sperrin return (value); 1557294Sperrin } 1565094Slling return (zpool_prop_default_numeric(prop)); 1577294Sperrin } 1585094Slling 1595094Slling nvl = zhp->zpool_props; 1605094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1615094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 1625094Slling source = value; 1635094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1645094Slling } else { 1655094Slling source = ZPROP_SRC_DEFAULT; 1665094Slling value = zpool_prop_default_numeric(prop); 1675094Slling } 1685094Slling 1695094Slling if (src) 1705094Slling *src = source; 1715094Slling 1725094Slling return (value); 1735094Slling } 1745094Slling 1755094Slling /* 1765094Slling * Map VDEV STATE to printed strings. 1775094Slling */ 1785094Slling char * 1795094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 1805094Slling { 1815094Slling switch (state) { 1825094Slling case VDEV_STATE_CLOSED: 1835094Slling case VDEV_STATE_OFFLINE: 1845094Slling return (gettext("OFFLINE")); 1855094Slling case VDEV_STATE_REMOVED: 1865094Slling return (gettext("REMOVED")); 1875094Slling case VDEV_STATE_CANT_OPEN: 1887294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 1895094Slling return (gettext("FAULTED")); 1905094Slling else 1915094Slling return (gettext("UNAVAIL")); 1925094Slling case VDEV_STATE_FAULTED: 1935094Slling return (gettext("FAULTED")); 1945094Slling case VDEV_STATE_DEGRADED: 1955094Slling return (gettext("DEGRADED")); 1965094Slling case VDEV_STATE_HEALTHY: 1975094Slling return (gettext("ONLINE")); 1985094Slling } 1995094Slling 2005094Slling return (gettext("UNKNOWN")); 2015094Slling } 2025094Slling 2035094Slling /* 2045094Slling * Get a zpool property value for 'prop' and return the value in 2055094Slling * a pre-allocated buffer. 2065094Slling */ 2075094Slling int 2085094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2095094Slling zprop_source_t *srctype) 2105094Slling { 2115094Slling uint64_t intval; 2125094Slling const char *strval; 2135094Slling zprop_source_t src = ZPROP_SRC_NONE; 2145094Slling nvlist_t *nvroot; 2155094Slling vdev_stat_t *vs; 2165094Slling uint_t vsc; 2175094Slling 2185094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2198525SEric.Schrock@Sun.COM switch (prop) { 2208525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2215094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2228525SEric.Schrock@Sun.COM break; 2238525SEric.Schrock@Sun.COM 2248525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2255094Slling (void) strlcpy(buf, "FAULTED", len); 2268525SEric.Schrock@Sun.COM break; 2278525SEric.Schrock@Sun.COM 2288525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2298525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2308525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2318525SEric.Schrock@Sun.COM break; 2328525SEric.Schrock@Sun.COM 2338525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2348525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2358525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2368525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2378525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2388525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2398525SEric.Schrock@Sun.COM len); 2408525SEric.Schrock@Sun.COM if (srctype != NULL) 2418525SEric.Schrock@Sun.COM *srctype = src; 2428525SEric.Schrock@Sun.COM return (0); 2438525SEric.Schrock@Sun.COM } 2448525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2458525SEric.Schrock@Sun.COM default: 2465094Slling (void) strlcpy(buf, "-", len); 2478525SEric.Schrock@Sun.COM break; 2488525SEric.Schrock@Sun.COM } 2498525SEric.Schrock@Sun.COM 2508525SEric.Schrock@Sun.COM if (srctype != NULL) 2518525SEric.Schrock@Sun.COM *srctype = src; 2525094Slling return (0); 2535094Slling } 2545094Slling 2555094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2565094Slling prop != ZPOOL_PROP_NAME) 2575094Slling return (-1); 2585094Slling 2595094Slling switch (zpool_prop_get_type(prop)) { 2605094Slling case PROP_TYPE_STRING: 2615094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 2625094Slling len); 2635094Slling break; 2645094Slling 2655094Slling case PROP_TYPE_NUMBER: 2665094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2675094Slling 2685094Slling switch (prop) { 2695094Slling case ZPOOL_PROP_SIZE: 2705094Slling case ZPOOL_PROP_USED: 2715094Slling case ZPOOL_PROP_AVAILABLE: 2725094Slling (void) zfs_nicenum(intval, buf, len); 2735094Slling break; 2745094Slling 2755094Slling case ZPOOL_PROP_CAPACITY: 2765094Slling (void) snprintf(buf, len, "%llu%%", 2775094Slling (u_longlong_t)intval); 2785094Slling break; 2795094Slling 2805094Slling case ZPOOL_PROP_HEALTH: 2815094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 2825094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2835094Slling verify(nvlist_lookup_uint64_array(nvroot, 2845094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 2855094Slling 2865094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 2875094Slling vs->vs_aux), len); 2885094Slling break; 2895094Slling default: 2905094Slling (void) snprintf(buf, len, "%llu", intval); 2915094Slling } 2925094Slling break; 2935094Slling 2945094Slling case PROP_TYPE_INDEX: 2955094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2965094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 2975094Slling != 0) 2985094Slling return (-1); 2995094Slling (void) strlcpy(buf, strval, len); 3005094Slling break; 3015094Slling 3025094Slling default: 3035094Slling abort(); 3045094Slling } 3055094Slling 3065094Slling if (srctype) 3075094Slling *srctype = src; 3085094Slling 3095094Slling return (0); 3105094Slling } 3115094Slling 3125094Slling /* 3135094Slling * Check if the bootfs name has the same pool name as it is set to. 3145094Slling * Assuming bootfs is a valid dataset name. 3155094Slling */ 3165094Slling static boolean_t 3175094Slling bootfs_name_valid(const char *pool, char *bootfs) 3185094Slling { 3195094Slling int len = strlen(pool); 3205094Slling 3217300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3225094Slling return (B_FALSE); 3235094Slling 3245094Slling if (strncmp(pool, bootfs, len) == 0 && 3255094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3265094Slling return (B_TRUE); 3275094Slling 3285094Slling return (B_FALSE); 3295094Slling } 3305094Slling 3315094Slling /* 3327042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3337042Sgw25295 * an EFI label. 3347042Sgw25295 */ 3357042Sgw25295 static boolean_t 3367042Sgw25295 pool_uses_efi(nvlist_t *config) 3377042Sgw25295 { 3387042Sgw25295 nvlist_t **child; 3397042Sgw25295 uint_t c, children; 3407042Sgw25295 3417042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3427042Sgw25295 &child, &children) != 0) 3437042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3447042Sgw25295 3457042Sgw25295 for (c = 0; c < children; c++) { 3467042Sgw25295 if (pool_uses_efi(child[c])) 3477042Sgw25295 return (B_TRUE); 3487042Sgw25295 } 3497042Sgw25295 return (B_FALSE); 3507042Sgw25295 } 3517042Sgw25295 3527965SGeorge.Wilson@Sun.COM static boolean_t 3537965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3547965SGeorge.Wilson@Sun.COM { 3557965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3567965SGeorge.Wilson@Sun.COM 3577965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 3587965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 3597965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 3607965SGeorge.Wilson@Sun.COM } 3617965SGeorge.Wilson@Sun.COM 3627965SGeorge.Wilson@Sun.COM 3637042Sgw25295 /* 3645094Slling * Given an nvlist of zpool properties to be set, validate that they are 3655094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 3665094Slling * specified as strings. 3675094Slling */ 3685094Slling static nvlist_t * 3697184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 3705094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 3715094Slling { 3725094Slling nvpair_t *elem; 3735094Slling nvlist_t *retprops; 3745094Slling zpool_prop_t prop; 3755094Slling char *strval; 3765094Slling uint64_t intval; 3775363Seschrock char *slash; 3785363Seschrock struct stat64 statbuf; 3797042Sgw25295 zpool_handle_t *zhp; 3807042Sgw25295 nvlist_t *nvroot; 3815094Slling 3825094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 3835094Slling (void) no_memory(hdl); 3845094Slling return (NULL); 3855094Slling } 3865094Slling 3875094Slling elem = NULL; 3885094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 3895094Slling const char *propname = nvpair_name(elem); 3905094Slling 3915094Slling /* 3925094Slling * Make sure this property is valid and applies to this type. 3935094Slling */ 3945094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 3955094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3965094Slling "invalid property '%s'"), propname); 3975094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 3985094Slling goto error; 3995094Slling } 4005094Slling 4015094Slling if (zpool_prop_readonly(prop)) { 4025094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4035094Slling "is readonly"), propname); 4045094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4055094Slling goto error; 4065094Slling } 4075094Slling 4085094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4095094Slling &strval, &intval, errbuf) != 0) 4105094Slling goto error; 4115094Slling 4125094Slling /* 4135094Slling * Perform additional checking for specific properties. 4145094Slling */ 4155094Slling switch (prop) { 4165094Slling case ZPOOL_PROP_VERSION: 4175094Slling if (intval < version || intval > SPA_VERSION) { 4185094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4195094Slling "property '%s' number %d is invalid."), 4205094Slling propname, intval); 4215094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4225094Slling goto error; 4235094Slling } 4245094Slling break; 4255094Slling 4265094Slling case ZPOOL_PROP_BOOTFS: 4275094Slling if (create_or_import) { 4285094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4295094Slling "property '%s' cannot be set at creation " 4305094Slling "or import time"), propname); 4315094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4325094Slling goto error; 4335094Slling } 4345094Slling 4355094Slling if (version < SPA_VERSION_BOOTFS) { 4365094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4375094Slling "pool must be upgraded to support " 4385094Slling "'%s' property"), propname); 4395094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4405094Slling goto error; 4415094Slling } 4425094Slling 4435094Slling /* 4445094Slling * bootfs property value has to be a dataset name and 4455094Slling * the dataset has to be in the same pool as it sets to. 4465094Slling */ 4475094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4485094Slling strval)) { 4495094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4505094Slling "is an invalid name"), strval); 4515094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4525094Slling goto error; 4535094Slling } 4547042Sgw25295 4557042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4567042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4577042Sgw25295 "could not open pool '%s'"), poolname); 4587042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4597042Sgw25295 goto error; 4607042Sgw25295 } 4617042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 4627042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 4637042Sgw25295 4647042Sgw25295 /* 4657042Sgw25295 * bootfs property cannot be set on a disk which has 4667042Sgw25295 * been EFI labeled. 4677042Sgw25295 */ 4687042Sgw25295 if (pool_uses_efi(nvroot)) { 4697042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4707042Sgw25295 "property '%s' not supported on " 4717042Sgw25295 "EFI labeled devices"), propname); 4727042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 4737042Sgw25295 zpool_close(zhp); 4747042Sgw25295 goto error; 4757042Sgw25295 } 4767042Sgw25295 zpool_close(zhp); 4775094Slling break; 4785094Slling 4795094Slling case ZPOOL_PROP_ALTROOT: 4805094Slling if (!create_or_import) { 4815094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4825094Slling "property '%s' can only be set during pool " 4835094Slling "creation or import"), propname); 4845094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4855094Slling goto error; 4865094Slling } 4875094Slling 4885094Slling if (strval[0] != '/') { 4895094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4905094Slling "bad alternate root '%s'"), strval); 4915094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 4925094Slling goto error; 4935094Slling } 4945094Slling break; 4955363Seschrock 4965363Seschrock case ZPOOL_PROP_CACHEFILE: 4975363Seschrock if (strval[0] == '\0') 4985363Seschrock break; 4995363Seschrock 5005363Seschrock if (strcmp(strval, "none") == 0) 5015363Seschrock break; 5025363Seschrock 5035363Seschrock if (strval[0] != '/') { 5045363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5055363Seschrock "property '%s' must be empty, an " 5065363Seschrock "absolute path, or 'none'"), propname); 5075363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5085363Seschrock goto error; 5095363Seschrock } 5105363Seschrock 5115363Seschrock slash = strrchr(strval, '/'); 5125363Seschrock 5135363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5145363Seschrock strcmp(slash, "/..") == 0) { 5155363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5165363Seschrock "'%s' is not a valid file"), strval); 5175363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5185363Seschrock goto error; 5195363Seschrock } 5205363Seschrock 5215363Seschrock *slash = '\0'; 5225363Seschrock 5235621Seschrock if (strval[0] != '\0' && 5245621Seschrock (stat64(strval, &statbuf) != 0 || 5255621Seschrock !S_ISDIR(statbuf.st_mode))) { 5265363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5275363Seschrock "'%s' is not a valid directory"), 5285363Seschrock strval); 5295363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5305363Seschrock goto error; 5315363Seschrock } 5325363Seschrock 5335363Seschrock *slash = '/'; 5345363Seschrock break; 5355094Slling } 5365094Slling } 5375094Slling 5385094Slling return (retprops); 5395094Slling error: 5405094Slling nvlist_free(retprops); 5415094Slling return (NULL); 5425094Slling } 5435094Slling 5445094Slling /* 5455094Slling * Set zpool property : propname=propval. 5465094Slling */ 5475094Slling int 5485094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5495094Slling { 5505094Slling zfs_cmd_t zc = { 0 }; 5515094Slling int ret = -1; 5525094Slling char errbuf[1024]; 5535094Slling nvlist_t *nvl = NULL; 5545094Slling nvlist_t *realprops; 5555094Slling uint64_t version; 5565094Slling 5575094Slling (void) snprintf(errbuf, sizeof (errbuf), 5585094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 5595094Slling zhp->zpool_name); 5605094Slling 5615094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5625094Slling return (no_memory(zhp->zpool_hdl)); 5635094Slling 5645094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 5655094Slling nvlist_free(nvl); 5665094Slling return (no_memory(zhp->zpool_hdl)); 5675094Slling } 5685094Slling 5695094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5707184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 5715094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 5725094Slling nvlist_free(nvl); 5735094Slling return (-1); 5745094Slling } 5755094Slling 5765094Slling nvlist_free(nvl); 5775094Slling nvl = realprops; 5785094Slling 5795094Slling /* 5805094Slling * Execute the corresponding ioctl() to set this property. 5815094Slling */ 5825094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 5835094Slling 5845094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 5855094Slling nvlist_free(nvl); 5865094Slling return (-1); 5875094Slling } 5885094Slling 5895094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 5905094Slling 5915094Slling zcmd_free_nvlists(&zc); 5925094Slling nvlist_free(nvl); 5935094Slling 5945094Slling if (ret) 5955094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 5965094Slling else 5975094Slling (void) zpool_props_refresh(zhp); 5985094Slling 5995094Slling return (ret); 6005094Slling } 6015094Slling 6025094Slling int 6035094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6045094Slling { 6055094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6065094Slling zprop_list_t *entry; 6075094Slling char buf[ZFS_MAXPROPLEN]; 6085094Slling 6095094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6105094Slling return (-1); 6115094Slling 6125094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6135094Slling 6145094Slling if (entry->pl_fixed) 6155094Slling continue; 6165094Slling 6175094Slling if (entry->pl_prop != ZPROP_INVAL && 6185094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6195094Slling NULL) == 0) { 6205094Slling if (strlen(buf) > entry->pl_width) 6215094Slling entry->pl_width = strlen(buf); 6225094Slling } 6235094Slling } 6245094Slling 6255094Slling return (0); 6265094Slling } 6275094Slling 6285094Slling 629789Sahrens /* 6309816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6319816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6329816SGeorge.Wilson@Sun.COM */ 6339816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6349816SGeorge.Wilson@Sun.COM 6359816SGeorge.Wilson@Sun.COM /* 636789Sahrens * Validate the given pool name, optionally putting an extended error message in 637789Sahrens * 'buf'. 638789Sahrens */ 6396423Sgw25295 boolean_t 6402082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 641789Sahrens { 642789Sahrens namecheck_err_t why; 643789Sahrens char what; 6441773Seschrock int ret; 645789Sahrens 6461773Seschrock ret = pool_namecheck(pool, &why, &what); 6471773Seschrock 6481773Seschrock /* 6491773Seschrock * The rules for reserved pool names were extended at a later point. 6501773Seschrock * But we need to support users with existing pools that may now be 6511773Seschrock * invalid. So we only check for this expanded set of names during a 6521773Seschrock * create (or import), and only in userland. 6531773Seschrock */ 6541773Seschrock if (ret == 0 && !isopen && 6551773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6561773Seschrock strncmp(pool, "raidz", 5) == 0 || 6574527Sperrin strncmp(pool, "spare", 5) == 0 || 6584527Sperrin strcmp(pool, "log") == 0)) { 6596423Sgw25295 if (hdl != NULL) 6606423Sgw25295 zfs_error_aux(hdl, 6616423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 6622082Seschrock return (B_FALSE); 6631773Seschrock } 6641773Seschrock 6651773Seschrock 6661773Seschrock if (ret != 0) { 6672082Seschrock if (hdl != NULL) { 668789Sahrens switch (why) { 6691003Slling case NAME_ERR_TOOLONG: 6702082Seschrock zfs_error_aux(hdl, 6711003Slling dgettext(TEXT_DOMAIN, "name is too long")); 6721003Slling break; 6731003Slling 674789Sahrens case NAME_ERR_INVALCHAR: 6752082Seschrock zfs_error_aux(hdl, 676789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 677789Sahrens "'%c' in pool name"), what); 678789Sahrens break; 679789Sahrens 680789Sahrens case NAME_ERR_NOLETTER: 6812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6822082Seschrock "name must begin with a letter")); 683789Sahrens break; 684789Sahrens 685789Sahrens case NAME_ERR_RESERVED: 6862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6872082Seschrock "name is reserved")); 688789Sahrens break; 689789Sahrens 690789Sahrens case NAME_ERR_DISKLIKE: 6912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6922082Seschrock "pool name is reserved")); 693789Sahrens break; 6942856Snd150628 6952856Snd150628 case NAME_ERR_LEADING_SLASH: 6962856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6972856Snd150628 "leading slash in name")); 6982856Snd150628 break; 6992856Snd150628 7002856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7012856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7022856Snd150628 "empty component in name")); 7032856Snd150628 break; 7042856Snd150628 7052856Snd150628 case NAME_ERR_TRAILING_SLASH: 7062856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7072856Snd150628 "trailing slash in name")); 7082856Snd150628 break; 7092856Snd150628 7102856Snd150628 case NAME_ERR_MULTIPLE_AT: 7112856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7122856Snd150628 "multiple '@' delimiters in name")); 7132856Snd150628 break; 7142856Snd150628 715789Sahrens } 716789Sahrens } 7172082Seschrock return (B_FALSE); 718789Sahrens } 719789Sahrens 7202082Seschrock return (B_TRUE); 721789Sahrens } 722789Sahrens 723789Sahrens /* 724789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 725789Sahrens * state. 726789Sahrens */ 727789Sahrens zpool_handle_t * 7282082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 729789Sahrens { 730789Sahrens zpool_handle_t *zhp; 7312142Seschrock boolean_t missing; 732789Sahrens 733789Sahrens /* 734789Sahrens * Make sure the pool name is valid. 735789Sahrens */ 7362082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7373237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7382082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7392082Seschrock pool); 740789Sahrens return (NULL); 741789Sahrens } 742789Sahrens 7432082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7442082Seschrock return (NULL); 745789Sahrens 7462082Seschrock zhp->zpool_hdl = hdl; 747789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 748789Sahrens 7492142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7502142Seschrock zpool_close(zhp); 7512142Seschrock return (NULL); 7522142Seschrock } 7532142Seschrock 7542142Seschrock if (missing) { 7555094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7563237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 7575094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 7582142Seschrock zpool_close(zhp); 7592142Seschrock return (NULL); 760789Sahrens } 761789Sahrens 762789Sahrens return (zhp); 763789Sahrens } 764789Sahrens 765789Sahrens /* 766789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 767789Sahrens * the configuration cache may be out of date). 768789Sahrens */ 7692142Seschrock int 7702142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 771789Sahrens { 772789Sahrens zpool_handle_t *zhp; 7732142Seschrock boolean_t missing; 774789Sahrens 7752142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7762142Seschrock return (-1); 777789Sahrens 7782082Seschrock zhp->zpool_hdl = hdl; 779789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 780789Sahrens 7812142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7822142Seschrock zpool_close(zhp); 7832142Seschrock return (-1); 784789Sahrens } 785789Sahrens 7862142Seschrock if (missing) { 7872142Seschrock zpool_close(zhp); 7882142Seschrock *ret = NULL; 7892142Seschrock return (0); 7902142Seschrock } 7912142Seschrock 7922142Seschrock *ret = zhp; 7932142Seschrock return (0); 794789Sahrens } 795789Sahrens 796789Sahrens /* 797789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 798789Sahrens * state. 799789Sahrens */ 800789Sahrens zpool_handle_t * 8012082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 802789Sahrens { 803789Sahrens zpool_handle_t *zhp; 804789Sahrens 8052082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 806789Sahrens return (NULL); 807789Sahrens 808789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8093237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8102082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 811789Sahrens zpool_close(zhp); 812789Sahrens return (NULL); 813789Sahrens } 814789Sahrens 815789Sahrens return (zhp); 816789Sahrens } 817789Sahrens 818789Sahrens /* 819789Sahrens * Close the handle. Simply frees the memory associated with the handle. 820789Sahrens */ 821789Sahrens void 822789Sahrens zpool_close(zpool_handle_t *zhp) 823789Sahrens { 824789Sahrens if (zhp->zpool_config) 825789Sahrens nvlist_free(zhp->zpool_config); 826952Seschrock if (zhp->zpool_old_config) 827952Seschrock nvlist_free(zhp->zpool_old_config); 8283912Slling if (zhp->zpool_props) 8293912Slling nvlist_free(zhp->zpool_props); 830789Sahrens free(zhp); 831789Sahrens } 832789Sahrens 833789Sahrens /* 834789Sahrens * Return the name of the pool. 835789Sahrens */ 836789Sahrens const char * 837789Sahrens zpool_get_name(zpool_handle_t *zhp) 838789Sahrens { 839789Sahrens return (zhp->zpool_name); 840789Sahrens } 841789Sahrens 842789Sahrens 843789Sahrens /* 844789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 845789Sahrens */ 846789Sahrens int 847789Sahrens zpool_get_state(zpool_handle_t *zhp) 848789Sahrens { 849789Sahrens return (zhp->zpool_state); 850789Sahrens } 851789Sahrens 852789Sahrens /* 853789Sahrens * Create the named pool, using the provided vdev list. It is assumed 854789Sahrens * that the consumer has already validated the contents of the nvlist, so we 855789Sahrens * don't have to worry about error semantics. 856789Sahrens */ 857789Sahrens int 8582082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8597184Stimh nvlist_t *props, nvlist_t *fsprops) 860789Sahrens { 861789Sahrens zfs_cmd_t zc = { 0 }; 8627184Stimh nvlist_t *zc_fsprops = NULL; 8637184Stimh nvlist_t *zc_props = NULL; 8642082Seschrock char msg[1024]; 8655094Slling char *altroot; 8667184Stimh int ret = -1; 8672082Seschrock 8682082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 8692082Seschrock "cannot create '%s'"), pool); 870789Sahrens 8712082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 8722082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 8732082Seschrock 8745320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 8755320Slling return (-1); 8765320Slling 8777184Stimh if (props) { 8787184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8797184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8807184Stimh goto create_failed; 8817184Stimh } 8825320Slling } 883789Sahrens 8847184Stimh if (fsprops) { 8857184Stimh uint64_t zoned; 8867184Stimh char *zonestr; 8877184Stimh 8887184Stimh zoned = ((nvlist_lookup_string(fsprops, 8897184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8907184Stimh strcmp(zonestr, "on") == 0); 8917184Stimh 8927184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 8937184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 8947184Stimh goto create_failed; 8957184Stimh } 8967184Stimh if (!zc_props && 8977184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 8987184Stimh goto create_failed; 8997184Stimh } 9007184Stimh if (nvlist_add_nvlist(zc_props, 9017184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9027184Stimh goto create_failed; 9037184Stimh } 9047184Stimh } 9057184Stimh 9067184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9077184Stimh goto create_failed; 9087184Stimh 909789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 910789Sahrens 9117184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9125320Slling 9132676Seschrock zcmd_free_nvlists(&zc); 9147184Stimh nvlist_free(zc_props); 9157184Stimh nvlist_free(zc_fsprops); 9162082Seschrock 917789Sahrens switch (errno) { 918789Sahrens case EBUSY: 919789Sahrens /* 920789Sahrens * This can happen if the user has specified the same 921789Sahrens * device multiple times. We can't reliably detect this 922789Sahrens * until we try to add it and see we already have a 923789Sahrens * label. 924789Sahrens */ 9252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9262082Seschrock "one or more vdevs refer to the same device")); 9272082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 928789Sahrens 929789Sahrens case EOVERFLOW: 930789Sahrens /* 9312082Seschrock * This occurs when one of the devices is below 932789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 933789Sahrens * device was the problem device since there's no 934789Sahrens * reliable way to determine device size from userland. 935789Sahrens */ 936789Sahrens { 937789Sahrens char buf[64]; 938789Sahrens 939789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 940789Sahrens 9412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9422082Seschrock "one or more devices is less than the " 9432082Seschrock "minimum size (%s)"), buf); 944789Sahrens } 9452082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 946789Sahrens 947789Sahrens case ENOSPC: 9482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9492082Seschrock "one or more devices is out of space")); 9502082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 951789Sahrens 9525450Sbrendan case ENOTBLK: 9535450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9545450Sbrendan "cache device must be a disk or disk slice")); 9555450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9565450Sbrendan 957789Sahrens default: 9582082Seschrock return (zpool_standard_error(hdl, errno, msg)); 959789Sahrens } 960789Sahrens } 961789Sahrens 962789Sahrens /* 963789Sahrens * If this is an alternate root pool, then we automatically set the 9642676Seschrock * mountpoint of the root dataset to be '/'. 965789Sahrens */ 9665094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 9675094Slling &altroot) == 0) { 968789Sahrens zfs_handle_t *zhp; 969789Sahrens 9705094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 9712676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 9722676Seschrock "/") == 0); 973789Sahrens 974789Sahrens zfs_close(zhp); 975789Sahrens } 976789Sahrens 9777184Stimh create_failed: 9785320Slling zcmd_free_nvlists(&zc); 9797184Stimh nvlist_free(zc_props); 9807184Stimh nvlist_free(zc_fsprops); 9817184Stimh return (ret); 982789Sahrens } 983789Sahrens 984789Sahrens /* 985789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 986789Sahrens * datasets left in the pool. 987789Sahrens */ 988789Sahrens int 989789Sahrens zpool_destroy(zpool_handle_t *zhp) 990789Sahrens { 991789Sahrens zfs_cmd_t zc = { 0 }; 992789Sahrens zfs_handle_t *zfp = NULL; 9932082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 9942082Seschrock char msg[1024]; 995789Sahrens 996789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 9972082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 9982082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 999789Sahrens return (-1); 1000789Sahrens 1001789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1002789Sahrens 10034543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10042082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10052082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1006789Sahrens 10072082Seschrock if (errno == EROFS) { 10082082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10092082Seschrock "one or more devices is read only")); 10102082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10112082Seschrock } else { 10122082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1013789Sahrens } 1014789Sahrens 1015789Sahrens if (zfp) 1016789Sahrens zfs_close(zfp); 1017789Sahrens return (-1); 1018789Sahrens } 1019789Sahrens 1020789Sahrens if (zfp) { 1021789Sahrens remove_mountpoint(zfp); 1022789Sahrens zfs_close(zfp); 1023789Sahrens } 1024789Sahrens 1025789Sahrens return (0); 1026789Sahrens } 1027789Sahrens 1028789Sahrens /* 1029789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1030789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1031789Sahrens */ 1032789Sahrens int 1033789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1034789Sahrens { 10352676Seschrock zfs_cmd_t zc = { 0 }; 10362082Seschrock int ret; 10372082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10382082Seschrock char msg[1024]; 10395450Sbrendan nvlist_t **spares, **l2cache; 10405450Sbrendan uint_t nspares, nl2cache; 10412082Seschrock 10422082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10432082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10442082Seschrock 10455450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10465450Sbrendan SPA_VERSION_SPARES && 10472082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10482082Seschrock &spares, &nspares) == 0) { 10492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10502082Seschrock "upgraded to add hot spares")); 10512082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10522082Seschrock } 1053789Sahrens 10547965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10557965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10567965SGeorge.Wilson@Sun.COM uint64_t s; 10577965SGeorge.Wilson@Sun.COM 10587965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 10597965SGeorge.Wilson@Sun.COM char *path; 10607965SGeorge.Wilson@Sun.COM 10617965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 10627965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 10637965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10647965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 10657965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 1066*10594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 1067*10594SGeorge.Wilson@Sun.COM B_FALSE)); 10687965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 10697965SGeorge.Wilson@Sun.COM } 10707965SGeorge.Wilson@Sun.COM } 10717965SGeorge.Wilson@Sun.COM } 10727965SGeorge.Wilson@Sun.COM 10735450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10745450Sbrendan SPA_VERSION_L2CACHE && 10755450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 10765450Sbrendan &l2cache, &nl2cache) == 0) { 10775450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10785450Sbrendan "upgraded to add cache devices")); 10795450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10805450Sbrendan } 10815450Sbrendan 10825094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 10832082Seschrock return (-1); 1084789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1085789Sahrens 10864543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1087789Sahrens switch (errno) { 1088789Sahrens case EBUSY: 1089789Sahrens /* 1090789Sahrens * This can happen if the user has specified the same 1091789Sahrens * device multiple times. We can't reliably detect this 1092789Sahrens * until we try to add it and see we already have a 1093789Sahrens * label. 1094789Sahrens */ 10952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10962082Seschrock "one or more vdevs refer to the same device")); 10972082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1098789Sahrens break; 1099789Sahrens 1100789Sahrens case EOVERFLOW: 1101789Sahrens /* 1102789Sahrens * This occurrs when one of the devices is below 1103789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1104789Sahrens * device was the problem device since there's no 1105789Sahrens * reliable way to determine device size from userland. 1106789Sahrens */ 1107789Sahrens { 1108789Sahrens char buf[64]; 1109789Sahrens 1110789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1111789Sahrens 11122082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11132082Seschrock "device is less than the minimum " 11142082Seschrock "size (%s)"), buf); 1115789Sahrens } 11162082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11172082Seschrock break; 11182082Seschrock 11192082Seschrock case ENOTSUP: 11202082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11214527Sperrin "pool must be upgraded to add these vdevs")); 11222082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1123789Sahrens break; 1124789Sahrens 11253912Slling case EDOM: 11263912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11274527Sperrin "root pool can not have multiple vdevs" 11284527Sperrin " or separate logs")); 11293912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11303912Slling break; 11313912Slling 11325450Sbrendan case ENOTBLK: 11335450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11345450Sbrendan "cache device must be a disk or disk slice")); 11355450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11365450Sbrendan break; 11375450Sbrendan 1138789Sahrens default: 11392082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1140789Sahrens } 1141789Sahrens 11422082Seschrock ret = -1; 11432082Seschrock } else { 11442082Seschrock ret = 0; 1145789Sahrens } 1146789Sahrens 11472676Seschrock zcmd_free_nvlists(&zc); 1148789Sahrens 11492082Seschrock return (ret); 1150789Sahrens } 1151789Sahrens 1152789Sahrens /* 1153789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1154789Sahrens * mounted datasets in the pool. 1155789Sahrens */ 1156789Sahrens int 11578211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1158789Sahrens { 1159789Sahrens zfs_cmd_t zc = { 0 }; 11607214Slling char msg[1024]; 1161789Sahrens 11627214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 11637214Slling "cannot export '%s'"), zhp->zpool_name); 11647214Slling 1165789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 11667214Slling zc.zc_cookie = force; 11678211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 11687214Slling 11697214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 11707214Slling switch (errno) { 11717214Slling case EXDEV: 11727214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 11737214Slling "use '-f' to override the following errors:\n" 11747214Slling "'%s' has an active shared spare which could be" 11757214Slling " used by other pools once '%s' is exported."), 11767214Slling zhp->zpool_name, zhp->zpool_name); 11777214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 11787214Slling msg)); 11797214Slling default: 11807214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 11817214Slling msg)); 11827214Slling } 11837214Slling } 11847214Slling 1185789Sahrens return (0); 1186789Sahrens } 1187789Sahrens 11888211SGeorge.Wilson@Sun.COM int 11898211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 11908211SGeorge.Wilson@Sun.COM { 11918211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 11928211SGeorge.Wilson@Sun.COM } 11938211SGeorge.Wilson@Sun.COM 11948211SGeorge.Wilson@Sun.COM int 11958211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 11968211SGeorge.Wilson@Sun.COM { 11978211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 11988211SGeorge.Wilson@Sun.COM } 11998211SGeorge.Wilson@Sun.COM 1200789Sahrens /* 12015094Slling * zpool_import() is a contracted interface. Should be kept the same 12025094Slling * if possible. 12035094Slling * 12045094Slling * Applications should use zpool_import_props() to import a pool with 12055094Slling * new properties value to be set. 1206789Sahrens */ 1207789Sahrens int 12082082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12095094Slling char *altroot) 12105094Slling { 12115094Slling nvlist_t *props = NULL; 12125094Slling int ret; 12135094Slling 12145094Slling if (altroot != NULL) { 12155094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 12165094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12175094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12185094Slling newname)); 12195094Slling } 12205094Slling 12215094Slling if (nvlist_add_string(props, 12228084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 12238084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 12248084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 12255094Slling nvlist_free(props); 12265094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12275094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12285094Slling newname)); 12295094Slling } 12305094Slling } 12315094Slling 12326643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 12335094Slling if (props) 12345094Slling nvlist_free(props); 12355094Slling return (ret); 12365094Slling } 12375094Slling 12385094Slling /* 12395094Slling * Import the given pool using the known configuration and a list of 12405094Slling * properties to be set. The configuration should have come from 12415094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 12425094Slling * is imported with a different name. 12435094Slling */ 12445094Slling int 12455094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12466643Seschrock nvlist_t *props, boolean_t importfaulted) 1247789Sahrens { 12482676Seschrock zfs_cmd_t zc = { 0 }; 1249789Sahrens char *thename; 1250789Sahrens char *origname; 1251789Sahrens int ret; 12525094Slling char errbuf[1024]; 1253789Sahrens 1254789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1255789Sahrens &origname) == 0); 1256789Sahrens 12575094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 12585094Slling "cannot import pool '%s'"), origname); 12595094Slling 1260789Sahrens if (newname != NULL) { 12612082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 12623237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 12632082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12642082Seschrock newname)); 1265789Sahrens thename = (char *)newname; 1266789Sahrens } else { 1267789Sahrens thename = origname; 1268789Sahrens } 1269789Sahrens 12705094Slling if (props) { 12715094Slling uint64_t version; 12725094Slling 12735094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 12745094Slling &version) == 0); 12755094Slling 12767184Stimh if ((props = zpool_valid_proplist(hdl, origname, 12775320Slling props, version, B_TRUE, errbuf)) == NULL) { 12785094Slling return (-1); 12795320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 12805320Slling nvlist_free(props); 12815094Slling return (-1); 12825320Slling } 12835094Slling } 1284789Sahrens 1285789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1286789Sahrens 1287789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 12881544Seschrock &zc.zc_guid) == 0); 1289789Sahrens 12905320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 12915320Slling nvlist_free(props); 12922082Seschrock return (-1); 12935320Slling } 1294789Sahrens 12956643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1296789Sahrens ret = 0; 12974543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1298789Sahrens char desc[1024]; 1299789Sahrens if (newname == NULL) 1300789Sahrens (void) snprintf(desc, sizeof (desc), 1301789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1302789Sahrens thename); 1303789Sahrens else 1304789Sahrens (void) snprintf(desc, sizeof (desc), 1305789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1306789Sahrens origname, thename); 1307789Sahrens 1308789Sahrens switch (errno) { 13091544Seschrock case ENOTSUP: 13101544Seschrock /* 13111544Seschrock * Unsupported version. 13121544Seschrock */ 13132082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 13141544Seschrock break; 13151544Seschrock 13162174Seschrock case EINVAL: 13172174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 13182174Seschrock break; 13192174Seschrock 1320789Sahrens default: 13212082Seschrock (void) zpool_standard_error(hdl, errno, desc); 1322789Sahrens } 1323789Sahrens 1324789Sahrens ret = -1; 1325789Sahrens } else { 1326789Sahrens zpool_handle_t *zhp; 13274543Smarks 1328789Sahrens /* 1329789Sahrens * This should never fail, but play it safe anyway. 1330789Sahrens */ 133110588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 13322142Seschrock ret = -1; 133310588SEric.Taylor@Sun.COM else if (zhp != NULL) 1334789Sahrens zpool_close(zhp); 1335789Sahrens } 1336789Sahrens 13372676Seschrock zcmd_free_nvlists(&zc); 13385320Slling nvlist_free(props); 13395320Slling 1340789Sahrens return (ret); 1341789Sahrens } 1342789Sahrens 1343789Sahrens /* 1344789Sahrens * Scrub the pool. 1345789Sahrens */ 1346789Sahrens int 1347789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1348789Sahrens { 1349789Sahrens zfs_cmd_t zc = { 0 }; 1350789Sahrens char msg[1024]; 13512082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1352789Sahrens 1353789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1354789Sahrens zc.zc_cookie = type; 1355789Sahrens 13564543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1357789Sahrens return (0); 1358789Sahrens 1359789Sahrens (void) snprintf(msg, sizeof (msg), 1360789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1361789Sahrens 13622082Seschrock if (errno == EBUSY) 13632082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 13642082Seschrock else 13652082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1366789Sahrens } 1367789Sahrens 13682468Sek110237 /* 13699816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 13709816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 13712468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 13722468Sek110237 * spare; but FALSE if its an INUSE spare. 13732468Sek110237 */ 13742082Seschrock static nvlist_t * 13759816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 13769816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 13771544Seschrock { 13781544Seschrock uint_t c, children; 13791544Seschrock nvlist_t **child; 13802082Seschrock nvlist_t *ret; 13817326SEric.Schrock@Sun.COM uint64_t is_log; 13829816SGeorge.Wilson@Sun.COM char *srchkey; 13839816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 13849816SGeorge.Wilson@Sun.COM 13859816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 13869816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 13879816SGeorge.Wilson@Sun.COM return (NULL); 13889816SGeorge.Wilson@Sun.COM 13899816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 13909816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 13919816SGeorge.Wilson@Sun.COM 13929816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 13939816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 13949816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 13959816SGeorge.Wilson@Sun.COM 13969816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 13979816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 13989816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 13999816SGeorge.Wilson@Sun.COM &present) == 0) { 14009816SGeorge.Wilson@Sun.COM /* 14019816SGeorge.Wilson@Sun.COM * If the device has never been present since 14029816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 14039816SGeorge.Wilson@Sun.COM * vdev is by GUID. 14049816SGeorge.Wilson@Sun.COM */ 14059816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 14069816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 14079816SGeorge.Wilson@Sun.COM if (theguid == srchval) 14089816SGeorge.Wilson@Sun.COM return (nv); 14099816SGeorge.Wilson@Sun.COM } 14109816SGeorge.Wilson@Sun.COM } 14119816SGeorge.Wilson@Sun.COM break; 14129816SGeorge.Wilson@Sun.COM } 14139816SGeorge.Wilson@Sun.COM 14149816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 14159816SGeorge.Wilson@Sun.COM char *srchval, *val; 14169816SGeorge.Wilson@Sun.COM 14179816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 14189816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 14199816SGeorge.Wilson@Sun.COM break; 14209816SGeorge.Wilson@Sun.COM 14211544Seschrock /* 14229816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 1423*10594SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk and when 1424*10594SGeorge.Wilson@Sun.COM * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 1425*10594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 14261544Seschrock */ 14279816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 14289816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 14299816SGeorge.Wilson@Sun.COM 14309816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 14319816SGeorge.Wilson@Sun.COM &wholedisk); 14329816SGeorge.Wilson@Sun.COM if (wholedisk) { 14339816SGeorge.Wilson@Sun.COM /* 14349816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 14359816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 14369816SGeorge.Wilson@Sun.COM */ 14379816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 14389816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 14399816SGeorge.Wilson@Sun.COM return (nv); 14409816SGeorge.Wilson@Sun.COM break; 14419816SGeorge.Wilson@Sun.COM } 1442*10594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 1443*10594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 1444*10594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 1445*10594SGeorge.Wilson@Sun.COM 1446*10594SGeorge.Wilson@Sun.COM /* 1447*10594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 1448*10594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 1449*10594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 1450*10594SGeorge.Wilson@Sun.COM */ 1451*10594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 1452*10594SGeorge.Wilson@Sun.COM return (NULL); 1453*10594SGeorge.Wilson@Sun.COM 1454*10594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 1455*10594SGeorge.Wilson@Sun.COM free(type); 1456*10594SGeorge.Wilson@Sun.COM break; 1457*10594SGeorge.Wilson@Sun.COM } 1458*10594SGeorge.Wilson@Sun.COM idx = p + 1; 1459*10594SGeorge.Wilson@Sun.COM *p = '\0'; 1460*10594SGeorge.Wilson@Sun.COM 1461*10594SGeorge.Wilson@Sun.COM /* 1462*10594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 1463*10594SGeorge.Wilson@Sun.COM */ 1464*10594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 1465*10594SGeorge.Wilson@Sun.COM free(type); 1466*10594SGeorge.Wilson@Sun.COM break; 1467*10594SGeorge.Wilson@Sun.COM } 1468*10594SGeorge.Wilson@Sun.COM 1469*10594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 1470*10594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 1471*10594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 1472*10594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 1473*10594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 1474*10594SGeorge.Wilson@Sun.COM &id) == 0); 1475*10594SGeorge.Wilson@Sun.COM 1476*10594SGeorge.Wilson@Sun.COM errno = 0; 1477*10594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 1478*10594SGeorge.Wilson@Sun.COM 1479*10594SGeorge.Wilson@Sun.COM free(type); 1480*10594SGeorge.Wilson@Sun.COM if (errno != 0) 1481*10594SGeorge.Wilson@Sun.COM return (NULL); 1482*10594SGeorge.Wilson@Sun.COM 1483*10594SGeorge.Wilson@Sun.COM /* 1484*10594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 1485*10594SGeorge.Wilson@Sun.COM */ 1486*10594SGeorge.Wilson@Sun.COM if (vdev_id == id) 1487*10594SGeorge.Wilson@Sun.COM return (nv); 14889816SGeorge.Wilson@Sun.COM } 14899816SGeorge.Wilson@Sun.COM 14909816SGeorge.Wilson@Sun.COM /* 14919816SGeorge.Wilson@Sun.COM * Common case 14929816SGeorge.Wilson@Sun.COM */ 14939816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 14942082Seschrock return (nv); 14959816SGeorge.Wilson@Sun.COM break; 14969816SGeorge.Wilson@Sun.COM } 14979816SGeorge.Wilson@Sun.COM 14989816SGeorge.Wilson@Sun.COM default: 14999816SGeorge.Wilson@Sun.COM break; 15001544Seschrock } 15011544Seschrock 15021544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 15031544Seschrock &child, &children) != 0) 15042082Seschrock return (NULL); 15051544Seschrock 15067326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 15079816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15087326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15097326SEric.Schrock@Sun.COM /* 15107326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 15117326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 15127326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 15137326SEric.Schrock@Sun.COM * 'log' is non-NULL). 15147326SEric.Schrock@Sun.COM */ 15157326SEric.Schrock@Sun.COM if (log != NULL && 15167326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 15177326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 15187326SEric.Schrock@Sun.COM is_log) { 15197326SEric.Schrock@Sun.COM *log = B_TRUE; 15207326SEric.Schrock@Sun.COM } 15211544Seschrock return (ret); 15227326SEric.Schrock@Sun.COM } 15237326SEric.Schrock@Sun.COM } 15241544Seschrock 15252082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 15262082Seschrock &child, &children) == 0) { 15272082Seschrock for (c = 0; c < children; c++) { 15289816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15297326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15302468Sek110237 *avail_spare = B_TRUE; 15312082Seschrock return (ret); 15322082Seschrock } 15332082Seschrock } 15342082Seschrock } 15352082Seschrock 15365450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 15375450Sbrendan &child, &children) == 0) { 15385450Sbrendan for (c = 0; c < children; c++) { 15399816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15407326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15415450Sbrendan *l2cache = B_TRUE; 15425450Sbrendan return (ret); 15435450Sbrendan } 15445450Sbrendan } 15455450Sbrendan } 15465450Sbrendan 15472082Seschrock return (NULL); 15481544Seschrock } 15491544Seschrock 15509816SGeorge.Wilson@Sun.COM /* 15519816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 15529816SGeorge.Wilson@Sun.COM * associated vdev. 15539816SGeorge.Wilson@Sun.COM */ 15549816SGeorge.Wilson@Sun.COM nvlist_t * 15559816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 15569816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 15579816SGeorge.Wilson@Sun.COM { 15589816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 15599816SGeorge.Wilson@Sun.COM 15609816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15619816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 15629816SGeorge.Wilson@Sun.COM 15639816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 15649816SGeorge.Wilson@Sun.COM &nvroot) == 0); 15659816SGeorge.Wilson@Sun.COM 15669816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 15679816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 15689816SGeorge.Wilson@Sun.COM nvlist_free(search); 15699816SGeorge.Wilson@Sun.COM 15709816SGeorge.Wilson@Sun.COM return (ret); 15719816SGeorge.Wilson@Sun.COM } 15729816SGeorge.Wilson@Sun.COM 1573*10594SGeorge.Wilson@Sun.COM /* 1574*10594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 1575*10594SGeorge.Wilson@Sun.COM */ 1576*10594SGeorge.Wilson@Sun.COM boolean_t 1577*10594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 1578*10594SGeorge.Wilson@Sun.COM { 1579*10594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 1580*10594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 1581*10594SGeorge.Wilson@Sun.COM return (B_TRUE); 1582*10594SGeorge.Wilson@Sun.COM return (B_FALSE); 1583*10594SGeorge.Wilson@Sun.COM } 1584*10594SGeorge.Wilson@Sun.COM 15852082Seschrock nvlist_t * 15865450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 15877326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 15881544Seschrock { 15891544Seschrock char buf[MAXPATHLEN]; 15901544Seschrock char *end; 15919816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 15921544Seschrock uint64_t guid; 15931544Seschrock 15949816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15959816SGeorge.Wilson@Sun.COM 15961613Seschrock guid = strtoull(path, &end, 10); 15971544Seschrock if (guid != 0 && *end == '\0') { 15989816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 1599*10594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 1600*10594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 16011544Seschrock } else if (path[0] != '/') { 16021544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 16039816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 16041544Seschrock } else { 16059816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 16061544Seschrock } 16071544Seschrock 16081544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 16091544Seschrock &nvroot) == 0); 16101544Seschrock 16112468Sek110237 *avail_spare = B_FALSE; 16125450Sbrendan *l2cache = B_FALSE; 16137326SEric.Schrock@Sun.COM if (log != NULL) 16147326SEric.Schrock@Sun.COM *log = B_FALSE; 16159816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 16169816SGeorge.Wilson@Sun.COM nvlist_free(search); 16179816SGeorge.Wilson@Sun.COM 16189816SGeorge.Wilson@Sun.COM return (ret); 16192468Sek110237 } 16202468Sek110237 16217656SSherry.Moore@Sun.COM static int 16227656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 16237656SSherry.Moore@Sun.COM { 16247656SSherry.Moore@Sun.COM uint64_t ival; 16257656SSherry.Moore@Sun.COM 16267656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 16277656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 16287656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 16297656SSherry.Moore@Sun.COM return (0); 16307656SSherry.Moore@Sun.COM 16317656SSherry.Moore@Sun.COM return (1); 16327656SSherry.Moore@Sun.COM } 16337656SSherry.Moore@Sun.COM 16347656SSherry.Moore@Sun.COM /* 16359790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 16367656SSherry.Moore@Sun.COM */ 16379160SSherry.Moore@Sun.COM static int 16389790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 16399160SSherry.Moore@Sun.COM size_t *bytes_written) 16407656SSherry.Moore@Sun.COM { 16419160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 16429160SSherry.Moore@Sun.COM char *tmppath; 16439160SSherry.Moore@Sun.COM const char *format; 16449160SSherry.Moore@Sun.COM 16459160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 16469160SSherry.Moore@Sun.COM &tmppath) != 0) 16479160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 16489160SSherry.Moore@Sun.COM 16499160SSherry.Moore@Sun.COM pos = *bytes_written; 16509160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 16519160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 16529160SSherry.Moore@Sun.COM 16539160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 16549160SSherry.Moore@Sun.COM *bytes_written += rsz; 16559160SSherry.Moore@Sun.COM 16569160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 16579160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 16589160SSherry.Moore@Sun.COM if (bytes_left != 0) { 16599160SSherry.Moore@Sun.COM physpath[pos] = 0; 16609160SSherry.Moore@Sun.COM } 16619160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 16629160SSherry.Moore@Sun.COM } 16639160SSherry.Moore@Sun.COM return (0); 16649160SSherry.Moore@Sun.COM } 16659160SSherry.Moore@Sun.COM 16669790SLin.Ling@Sun.COM static int 16679790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 16689790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 16699790SLin.Ling@Sun.COM { 16709790SLin.Ling@Sun.COM char *type; 16719790SLin.Ling@Sun.COM int ret; 16729790SLin.Ling@Sun.COM 16739790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 16749790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16759790SLin.Ling@Sun.COM 16769790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 16779790SLin.Ling@Sun.COM /* 16789790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 16799790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 16809790SLin.Ling@Sun.COM * spare device. 16819790SLin.Ling@Sun.COM */ 16829790SLin.Ling@Sun.COM if (is_spare) { 16839790SLin.Ling@Sun.COM uint64_t spare = 0; 16849790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 16859790SLin.Ling@Sun.COM &spare); 16869790SLin.Ling@Sun.COM if (!spare) 16879790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16889790SLin.Ling@Sun.COM } 16899790SLin.Ling@Sun.COM 16909790SLin.Ling@Sun.COM if (vdev_online(nv)) { 16919790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 16929790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 16939790SLin.Ling@Sun.COM return (ret); 16949790SLin.Ling@Sun.COM } 16959790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 16969790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 16979790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 16989790SLin.Ling@Sun.COM nvlist_t **child; 16999790SLin.Ling@Sun.COM uint_t count; 17009790SLin.Ling@Sun.COM int i, ret; 17019790SLin.Ling@Sun.COM 17029790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 17039790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 17049790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 17059790SLin.Ling@Sun.COM 17069790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 17079790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 17089790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 17099790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 17109790SLin.Ling@Sun.COM return (ret); 17119790SLin.Ling@Sun.COM } 17129790SLin.Ling@Sun.COM } 17139790SLin.Ling@Sun.COM 17149790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 17159790SLin.Ling@Sun.COM } 17169790SLin.Ling@Sun.COM 17179160SSherry.Moore@Sun.COM /* 17189160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 17199160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 17209160SSherry.Moore@Sun.COM */ 17219160SSherry.Moore@Sun.COM static int 17229160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 17239160SSherry.Moore@Sun.COM { 17249160SSherry.Moore@Sun.COM size_t rsz; 17257656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 17267656SSherry.Moore@Sun.COM nvlist_t **child; 17277656SSherry.Moore@Sun.COM uint_t count; 17289160SSherry.Moore@Sun.COM char *type; 17299160SSherry.Moore@Sun.COM 17309160SSherry.Moore@Sun.COM rsz = 0; 17319160SSherry.Moore@Sun.COM 17329160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 17339160SSherry.Moore@Sun.COM &vdev_root) != 0) 17349160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 17359160SSherry.Moore@Sun.COM 17369160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 17379160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 17389160SSherry.Moore@Sun.COM &child, &count) != 0) 17399160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 17407656SSherry.Moore@Sun.COM 17417656SSherry.Moore@Sun.COM /* 17429160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 17439160SSherry.Moore@Sun.COM * a single top-level vdev. 17447656SSherry.Moore@Sun.COM */ 17459160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 17469160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 17479160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 17489160SSherry.Moore@Sun.COM 17499790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 17509790SLin.Ling@Sun.COM B_FALSE); 17517656SSherry.Moore@Sun.COM 17529160SSherry.Moore@Sun.COM /* No online devices */ 17539160SSherry.Moore@Sun.COM if (rsz == 0) 17549160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 17559160SSherry.Moore@Sun.COM 17567656SSherry.Moore@Sun.COM return (0); 17577656SSherry.Moore@Sun.COM } 17587656SSherry.Moore@Sun.COM 17592468Sek110237 /* 17609160SSherry.Moore@Sun.COM * Get phys_path for a root pool 17619160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 17629160SSherry.Moore@Sun.COM */ 17639160SSherry.Moore@Sun.COM int 17649160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 17659160SSherry.Moore@Sun.COM { 17669160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 17679160SSherry.Moore@Sun.COM phypath_size)); 17689160SSherry.Moore@Sun.COM } 17699160SSherry.Moore@Sun.COM 17709160SSherry.Moore@Sun.COM /* 17715450Sbrendan * Returns TRUE if the given guid corresponds to the given type. 17725450Sbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 17735450Sbrendan * devices. 17742468Sek110237 */ 17752468Sek110237 static boolean_t 17765450Sbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 17772468Sek110237 { 17785450Sbrendan uint64_t target_guid; 17792468Sek110237 nvlist_t *nvroot; 17805450Sbrendan nvlist_t **list; 17815450Sbrendan uint_t count; 17822468Sek110237 int i; 17832468Sek110237 17842468Sek110237 verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 17852468Sek110237 &nvroot) == 0); 17865450Sbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 17875450Sbrendan for (i = 0; i < count; i++) { 17885450Sbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 17895450Sbrendan &target_guid) == 0); 17905450Sbrendan if (guid == target_guid) 17912468Sek110237 return (B_TRUE); 17922468Sek110237 } 17932468Sek110237 } 17942468Sek110237 17952468Sek110237 return (B_FALSE); 17961544Seschrock } 17971544Seschrock 1798789Sahrens /* 17999816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 18009816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 18019816SGeorge.Wilson@Sun.COM */ 18029816SGeorge.Wilson@Sun.COM static int 18039816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 18049816SGeorge.Wilson@Sun.COM { 18059816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 18069816SGeorge.Wilson@Sun.COM char errbuf[1024]; 18079816SGeorge.Wilson@Sun.COM int fd, error; 18089816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 18099816SGeorge.Wilson@Sun.COM 18109816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 18119816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 18129816SGeorge.Wilson@Sun.COM return (-1); 18139816SGeorge.Wilson@Sun.COM 18149816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 18159816SGeorge.Wilson@Sun.COM 18169816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 18179816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 18189816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 18199816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 18209816SGeorge.Wilson@Sun.COM } 18219816SGeorge.Wilson@Sun.COM 18229816SGeorge.Wilson@Sun.COM /* 18239816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 18249816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 18259816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 18269816SGeorge.Wilson@Sun.COM */ 18279816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 18289816SGeorge.Wilson@Sun.COM (void) close(fd); 18299816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 18309816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 18319816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 18329816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 18339816SGeorge.Wilson@Sun.COM } 18349816SGeorge.Wilson@Sun.COM return (0); 18359816SGeorge.Wilson@Sun.COM } 18369816SGeorge.Wilson@Sun.COM 18379816SGeorge.Wilson@Sun.COM /* 18384451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 18394451Seschrock * ZFS_ONLINE_* flags. 1840789Sahrens */ 1841789Sahrens int 18424451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 18434451Seschrock vdev_state_t *newstate) 1844789Sahrens { 1845789Sahrens zfs_cmd_t zc = { 0 }; 1846789Sahrens char msg[1024]; 18472082Seschrock nvlist_t *tgt; 18489816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 18492082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1850789Sahrens 18519816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 18529816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 18539816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 18549816SGeorge.Wilson@Sun.COM } else { 18559816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 18569816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 18579816SGeorge.Wilson@Sun.COM } 1858789Sahrens 18591544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 18607326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 18619816SGeorge.Wilson@Sun.COM &islog)) == NULL) 18622082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1863789Sahrens 18642468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 18652468Sek110237 18665450Sbrendan if (avail_spare || 18675450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 18682082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 18692082Seschrock 18709816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 18719816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 18729816SGeorge.Wilson@Sun.COM char *pathname = NULL; 18739816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 18749816SGeorge.Wilson@Sun.COM 18759816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 18769816SGeorge.Wilson@Sun.COM &wholedisk); 18779816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 18789816SGeorge.Wilson@Sun.COM &pathname) == 0); 18799816SGeorge.Wilson@Sun.COM 18809816SGeorge.Wilson@Sun.COM /* 18819816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 18829816SGeorge.Wilson@Sun.COM */ 18839816SGeorge.Wilson@Sun.COM if (l2cache) { 18849816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18859816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 18869816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 18879816SGeorge.Wilson@Sun.COM } 18889816SGeorge.Wilson@Sun.COM 18899816SGeorge.Wilson@Sun.COM if (wholedisk) { 18909816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 18919816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 18929816SGeorge.Wilson@Sun.COM } 18939816SGeorge.Wilson@Sun.COM } 18949816SGeorge.Wilson@Sun.COM 18954451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 18964451Seschrock zc.zc_obj = flags; 18974451Seschrock 18984543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 18994451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19004451Seschrock 19014451Seschrock *newstate = zc.zc_cookie; 19024451Seschrock return (0); 1903789Sahrens } 1904789Sahrens 1905789Sahrens /* 1906789Sahrens * Take the specified vdev offline 1907789Sahrens */ 1908789Sahrens int 19094451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1910789Sahrens { 1911789Sahrens zfs_cmd_t zc = { 0 }; 1912789Sahrens char msg[1024]; 19132082Seschrock nvlist_t *tgt; 19145450Sbrendan boolean_t avail_spare, l2cache; 19152082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1916789Sahrens 19171544Seschrock (void) snprintf(msg, sizeof (msg), 19181544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 19191544Seschrock 1920789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19217326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 19227326SEric.Schrock@Sun.COM NULL)) == NULL) 19232082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 19242082Seschrock 19252468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 19262468Sek110237 19275450Sbrendan if (avail_spare || 19285450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 19292082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 19302082Seschrock 19314451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 19324451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 19331485Slling 19344543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1935789Sahrens return (0); 1936789Sahrens 1937789Sahrens switch (errno) { 19382082Seschrock case EBUSY: 1939789Sahrens 1940789Sahrens /* 1941789Sahrens * There are no other replicas of this device. 1942789Sahrens */ 19432082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 19442082Seschrock 19459701SGeorge.Wilson@Sun.COM case EEXIST: 19469701SGeorge.Wilson@Sun.COM /* 19479701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 19489701SGeorge.Wilson@Sun.COM */ 19499701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 19509701SGeorge.Wilson@Sun.COM 19512082Seschrock default: 19522082Seschrock return (zpool_standard_error(hdl, errno, msg)); 19532082Seschrock } 19542082Seschrock } 1955789Sahrens 19562082Seschrock /* 19574451Seschrock * Mark the given vdev faulted. 19584451Seschrock */ 19594451Seschrock int 19604451Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 19614451Seschrock { 19624451Seschrock zfs_cmd_t zc = { 0 }; 19634451Seschrock char msg[1024]; 19644451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19654451Seschrock 19664451Seschrock (void) snprintf(msg, sizeof (msg), 19674451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 19684451Seschrock 19694451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19704451Seschrock zc.zc_guid = guid; 19714451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 19724451Seschrock 19734451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19744451Seschrock return (0); 19754451Seschrock 19764451Seschrock switch (errno) { 19774451Seschrock case EBUSY: 19784451Seschrock 19794451Seschrock /* 19804451Seschrock * There are no other replicas of this device. 19814451Seschrock */ 19824451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 19834451Seschrock 19844451Seschrock default: 19854451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19864451Seschrock } 19874451Seschrock 19884451Seschrock } 19894451Seschrock 19904451Seschrock /* 19914451Seschrock * Mark the given vdev degraded. 19924451Seschrock */ 19934451Seschrock int 19944451Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 19954451Seschrock { 19964451Seschrock zfs_cmd_t zc = { 0 }; 19974451Seschrock char msg[1024]; 19984451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19994451Seschrock 20004451Seschrock (void) snprintf(msg, sizeof (msg), 20014451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 20024451Seschrock 20034451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20044451Seschrock zc.zc_guid = guid; 20054451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 20064451Seschrock 20074451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 20084451Seschrock return (0); 20094451Seschrock 20104451Seschrock return (zpool_standard_error(hdl, errno, msg)); 20114451Seschrock } 20124451Seschrock 20134451Seschrock /* 20142082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 20152082Seschrock * a hot spare. 20162082Seschrock */ 20172082Seschrock static boolean_t 20182082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 20192082Seschrock { 20202082Seschrock nvlist_t **child; 20212082Seschrock uint_t c, children; 20222082Seschrock char *type; 20232082Seschrock 20242082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 20252082Seschrock &children) == 0) { 20262082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 20272082Seschrock &type) == 0); 20282082Seschrock 20292082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 20302082Seschrock children == 2 && child[which] == tgt) 20312082Seschrock return (B_TRUE); 20322082Seschrock 20332082Seschrock for (c = 0; c < children; c++) 20342082Seschrock if (is_replacing_spare(child[c], tgt, which)) 20352082Seschrock return (B_TRUE); 2036789Sahrens } 20372082Seschrock 20382082Seschrock return (B_FALSE); 2039789Sahrens } 2040789Sahrens 2041789Sahrens /* 2042789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 20434527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2044789Sahrens */ 2045789Sahrens int 2046789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2047789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2048789Sahrens { 2049789Sahrens zfs_cmd_t zc = { 0 }; 2050789Sahrens char msg[1024]; 2051789Sahrens int ret; 20522082Seschrock nvlist_t *tgt; 20537326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 20547326SEric.Schrock@Sun.COM uint64_t val; 20557041Seschrock char *path, *newname; 20562082Seschrock nvlist_t **child; 20572082Seschrock uint_t children; 20582082Seschrock nvlist_t *config_root; 20592082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 20607965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2061789Sahrens 20621544Seschrock if (replacing) 20631544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20641544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 20651544Seschrock else 20661544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20671544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 20681544Seschrock 20697965SGeorge.Wilson@Sun.COM /* 20707965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 20717965SGeorge.Wilson@Sun.COM * EFI labeled device. 20727965SGeorge.Wilson@Sun.COM */ 20737965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 20747965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20757965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 20767965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 20777965SGeorge.Wilson@Sun.COM } 20787965SGeorge.Wilson@Sun.COM 2079789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20807326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 20817326SEric.Schrock@Sun.COM &islog)) == 0) 20822082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 20832082Seschrock 20842468Sek110237 if (avail_spare) 20852082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20862082Seschrock 20875450Sbrendan if (l2cache) 20885450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 20895450Sbrendan 20902082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20912082Seschrock zc.zc_cookie = replacing; 20922082Seschrock 20932082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 20942082Seschrock &child, &children) != 0 || children != 1) { 20952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20962082Seschrock "new device must be a single disk")); 20972082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 20981544Seschrock } 20992082Seschrock 21002082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 21012082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 21022082Seschrock 2103*10594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 21047041Seschrock return (-1); 21057041Seschrock 21062082Seschrock /* 21072082Seschrock * If the target is a hot spare that has been swapped in, we can only 21082082Seschrock * replace it with another hot spare. 21092082Seschrock */ 21102082Seschrock if (replacing && 21112082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 21127326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 21137326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 21147326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 21152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21162082Seschrock "can only be replaced by another hot spare")); 21177041Seschrock free(newname); 21182082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 21192082Seschrock } 21202082Seschrock 21212082Seschrock /* 21222082Seschrock * If we are attempting to replace a spare, it canot be applied to an 21232082Seschrock * already spared device. 21242082Seschrock */ 21252082Seschrock if (replacing && 21262082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 21277326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 21287326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 21297326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 21302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21312082Seschrock "device has already been replaced with a spare")); 21327041Seschrock free(newname); 21332082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 21342082Seschrock } 2135789Sahrens 21367041Seschrock free(newname); 21377041Seschrock 21385094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 21392082Seschrock return (-1); 2140789Sahrens 21414543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2142789Sahrens 21432676Seschrock zcmd_free_nvlists(&zc); 2144789Sahrens 21457965SGeorge.Wilson@Sun.COM if (ret == 0) { 21467965SGeorge.Wilson@Sun.COM if (rootpool) { 21477965SGeorge.Wilson@Sun.COM /* 21487965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 21497965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 21507965SGeorge.Wilson@Sun.COM * newly attached disk. 21517965SGeorge.Wilson@Sun.COM */ 21527965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 21537965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 21547965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 21559790SLin.Ling@Sun.COM 21569790SLin.Ling@Sun.COM /* 21579790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 21589790SLin.Ling@Sun.COM * booting up a half-baked vdev. 21599790SLin.Ling@Sun.COM */ 21609790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 21619790SLin.Ling@Sun.COM "sure to wait until resilver is done " 21629790SLin.Ling@Sun.COM "before rebooting.\n")); 21637965SGeorge.Wilson@Sun.COM } 2164789Sahrens return (0); 21657965SGeorge.Wilson@Sun.COM } 2166789Sahrens 2167789Sahrens switch (errno) { 21681544Seschrock case ENOTSUP: 2169789Sahrens /* 2170789Sahrens * Can't attach to or replace this type of vdev. 2171789Sahrens */ 21724527Sperrin if (replacing) { 21737326SEric.Schrock@Sun.COM if (islog) 21744527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21754527Sperrin "cannot replace a log with a spare")); 21764527Sperrin else 21774527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21784527Sperrin "cannot replace a replacing device")); 21794527Sperrin } else { 21802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21812082Seschrock "can only attach to mirrors and top-level " 21822082Seschrock "disks")); 21834527Sperrin } 21842082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2185789Sahrens break; 2186789Sahrens 21871544Seschrock case EINVAL: 2188789Sahrens /* 2189789Sahrens * The new device must be a single disk. 2190789Sahrens */ 21912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21922082Seschrock "new device must be a single disk")); 21932082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2194789Sahrens break; 2195789Sahrens 21961544Seschrock case EBUSY: 21972082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 21982082Seschrock new_disk); 21992082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2200789Sahrens break; 2201789Sahrens 22021544Seschrock case EOVERFLOW: 2203789Sahrens /* 2204789Sahrens * The new device is too small. 2205789Sahrens */ 22062082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22072082Seschrock "device is too small")); 22082082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2209789Sahrens break; 2210789Sahrens 22111544Seschrock case EDOM: 2212789Sahrens /* 2213789Sahrens * The new device has a different alignment requirement. 2214789Sahrens */ 22152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22162082Seschrock "devices have different sector alignment")); 22172082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2218789Sahrens break; 2219789Sahrens 22201544Seschrock case ENAMETOOLONG: 2221789Sahrens /* 2222789Sahrens * The resulting top-level vdev spec won't fit in the label. 2223789Sahrens */ 22242082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2225789Sahrens break; 2226789Sahrens 22271544Seschrock default: 22282082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2229789Sahrens } 2230789Sahrens 22312082Seschrock return (-1); 2232789Sahrens } 2233789Sahrens 2234789Sahrens /* 2235789Sahrens * Detach the specified device. 2236789Sahrens */ 2237789Sahrens int 2238789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2239789Sahrens { 2240789Sahrens zfs_cmd_t zc = { 0 }; 2241789Sahrens char msg[1024]; 22422082Seschrock nvlist_t *tgt; 22435450Sbrendan boolean_t avail_spare, l2cache; 22442082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2245789Sahrens 22461544Seschrock (void) snprintf(msg, sizeof (msg), 22471544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 22481544Seschrock 2249789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22507326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22517326SEric.Schrock@Sun.COM NULL)) == 0) 22522082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2253789Sahrens 22542468Sek110237 if (avail_spare) 22552082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22562082Seschrock 22575450Sbrendan if (l2cache) 22585450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 22595450Sbrendan 22602082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22612082Seschrock 22624543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2263789Sahrens return (0); 2264789Sahrens 2265789Sahrens switch (errno) { 2266789Sahrens 22671544Seschrock case ENOTSUP: 2268789Sahrens /* 2269789Sahrens * Can't detach from this type of vdev. 2270789Sahrens */ 22712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 22722082Seschrock "applicable to mirror and replacing vdevs")); 22732082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2274789Sahrens break; 2275789Sahrens 22761544Seschrock case EBUSY: 2277789Sahrens /* 2278789Sahrens * There are no other replicas of this device. 2279789Sahrens */ 22802082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2281789Sahrens break; 2282789Sahrens 22831544Seschrock default: 22842082Seschrock (void) zpool_standard_error(hdl, errno, msg); 22851544Seschrock } 22861544Seschrock 22872082Seschrock return (-1); 22882082Seschrock } 22892082Seschrock 22902082Seschrock /* 22915450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 22925450Sbrendan * and level 2 cache devices. 22932082Seschrock */ 22942082Seschrock int 22952082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 22962082Seschrock { 22972082Seschrock zfs_cmd_t zc = { 0 }; 22982082Seschrock char msg[1024]; 22992082Seschrock nvlist_t *tgt; 2300*10594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 23012082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2302*10594SGeorge.Wilson@Sun.COM uint64_t version; 23032082Seschrock 23042082Seschrock (void) snprintf(msg, sizeof (msg), 23052082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 23062082Seschrock 23072082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23087326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2309*10594SGeorge.Wilson@Sun.COM &islog)) == 0) 23102082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2311*10594SGeorge.Wilson@Sun.COM /* 2312*10594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 2313*10594SGeorge.Wilson@Sun.COM */ 2314*10594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 23152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2316*10594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 2317*10594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 23182082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23192082Seschrock } 23202082Seschrock 2321*10594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 2322*10594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 2323*10594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2324*10594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 2325*10594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 2326*10594SGeorge.Wilson@Sun.COM } 2327*10594SGeorge.Wilson@Sun.COM 23282082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 23292082Seschrock 23304543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 23312082Seschrock return (0); 23322082Seschrock 23332082Seschrock return (zpool_standard_error(hdl, errno, msg)); 23341544Seschrock } 23351544Seschrock 23361544Seschrock /* 23371544Seschrock * Clear the errors for the pool, or the particular device if specified. 23381544Seschrock */ 23391544Seschrock int 23401544Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 23411544Seschrock { 23421544Seschrock zfs_cmd_t zc = { 0 }; 23431544Seschrock char msg[1024]; 23442082Seschrock nvlist_t *tgt; 23455450Sbrendan boolean_t avail_spare, l2cache; 23462082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23471544Seschrock 23481544Seschrock if (path) 23491544Seschrock (void) snprintf(msg, sizeof (msg), 23501544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 23512676Seschrock path); 23521544Seschrock else 23531544Seschrock (void) snprintf(msg, sizeof (msg), 23541544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 23551544Seschrock zhp->zpool_name); 23561544Seschrock 23571544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23582082Seschrock if (path) { 23595450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 23607326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 23612082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23622082Seschrock 23635450Sbrendan /* 23645450Sbrendan * Don't allow error clearing for hot spares. Do allow 23655450Sbrendan * error clearing for l2cache devices. 23665450Sbrendan */ 23672468Sek110237 if (avail_spare) 23682082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 23692082Seschrock 23702082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 23712082Seschrock &zc.zc_guid) == 0); 23721544Seschrock } 23731544Seschrock 23744543Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 23751544Seschrock return (0); 23761544Seschrock 23772082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2378789Sahrens } 2379789Sahrens 23803126Sahl /* 23814451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 23824451Seschrock */ 23834451Seschrock int 23844451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 23854451Seschrock { 23864451Seschrock zfs_cmd_t zc = { 0 }; 23874451Seschrock char msg[1024]; 23884451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23894451Seschrock 23904451Seschrock (void) snprintf(msg, sizeof (msg), 23914451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 23924451Seschrock guid); 23934451Seschrock 23944451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23954451Seschrock zc.zc_guid = guid; 23964451Seschrock 23974451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 23984451Seschrock return (0); 23994451Seschrock 24004451Seschrock return (zpool_standard_error(hdl, errno, msg)); 24014451Seschrock } 24024451Seschrock 24034451Seschrock /* 24041354Seschrock * Convert from a devid string to a path. 24051354Seschrock */ 24061354Seschrock static char * 24071354Seschrock devid_to_path(char *devid_str) 24081354Seschrock { 24091354Seschrock ddi_devid_t devid; 24101354Seschrock char *minor; 24111354Seschrock char *path; 24121354Seschrock devid_nmlist_t *list = NULL; 24131354Seschrock int ret; 24141354Seschrock 24151354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 24161354Seschrock return (NULL); 24171354Seschrock 24181354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 24191354Seschrock 24201354Seschrock devid_str_free(minor); 24211354Seschrock devid_free(devid); 24221354Seschrock 24231354Seschrock if (ret != 0) 24241354Seschrock return (NULL); 24251354Seschrock 24262082Seschrock if ((path = strdup(list[0].devname)) == NULL) 24272082Seschrock return (NULL); 24282082Seschrock 24291354Seschrock devid_free_nmlist(list); 24301354Seschrock 24311354Seschrock return (path); 24321354Seschrock } 24331354Seschrock 24341354Seschrock /* 24351354Seschrock * Convert from a path to a devid string. 24361354Seschrock */ 24371354Seschrock static char * 24381354Seschrock path_to_devid(const char *path) 24391354Seschrock { 24401354Seschrock int fd; 24411354Seschrock ddi_devid_t devid; 24421354Seschrock char *minor, *ret; 24431354Seschrock 24441354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 24451354Seschrock return (NULL); 24461354Seschrock 24471354Seschrock minor = NULL; 24481354Seschrock ret = NULL; 24491354Seschrock if (devid_get(fd, &devid) == 0) { 24501354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 24511354Seschrock ret = devid_str_encode(devid, minor); 24521354Seschrock if (minor != NULL) 24531354Seschrock devid_str_free(minor); 24541354Seschrock devid_free(devid); 24551354Seschrock } 24561354Seschrock (void) close(fd); 24571354Seschrock 24581354Seschrock return (ret); 24591354Seschrock } 24601354Seschrock 24611354Seschrock /* 24621354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 24631354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 24641354Seschrock * type 'zpool status', and we'll display the correct information anyway. 24651354Seschrock */ 24661354Seschrock static void 24671354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 24681354Seschrock { 24691354Seschrock zfs_cmd_t zc = { 0 }; 24701354Seschrock 24711354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24722676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 24731354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 24741544Seschrock &zc.zc_guid) == 0); 24751354Seschrock 24762082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 24771354Seschrock } 24781354Seschrock 24791354Seschrock /* 24801354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 24811354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 24821354Seschrock * We also check if this is a whole disk, in which case we strip off the 24831354Seschrock * trailing 's0' slice name. 24841354Seschrock * 24851354Seschrock * This routine is also responsible for identifying when disks have been 24861354Seschrock * reconfigured in a new location. The kernel will have opened the device by 24871354Seschrock * devid, but the path will still refer to the old location. To catch this, we 24881354Seschrock * first do a path -> devid translation (which is fast for the common case). If 24891354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 24901354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 24911354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 24921354Seschrock * of these checks. 24931354Seschrock */ 24941354Seschrock char * 2495*10594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 2496*10594SGeorge.Wilson@Sun.COM boolean_t verbose) 24971354Seschrock { 24981354Seschrock char *path, *devid; 24991544Seschrock uint64_t value; 25001544Seschrock char buf[64]; 25014451Seschrock vdev_stat_t *vs; 25024451Seschrock uint_t vsc; 25031354Seschrock 25041544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 25051544Seschrock &value) == 0) { 25061544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 25071544Seschrock &value) == 0); 25082856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 25092856Snd150628 (u_longlong_t)value); 25101544Seschrock path = buf; 25111544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 25121354Seschrock 25134451Seschrock /* 25144451Seschrock * If the device is dead (faulted, offline, etc) then don't 25154451Seschrock * bother opening it. Otherwise we may be forcing the user to 25164451Seschrock * open a misbehaving device, which can have undesirable 25174451Seschrock * effects. 25184451Seschrock */ 25194451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 25204451Seschrock (uint64_t **)&vs, &vsc) != 0 || 25214451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 25224451Seschrock zhp != NULL && 25231354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 25241354Seschrock /* 25251354Seschrock * Determine if the current path is correct. 25261354Seschrock */ 25271354Seschrock char *newdevid = path_to_devid(path); 25281354Seschrock 25291354Seschrock if (newdevid == NULL || 25301354Seschrock strcmp(devid, newdevid) != 0) { 25311354Seschrock char *newpath; 25321354Seschrock 25331354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 25341354Seschrock /* 25351354Seschrock * Update the path appropriately. 25361354Seschrock */ 25371354Seschrock set_path(zhp, nv, newpath); 25382082Seschrock if (nvlist_add_string(nv, 25392082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 25402082Seschrock verify(nvlist_lookup_string(nv, 25412082Seschrock ZPOOL_CONFIG_PATH, 25422082Seschrock &path) == 0); 25431354Seschrock free(newpath); 25441354Seschrock } 25451354Seschrock } 25461354Seschrock 25472082Seschrock if (newdevid) 25482082Seschrock devid_str_free(newdevid); 25491354Seschrock } 25501354Seschrock 25511354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 25521354Seschrock path += 9; 25531354Seschrock 25541354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 25551544Seschrock &value) == 0 && value) { 25562082Seschrock char *tmp = zfs_strdup(hdl, path); 25572082Seschrock if (tmp == NULL) 25582082Seschrock return (NULL); 25591354Seschrock tmp[strlen(path) - 2] = '\0'; 25601354Seschrock return (tmp); 25611354Seschrock } 25621354Seschrock } else { 25631354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 25642082Seschrock 25652082Seschrock /* 25662082Seschrock * If it's a raidz device, we need to stick in the parity level. 25672082Seschrock */ 25682082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 25692082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 25702082Seschrock &value) == 0); 25712082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 25722856Snd150628 (u_longlong_t)value); 25732082Seschrock path = buf; 25742082Seschrock } 2575*10594SGeorge.Wilson@Sun.COM 2576*10594SGeorge.Wilson@Sun.COM /* 2577*10594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 2578*10594SGeorge.Wilson@Sun.COM * naming convention. 2579*10594SGeorge.Wilson@Sun.COM */ 2580*10594SGeorge.Wilson@Sun.COM if (verbose) { 2581*10594SGeorge.Wilson@Sun.COM uint64_t id; 2582*10594SGeorge.Wilson@Sun.COM 2583*10594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 2584*10594SGeorge.Wilson@Sun.COM &id) == 0); 2585*10594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 2586*10594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 2587*10594SGeorge.Wilson@Sun.COM path = buf; 2588*10594SGeorge.Wilson@Sun.COM } 25891354Seschrock } 25901354Seschrock 25912082Seschrock return (zfs_strdup(hdl, path)); 25921354Seschrock } 25931544Seschrock 25941544Seschrock static int 25951544Seschrock zbookmark_compare(const void *a, const void *b) 25961544Seschrock { 25971544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 25981544Seschrock } 25991544Seschrock 26001544Seschrock /* 26011544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 26021544Seschrock * caller. 26031544Seschrock */ 26041544Seschrock int 26053444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 26061544Seschrock { 26071544Seschrock zfs_cmd_t zc = { 0 }; 26081544Seschrock uint64_t count; 26092676Seschrock zbookmark_t *zb = NULL; 26103444Sek110237 int i; 26111544Seschrock 26121544Seschrock /* 26131544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 26141544Seschrock * has increased, allocate more space and continue until we get the 26151544Seschrock * entire list. 26161544Seschrock */ 26171544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 26181544Seschrock &count) == 0); 26194820Sek110237 if (count == 0) 26204820Sek110237 return (0); 26212676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 26222856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 26232082Seschrock return (-1); 26242676Seschrock zc.zc_nvlist_dst_size = count; 26251544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 26261544Seschrock for (;;) { 26272082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 26282082Seschrock &zc) != 0) { 26292676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 26301544Seschrock if (errno == ENOMEM) { 26313823Svb160487 count = zc.zc_nvlist_dst_size; 26322676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 26333823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 26343823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 26352082Seschrock return (-1); 26361544Seschrock } else { 26371544Seschrock return (-1); 26381544Seschrock } 26391544Seschrock } else { 26401544Seschrock break; 26411544Seschrock } 26421544Seschrock } 26431544Seschrock 26441544Seschrock /* 26451544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 26461544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 26472676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 26481544Seschrock * _not_ copied as part of the process. So we point the start of our 26491544Seschrock * array appropriate and decrement the total number of elements. 26501544Seschrock */ 26512676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 26522676Seschrock zc.zc_nvlist_dst_size; 26532676Seschrock count -= zc.zc_nvlist_dst_size; 26541544Seschrock 26551544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 26561544Seschrock 26573444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 26581544Seschrock 26591544Seschrock /* 26603444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 26611544Seschrock */ 26621544Seschrock for (i = 0; i < count; i++) { 26631544Seschrock nvlist_t *nv; 26641544Seschrock 26653700Sek110237 /* ignoring zb_blkid and zb_level for now */ 26663700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 26673700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 26681544Seschrock continue; 26691544Seschrock 26703444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 26713444Sek110237 goto nomem; 26723444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 26733444Sek110237 zb[i].zb_objset) != 0) { 26743444Sek110237 nvlist_free(nv); 26752082Seschrock goto nomem; 26763444Sek110237 } 26773444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 26783444Sek110237 zb[i].zb_object) != 0) { 26793444Sek110237 nvlist_free(nv); 26803444Sek110237 goto nomem; 26811544Seschrock } 26823444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 26833444Sek110237 nvlist_free(nv); 26843444Sek110237 goto nomem; 26853444Sek110237 } 26863444Sek110237 nvlist_free(nv); 26871544Seschrock } 26881544Seschrock 26893265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 26901544Seschrock return (0); 26912082Seschrock 26922082Seschrock nomem: 26932676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 26942082Seschrock return (no_memory(zhp->zpool_hdl)); 26951544Seschrock } 26961760Seschrock 26971760Seschrock /* 26981760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 26991760Seschrock */ 27001760Seschrock int 27015094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 27021760Seschrock { 27031760Seschrock zfs_cmd_t zc = { 0 }; 27042082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 27051760Seschrock 27061760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 27075094Slling zc.zc_cookie = new_version; 27085094Slling 27094543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 27103237Slling return (zpool_standard_error_fmt(hdl, errno, 27112082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 27122082Seschrock zhp->zpool_name)); 27131760Seschrock return (0); 27141760Seschrock } 27152926Sek110237 27164988Sek110237 void 27174988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 27184988Sek110237 char *history_str) 27194988Sek110237 { 27204988Sek110237 int i; 27214988Sek110237 27224988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 27234988Sek110237 for (i = 1; i < argc; i++) { 27244988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 27254988Sek110237 HIS_MAX_RECORD_LEN) 27264988Sek110237 break; 27274988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 27284988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 27294988Sek110237 } 27304988Sek110237 } 27314988Sek110237 27322926Sek110237 /* 27334988Sek110237 * Stage command history for logging. 27342926Sek110237 */ 27354988Sek110237 int 27364988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 27372926Sek110237 { 27384988Sek110237 if (history_str == NULL) 27394988Sek110237 return (EINVAL); 27404988Sek110237 27414988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 27424988Sek110237 return (EINVAL); 27432926Sek110237 27444715Sek110237 if (hdl->libzfs_log_str != NULL) 27454543Smarks free(hdl->libzfs_log_str); 27462926Sek110237 27474988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 27484988Sek110237 return (no_memory(hdl)); 27494543Smarks 27504988Sek110237 return (0); 27512926Sek110237 } 27522926Sek110237 27532926Sek110237 /* 27542926Sek110237 * Perform ioctl to get some command history of a pool. 27552926Sek110237 * 27562926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 27572926Sek110237 * logical offset of the history buffer to start reading from. 27582926Sek110237 * 27592926Sek110237 * Upon return, 'off' is the next logical offset to read from and 27602926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 27612926Sek110237 */ 27622926Sek110237 static int 27632926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 27642926Sek110237 { 27652926Sek110237 zfs_cmd_t zc = { 0 }; 27662926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 27672926Sek110237 27682926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 27692926Sek110237 27702926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 27712926Sek110237 zc.zc_history_len = *len; 27722926Sek110237 zc.zc_history_offset = *off; 27732926Sek110237 27742926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 27752926Sek110237 switch (errno) { 27762926Sek110237 case EPERM: 27773237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 27783237Slling dgettext(TEXT_DOMAIN, 27792926Sek110237 "cannot show history for pool '%s'"), 27802926Sek110237 zhp->zpool_name)); 27812926Sek110237 case ENOENT: 27823237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 27832926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 27842926Sek110237 "'%s'"), zhp->zpool_name)); 27853863Sek110237 case ENOTSUP: 27863863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 27873863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 27883863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 27892926Sek110237 default: 27903237Slling return (zpool_standard_error_fmt(hdl, errno, 27912926Sek110237 dgettext(TEXT_DOMAIN, 27922926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 27932926Sek110237 } 27942926Sek110237 } 27952926Sek110237 27962926Sek110237 *len = zc.zc_history_len; 27972926Sek110237 *off = zc.zc_history_offset; 27982926Sek110237 27992926Sek110237 return (0); 28002926Sek110237 } 28012926Sek110237 28022926Sek110237 /* 28032926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 28042926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 28052926Sek110237 * processed as there wasn't a complete record. 28062926Sek110237 */ 28072926Sek110237 static int 28082926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 28092926Sek110237 nvlist_t ***records, uint_t *numrecords) 28102926Sek110237 { 28112926Sek110237 uint64_t reclen; 28122926Sek110237 nvlist_t *nv; 28132926Sek110237 int i; 28142926Sek110237 28152926Sek110237 while (bytes_read > sizeof (reclen)) { 28162926Sek110237 28172926Sek110237 /* get length of packed record (stored as little endian) */ 28182926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 28192926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 28202926Sek110237 28212926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 28222926Sek110237 break; 28232926Sek110237 28242926Sek110237 /* unpack record */ 28252926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 28262926Sek110237 return (ENOMEM); 28272926Sek110237 bytes_read -= sizeof (reclen) + reclen; 28282926Sek110237 buf += sizeof (reclen) + reclen; 28292926Sek110237 28302926Sek110237 /* add record to nvlist array */ 28312926Sek110237 (*numrecords)++; 28322926Sek110237 if (ISP2(*numrecords + 1)) { 28332926Sek110237 *records = realloc(*records, 28342926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 28352926Sek110237 } 28362926Sek110237 (*records)[*numrecords - 1] = nv; 28372926Sek110237 } 28382926Sek110237 28392926Sek110237 *leftover = bytes_read; 28402926Sek110237 return (0); 28412926Sek110237 } 28422926Sek110237 28432926Sek110237 #define HIS_BUF_LEN (128*1024) 28442926Sek110237 28452926Sek110237 /* 28462926Sek110237 * Retrieve the command history of a pool. 28472926Sek110237 */ 28482926Sek110237 int 28492926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 28502926Sek110237 { 28512926Sek110237 char buf[HIS_BUF_LEN]; 28522926Sek110237 uint64_t off = 0; 28532926Sek110237 nvlist_t **records = NULL; 28542926Sek110237 uint_t numrecords = 0; 28552926Sek110237 int err, i; 28562926Sek110237 28572926Sek110237 do { 28582926Sek110237 uint64_t bytes_read = sizeof (buf); 28592926Sek110237 uint64_t leftover; 28602926Sek110237 28612926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 28622926Sek110237 break; 28632926Sek110237 28642926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 28652926Sek110237 if (!bytes_read) 28662926Sek110237 break; 28672926Sek110237 28682926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 28692926Sek110237 &leftover, &records, &numrecords)) != 0) 28702926Sek110237 break; 28712926Sek110237 off -= leftover; 28722926Sek110237 28732926Sek110237 /* CONSTCOND */ 28742926Sek110237 } while (1); 28752926Sek110237 28762926Sek110237 if (!err) { 28772926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 28782926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 28792926Sek110237 records, numrecords) == 0); 28802926Sek110237 } 28812926Sek110237 for (i = 0; i < numrecords; i++) 28822926Sek110237 nvlist_free(records[i]); 28832926Sek110237 free(records); 28842926Sek110237 28852926Sek110237 return (err); 28862926Sek110237 } 28873444Sek110237 28883444Sek110237 void 28893444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 28903444Sek110237 char *pathname, size_t len) 28913444Sek110237 { 28923444Sek110237 zfs_cmd_t zc = { 0 }; 28933444Sek110237 boolean_t mounted = B_FALSE; 28943444Sek110237 char *mntpnt = NULL; 28953444Sek110237 char dsname[MAXNAMELEN]; 28963444Sek110237 28973444Sek110237 if (dsobj == 0) { 28983444Sek110237 /* special case for the MOS */ 28993444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 29003444Sek110237 return; 29013444Sek110237 } 29023444Sek110237 29033444Sek110237 /* get the dataset's name */ 29043444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29053444Sek110237 zc.zc_obj = dsobj; 29063444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 29073444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 29083444Sek110237 /* just write out a path of two object numbers */ 29093444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 29103444Sek110237 dsobj, obj); 29113444Sek110237 return; 29123444Sek110237 } 29133444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 29143444Sek110237 29153444Sek110237 /* find out if the dataset is mounted */ 29163444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 29173444Sek110237 29183444Sek110237 /* get the corrupted object's path */ 29193444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 29203444Sek110237 zc.zc_obj = obj; 29213444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 29223444Sek110237 &zc) == 0) { 29233444Sek110237 if (mounted) { 29243444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 29253444Sek110237 zc.zc_value); 29263444Sek110237 } else { 29273444Sek110237 (void) snprintf(pathname, len, "%s:%s", 29283444Sek110237 dsname, zc.zc_value); 29293444Sek110237 } 29303444Sek110237 } else { 29313444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 29323444Sek110237 } 29333444Sek110237 free(mntpnt); 29343444Sek110237 } 29353912Slling 29364276Staylor /* 29377042Sgw25295 * Read the EFI label from the config, if a label does not exist then 29387042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 29397042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 29407042Sgw25295 * partition. 29417042Sgw25295 */ 29427042Sgw25295 static int 29437042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 29447042Sgw25295 { 29457042Sgw25295 char *path; 29467042Sgw25295 int fd; 29477042Sgw25295 char diskname[MAXPATHLEN]; 29487042Sgw25295 int err = -1; 29497042Sgw25295 29507042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 29517042Sgw25295 return (err); 29527042Sgw25295 29537042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 29547042Sgw25295 strrchr(path, '/')); 29557042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 29567042Sgw25295 struct dk_gpt *vtoc; 29577042Sgw25295 29587042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 29597042Sgw25295 if (sb != NULL) 29607042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 29617042Sgw25295 efi_free(vtoc); 29627042Sgw25295 } 29637042Sgw25295 (void) close(fd); 29647042Sgw25295 } 29657042Sgw25295 return (err); 29667042Sgw25295 } 29677042Sgw25295 29687042Sgw25295 /* 29694276Staylor * determine where a partition starts on a disk in the current 29704276Staylor * configuration 29714276Staylor */ 29724276Staylor static diskaddr_t 29734276Staylor find_start_block(nvlist_t *config) 29744276Staylor { 29754276Staylor nvlist_t **child; 29764276Staylor uint_t c, children; 29774276Staylor diskaddr_t sb = MAXOFFSET_T; 29784276Staylor uint64_t wholedisk; 29794276Staylor 29804276Staylor if (nvlist_lookup_nvlist_array(config, 29814276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 29824276Staylor if (nvlist_lookup_uint64(config, 29834276Staylor ZPOOL_CONFIG_WHOLE_DISK, 29844276Staylor &wholedisk) != 0 || !wholedisk) { 29854276Staylor return (MAXOFFSET_T); 29864276Staylor } 29877042Sgw25295 if (read_efi_label(config, &sb) < 0) 29887042Sgw25295 sb = MAXOFFSET_T; 29894276Staylor return (sb); 29904276Staylor } 29914276Staylor 29924276Staylor for (c = 0; c < children; c++) { 29934276Staylor sb = find_start_block(child[c]); 29944276Staylor if (sb != MAXOFFSET_T) { 29954276Staylor return (sb); 29964276Staylor } 29974276Staylor } 29984276Staylor return (MAXOFFSET_T); 29994276Staylor } 30004276Staylor 30014276Staylor /* 30024276Staylor * Label an individual disk. The name provided is the short name, 30034276Staylor * stripped of any leading /dev path. 30044276Staylor */ 30054276Staylor int 30064276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 30074276Staylor { 30084276Staylor char path[MAXPATHLEN]; 30094276Staylor struct dk_gpt *vtoc; 30104276Staylor int fd; 30114276Staylor size_t resv = EFI_MIN_RESV_SIZE; 30124276Staylor uint64_t slice_size; 30134276Staylor diskaddr_t start_block; 30144276Staylor char errbuf[1024]; 30154276Staylor 30166289Smmusante /* prepare an error message just in case */ 30176289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 30186289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 30196289Smmusante 30204276Staylor if (zhp) { 30214276Staylor nvlist_t *nvroot; 30224276Staylor 30237965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 30247965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30257965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 30267965SGeorge.Wilson@Sun.COM "pools.")); 30277965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 30287965SGeorge.Wilson@Sun.COM } 30297965SGeorge.Wilson@Sun.COM 30304276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 30314276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 30324276Staylor 30334276Staylor if (zhp->zpool_start_block == 0) 30344276Staylor start_block = find_start_block(nvroot); 30354276Staylor else 30364276Staylor start_block = zhp->zpool_start_block; 30374276Staylor zhp->zpool_start_block = start_block; 30384276Staylor } else { 30394276Staylor /* new pool */ 30404276Staylor start_block = NEW_START_BLOCK; 30414276Staylor } 30424276Staylor 30434276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 30444276Staylor BACKUP_SLICE); 30454276Staylor 30464276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 30474276Staylor /* 30484276Staylor * This shouldn't happen. We've long since verified that this 30494276Staylor * is a valid device. 30504276Staylor */ 30516289Smmusante zfs_error_aux(hdl, 30526289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 30534276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 30544276Staylor } 30554276Staylor 30564276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 30574276Staylor /* 30584276Staylor * The only way this can fail is if we run out of memory, or we 30594276Staylor * were unable to read the disk's capacity 30604276Staylor */ 30614276Staylor if (errno == ENOMEM) 30624276Staylor (void) no_memory(hdl); 30634276Staylor 30644276Staylor (void) close(fd); 30656289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30666289Smmusante "unable to read disk capacity"), name); 30674276Staylor 30684276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 30694276Staylor } 30704276Staylor 30714276Staylor slice_size = vtoc->efi_last_u_lba + 1; 30724276Staylor slice_size -= EFI_MIN_RESV_SIZE; 30734276Staylor if (start_block == MAXOFFSET_T) 30744276Staylor start_block = NEW_START_BLOCK; 30754276Staylor slice_size -= start_block; 30764276Staylor 30774276Staylor vtoc->efi_parts[0].p_start = start_block; 30784276Staylor vtoc->efi_parts[0].p_size = slice_size; 30794276Staylor 30804276Staylor /* 30814276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 30824276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 30834276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 30844276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 30854276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 30864276Staylor * can get, in the absence of V_OTHER. 30874276Staylor */ 30884276Staylor vtoc->efi_parts[0].p_tag = V_USR; 30894276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 30904276Staylor 30914276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 30924276Staylor vtoc->efi_parts[8].p_size = resv; 30934276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 30944276Staylor 30954276Staylor if (efi_write(fd, vtoc) != 0) { 30964276Staylor /* 30974276Staylor * Some block drivers (like pcata) may not support EFI 30984276Staylor * GPT labels. Print out a helpful error message dir- 30994276Staylor * ecting the user to manually label the disk and give 31004276Staylor * a specific slice. 31014276Staylor */ 31024276Staylor (void) close(fd); 31034276Staylor efi_free(vtoc); 31044276Staylor 31054276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31066289Smmusante "try using fdisk(1M) and then provide a specific slice")); 31074276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 31084276Staylor } 31094276Staylor 31104276Staylor (void) close(fd); 31114276Staylor efi_free(vtoc); 31124276Staylor return (0); 31134276Staylor } 31146423Sgw25295 31156423Sgw25295 static boolean_t 31166423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 31176423Sgw25295 { 31186423Sgw25295 char *type; 31196423Sgw25295 nvlist_t **child; 31206423Sgw25295 uint_t children, c; 31216423Sgw25295 31226423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 31236423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 31246423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 31256423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 3126*10594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 31276423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 31286423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31296423Sgw25295 "vdev type '%s' is not supported"), type); 31306423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 31316423Sgw25295 return (B_FALSE); 31326423Sgw25295 } 31336423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 31346423Sgw25295 &child, &children) == 0) { 31356423Sgw25295 for (c = 0; c < children; c++) { 31366423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 31376423Sgw25295 return (B_FALSE); 31386423Sgw25295 } 31396423Sgw25295 } 31406423Sgw25295 return (B_TRUE); 31416423Sgw25295 } 31426423Sgw25295 31436423Sgw25295 /* 31446423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 31456423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 31466423Sgw25295 */ 31476423Sgw25295 int 31486423Sgw25295 zvol_check_dump_config(char *arg) 31496423Sgw25295 { 31506423Sgw25295 zpool_handle_t *zhp = NULL; 31516423Sgw25295 nvlist_t *config, *nvroot; 31526423Sgw25295 char *p, *volname; 31536423Sgw25295 nvlist_t **top; 31546423Sgw25295 uint_t toplevels; 31556423Sgw25295 libzfs_handle_t *hdl; 31566423Sgw25295 char errbuf[1024]; 31576423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 31586423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 31596423Sgw25295 int ret = 1; 31606423Sgw25295 31616423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 31626423Sgw25295 return (-1); 31636423Sgw25295 } 31646423Sgw25295 31656423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 31666423Sgw25295 "dump is not supported on device '%s'"), arg); 31676423Sgw25295 31686423Sgw25295 if ((hdl = libzfs_init()) == NULL) 31696423Sgw25295 return (1); 31706423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 31716423Sgw25295 31726423Sgw25295 volname = arg + pathlen; 31736423Sgw25295 31746423Sgw25295 /* check the configuration of the pool */ 31756423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 31766423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31776423Sgw25295 "malformed dataset name")); 31786423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 31796423Sgw25295 return (1); 31806423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 31816423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31826423Sgw25295 "dataset name is too long")); 31836423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 31846423Sgw25295 return (1); 31856423Sgw25295 } else { 31866423Sgw25295 (void) strncpy(poolname, volname, p - volname); 31876423Sgw25295 poolname[p - volname] = '\0'; 31886423Sgw25295 } 31896423Sgw25295 31906423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 31916423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31926423Sgw25295 "could not open pool '%s'"), poolname); 31936423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 31946423Sgw25295 goto out; 31956423Sgw25295 } 31966423Sgw25295 config = zpool_get_config(zhp, NULL); 31976423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 31986423Sgw25295 &nvroot) != 0) { 31996423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32006423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 32016423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 32026423Sgw25295 goto out; 32036423Sgw25295 } 32046423Sgw25295 32056423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 32066423Sgw25295 &top, &toplevels) == 0); 32076423Sgw25295 if (toplevels != 1) { 32086423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32096423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 32106423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 32116423Sgw25295 goto out; 32126423Sgw25295 } 32136423Sgw25295 32146423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 32156423Sgw25295 goto out; 32166423Sgw25295 } 32176423Sgw25295 ret = 0; 32186423Sgw25295 32196423Sgw25295 out: 32206423Sgw25295 if (zhp) 32216423Sgw25295 zpool_close(zhp); 32226423Sgw25295 libzfs_fini(hdl); 32236423Sgw25295 return (ret); 32246423Sgw25295 } 3225