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 273126Sahl #include <alloca.h> 28789Sahrens #include <assert.h> 29789Sahrens #include <ctype.h> 30789Sahrens #include <errno.h> 31789Sahrens #include <devid.h> 323126Sahl #include <dirent.h> 33789Sahrens #include <fcntl.h> 34789Sahrens #include <libintl.h> 35789Sahrens #include <stdio.h> 36789Sahrens #include <stdlib.h> 373126Sahl #include <strings.h> 38789Sahrens #include <unistd.h> 397184Stimh #include <zone.h> 404276Staylor #include <sys/efi_partition.h> 414276Staylor #include <sys/vtoc.h> 42789Sahrens #include <sys/zfs_ioctl.h> 431544Seschrock #include <sys/zio.h> 442926Sek110237 #include <strings.h> 45*9816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 46789Sahrens 47789Sahrens #include "zfs_namecheck.h" 483912Slling #include "zfs_prop.h" 49789Sahrens #include "libzfs_impl.h" 50789Sahrens 517042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 525094Slling 537965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 547965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 557965SGeorge.Wilson@Sun.COM #else 567965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 577965SGeorge.Wilson@Sun.COM #endif 587965SGeorge.Wilson@Sun.COM 59*9816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 60*9816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 61*9816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 62*9816SGeorge.Wilson@Sun.COM 635094Slling /* 645094Slling * ==================================================================== 655094Slling * zpool property functions 665094Slling * ==================================================================== 675094Slling */ 685094Slling 695094Slling static int 705094Slling zpool_get_all_props(zpool_handle_t *zhp) 715094Slling { 725094Slling zfs_cmd_t zc = { 0 }; 735094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 745094Slling 755094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 765094Slling 775094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 785094Slling return (-1); 795094Slling 805094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 815094Slling if (errno == ENOMEM) { 825094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 835094Slling zcmd_free_nvlists(&zc); 845094Slling return (-1); 855094Slling } 865094Slling } else { 875094Slling zcmd_free_nvlists(&zc); 885094Slling return (-1); 895094Slling } 905094Slling } 915094Slling 925094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 935094Slling zcmd_free_nvlists(&zc); 945094Slling return (-1); 955094Slling } 965094Slling 975094Slling zcmd_free_nvlists(&zc); 985094Slling 995094Slling return (0); 1005094Slling } 1015094Slling 1025094Slling static int 1035094Slling zpool_props_refresh(zpool_handle_t *zhp) 1045094Slling { 1055094Slling nvlist_t *old_props; 1065094Slling 1075094Slling old_props = zhp->zpool_props; 1085094Slling 1095094Slling if (zpool_get_all_props(zhp) != 0) 1105094Slling return (-1); 1115094Slling 1125094Slling nvlist_free(old_props); 1135094Slling return (0); 1145094Slling } 1155094Slling 1165094Slling static char * 1175094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1185094Slling zprop_source_t *src) 1195094Slling { 1205094Slling nvlist_t *nv, *nvl; 1215094Slling uint64_t ival; 1225094Slling char *value; 1235094Slling zprop_source_t source; 1245094Slling 1255094Slling nvl = zhp->zpool_props; 1265094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1275094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1285094Slling source = ival; 1295094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1305094Slling } else { 1315094Slling source = ZPROP_SRC_DEFAULT; 1325094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1335094Slling value = "-"; 1345094Slling } 1355094Slling 1365094Slling if (src) 1375094Slling *src = source; 1385094Slling 1395094Slling return (value); 1405094Slling } 1415094Slling 1425094Slling uint64_t 1435094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1445094Slling { 1455094Slling nvlist_t *nv, *nvl; 1465094Slling uint64_t value; 1475094Slling zprop_source_t source; 1485094Slling 1497294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1507294Sperrin /* 1517294Sperrin * zpool_get_all_props() has most likely failed because 1527294Sperrin * the pool is faulted, but if all we need is the top level 1537294Sperrin * vdev's guid then get it from the zhp config nvlist. 1547294Sperrin */ 1557294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1567294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1577294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1587294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1597294Sperrin == 0)) { 1607294Sperrin return (value); 1617294Sperrin } 1625094Slling return (zpool_prop_default_numeric(prop)); 1637294Sperrin } 1645094Slling 1655094Slling nvl = zhp->zpool_props; 1665094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1675094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 1685094Slling source = value; 1695094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1705094Slling } else { 1715094Slling source = ZPROP_SRC_DEFAULT; 1725094Slling value = zpool_prop_default_numeric(prop); 1735094Slling } 1745094Slling 1755094Slling if (src) 1765094Slling *src = source; 1775094Slling 1785094Slling return (value); 1795094Slling } 1805094Slling 1815094Slling /* 1825094Slling * Map VDEV STATE to printed strings. 1835094Slling */ 1845094Slling char * 1855094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 1865094Slling { 1875094Slling switch (state) { 1885094Slling case VDEV_STATE_CLOSED: 1895094Slling case VDEV_STATE_OFFLINE: 1905094Slling return (gettext("OFFLINE")); 1915094Slling case VDEV_STATE_REMOVED: 1925094Slling return (gettext("REMOVED")); 1935094Slling case VDEV_STATE_CANT_OPEN: 1947294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 1955094Slling return (gettext("FAULTED")); 1965094Slling else 1975094Slling return (gettext("UNAVAIL")); 1985094Slling case VDEV_STATE_FAULTED: 1995094Slling return (gettext("FAULTED")); 2005094Slling case VDEV_STATE_DEGRADED: 2015094Slling return (gettext("DEGRADED")); 2025094Slling case VDEV_STATE_HEALTHY: 2035094Slling return (gettext("ONLINE")); 2045094Slling } 2055094Slling 2065094Slling return (gettext("UNKNOWN")); 2075094Slling } 2085094Slling 2095094Slling /* 2105094Slling * Get a zpool property value for 'prop' and return the value in 2115094Slling * a pre-allocated buffer. 2125094Slling */ 2135094Slling int 2145094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2155094Slling zprop_source_t *srctype) 2165094Slling { 2175094Slling uint64_t intval; 2185094Slling const char *strval; 2195094Slling zprop_source_t src = ZPROP_SRC_NONE; 2205094Slling nvlist_t *nvroot; 2215094Slling vdev_stat_t *vs; 2225094Slling uint_t vsc; 2235094Slling 2245094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2258525SEric.Schrock@Sun.COM switch (prop) { 2268525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2275094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2288525SEric.Schrock@Sun.COM break; 2298525SEric.Schrock@Sun.COM 2308525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2315094Slling (void) strlcpy(buf, "FAULTED", len); 2328525SEric.Schrock@Sun.COM break; 2338525SEric.Schrock@Sun.COM 2348525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2358525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2368525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2378525SEric.Schrock@Sun.COM break; 2388525SEric.Schrock@Sun.COM 2398525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2408525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2418525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2428525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2438525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2448525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2458525SEric.Schrock@Sun.COM len); 2468525SEric.Schrock@Sun.COM if (srctype != NULL) 2478525SEric.Schrock@Sun.COM *srctype = src; 2488525SEric.Schrock@Sun.COM return (0); 2498525SEric.Schrock@Sun.COM } 2508525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2518525SEric.Schrock@Sun.COM default: 2525094Slling (void) strlcpy(buf, "-", len); 2538525SEric.Schrock@Sun.COM break; 2548525SEric.Schrock@Sun.COM } 2558525SEric.Schrock@Sun.COM 2568525SEric.Schrock@Sun.COM if (srctype != NULL) 2578525SEric.Schrock@Sun.COM *srctype = src; 2585094Slling return (0); 2595094Slling } 2605094Slling 2615094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2625094Slling prop != ZPOOL_PROP_NAME) 2635094Slling return (-1); 2645094Slling 2655094Slling switch (zpool_prop_get_type(prop)) { 2665094Slling case PROP_TYPE_STRING: 2675094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 2685094Slling len); 2695094Slling break; 2705094Slling 2715094Slling case PROP_TYPE_NUMBER: 2725094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2735094Slling 2745094Slling switch (prop) { 2755094Slling case ZPOOL_PROP_SIZE: 2765094Slling case ZPOOL_PROP_USED: 2775094Slling case ZPOOL_PROP_AVAILABLE: 2785094Slling (void) zfs_nicenum(intval, buf, len); 2795094Slling break; 2805094Slling 2815094Slling case ZPOOL_PROP_CAPACITY: 2825094Slling (void) snprintf(buf, len, "%llu%%", 2835094Slling (u_longlong_t)intval); 2845094Slling break; 2855094Slling 2865094Slling case ZPOOL_PROP_HEALTH: 2875094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 2885094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2895094Slling verify(nvlist_lookup_uint64_array(nvroot, 2905094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 2915094Slling 2925094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 2935094Slling vs->vs_aux), len); 2945094Slling break; 2955094Slling default: 2965094Slling (void) snprintf(buf, len, "%llu", intval); 2975094Slling } 2985094Slling break; 2995094Slling 3005094Slling case PROP_TYPE_INDEX: 3015094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3025094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3035094Slling != 0) 3045094Slling return (-1); 3055094Slling (void) strlcpy(buf, strval, len); 3065094Slling break; 3075094Slling 3085094Slling default: 3095094Slling abort(); 3105094Slling } 3115094Slling 3125094Slling if (srctype) 3135094Slling *srctype = src; 3145094Slling 3155094Slling return (0); 3165094Slling } 3175094Slling 3185094Slling /* 3195094Slling * Check if the bootfs name has the same pool name as it is set to. 3205094Slling * Assuming bootfs is a valid dataset name. 3215094Slling */ 3225094Slling static boolean_t 3235094Slling bootfs_name_valid(const char *pool, char *bootfs) 3245094Slling { 3255094Slling int len = strlen(pool); 3265094Slling 3277300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3285094Slling return (B_FALSE); 3295094Slling 3305094Slling if (strncmp(pool, bootfs, len) == 0 && 3315094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3325094Slling return (B_TRUE); 3335094Slling 3345094Slling return (B_FALSE); 3355094Slling } 3365094Slling 3375094Slling /* 3387042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3397042Sgw25295 * an EFI label. 3407042Sgw25295 */ 3417042Sgw25295 static boolean_t 3427042Sgw25295 pool_uses_efi(nvlist_t *config) 3437042Sgw25295 { 3447042Sgw25295 nvlist_t **child; 3457042Sgw25295 uint_t c, children; 3467042Sgw25295 3477042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3487042Sgw25295 &child, &children) != 0) 3497042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3507042Sgw25295 3517042Sgw25295 for (c = 0; c < children; c++) { 3527042Sgw25295 if (pool_uses_efi(child[c])) 3537042Sgw25295 return (B_TRUE); 3547042Sgw25295 } 3557042Sgw25295 return (B_FALSE); 3567042Sgw25295 } 3577042Sgw25295 3587965SGeorge.Wilson@Sun.COM static boolean_t 3597965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3607965SGeorge.Wilson@Sun.COM { 3617965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3627965SGeorge.Wilson@Sun.COM 3637965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 3647965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 3657965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 3667965SGeorge.Wilson@Sun.COM } 3677965SGeorge.Wilson@Sun.COM 3687965SGeorge.Wilson@Sun.COM 3697042Sgw25295 /* 3705094Slling * Given an nvlist of zpool properties to be set, validate that they are 3715094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 3725094Slling * specified as strings. 3735094Slling */ 3745094Slling static nvlist_t * 3757184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 3765094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 3775094Slling { 3785094Slling nvpair_t *elem; 3795094Slling nvlist_t *retprops; 3805094Slling zpool_prop_t prop; 3815094Slling char *strval; 3825094Slling uint64_t intval; 3835363Seschrock char *slash; 3845363Seschrock struct stat64 statbuf; 3857042Sgw25295 zpool_handle_t *zhp; 3867042Sgw25295 nvlist_t *nvroot; 3875094Slling 3885094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 3895094Slling (void) no_memory(hdl); 3905094Slling return (NULL); 3915094Slling } 3925094Slling 3935094Slling elem = NULL; 3945094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 3955094Slling const char *propname = nvpair_name(elem); 3965094Slling 3975094Slling /* 3985094Slling * Make sure this property is valid and applies to this type. 3995094Slling */ 4005094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4015094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4025094Slling "invalid property '%s'"), propname); 4035094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4045094Slling goto error; 4055094Slling } 4065094Slling 4075094Slling if (zpool_prop_readonly(prop)) { 4085094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4095094Slling "is readonly"), propname); 4105094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4115094Slling goto error; 4125094Slling } 4135094Slling 4145094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4155094Slling &strval, &intval, errbuf) != 0) 4165094Slling goto error; 4175094Slling 4185094Slling /* 4195094Slling * Perform additional checking for specific properties. 4205094Slling */ 4215094Slling switch (prop) { 4225094Slling case ZPOOL_PROP_VERSION: 4235094Slling if (intval < version || intval > SPA_VERSION) { 4245094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4255094Slling "property '%s' number %d is invalid."), 4265094Slling propname, intval); 4275094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4285094Slling goto error; 4295094Slling } 4305094Slling break; 4315094Slling 4325094Slling case ZPOOL_PROP_BOOTFS: 4335094Slling if (create_or_import) { 4345094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4355094Slling "property '%s' cannot be set at creation " 4365094Slling "or import time"), propname); 4375094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4385094Slling goto error; 4395094Slling } 4405094Slling 4415094Slling if (version < SPA_VERSION_BOOTFS) { 4425094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4435094Slling "pool must be upgraded to support " 4445094Slling "'%s' property"), propname); 4455094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4465094Slling goto error; 4475094Slling } 4485094Slling 4495094Slling /* 4505094Slling * bootfs property value has to be a dataset name and 4515094Slling * the dataset has to be in the same pool as it sets to. 4525094Slling */ 4535094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4545094Slling strval)) { 4555094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4565094Slling "is an invalid name"), strval); 4575094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4585094Slling goto error; 4595094Slling } 4607042Sgw25295 4617042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4627042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4637042Sgw25295 "could not open pool '%s'"), poolname); 4647042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4657042Sgw25295 goto error; 4667042Sgw25295 } 4677042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 4687042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 4697042Sgw25295 4707042Sgw25295 /* 4717042Sgw25295 * bootfs property cannot be set on a disk which has 4727042Sgw25295 * been EFI labeled. 4737042Sgw25295 */ 4747042Sgw25295 if (pool_uses_efi(nvroot)) { 4757042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4767042Sgw25295 "property '%s' not supported on " 4777042Sgw25295 "EFI labeled devices"), propname); 4787042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 4797042Sgw25295 zpool_close(zhp); 4807042Sgw25295 goto error; 4817042Sgw25295 } 4827042Sgw25295 zpool_close(zhp); 4835094Slling break; 4845094Slling 4855094Slling case ZPOOL_PROP_ALTROOT: 4865094Slling if (!create_or_import) { 4875094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4885094Slling "property '%s' can only be set during pool " 4895094Slling "creation or import"), propname); 4905094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4915094Slling goto error; 4925094Slling } 4935094Slling 4945094Slling if (strval[0] != '/') { 4955094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4965094Slling "bad alternate root '%s'"), strval); 4975094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 4985094Slling goto error; 4995094Slling } 5005094Slling break; 5015363Seschrock 5025363Seschrock case ZPOOL_PROP_CACHEFILE: 5035363Seschrock if (strval[0] == '\0') 5045363Seschrock break; 5055363Seschrock 5065363Seschrock if (strcmp(strval, "none") == 0) 5075363Seschrock break; 5085363Seschrock 5095363Seschrock if (strval[0] != '/') { 5105363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5115363Seschrock "property '%s' must be empty, an " 5125363Seschrock "absolute path, or 'none'"), propname); 5135363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5145363Seschrock goto error; 5155363Seschrock } 5165363Seschrock 5175363Seschrock slash = strrchr(strval, '/'); 5185363Seschrock 5195363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5205363Seschrock strcmp(slash, "/..") == 0) { 5215363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5225363Seschrock "'%s' is not a valid file"), strval); 5235363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5245363Seschrock goto error; 5255363Seschrock } 5265363Seschrock 5275363Seschrock *slash = '\0'; 5285363Seschrock 5295621Seschrock if (strval[0] != '\0' && 5305621Seschrock (stat64(strval, &statbuf) != 0 || 5315621Seschrock !S_ISDIR(statbuf.st_mode))) { 5325363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5335363Seschrock "'%s' is not a valid directory"), 5345363Seschrock strval); 5355363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5365363Seschrock goto error; 5375363Seschrock } 5385363Seschrock 5395363Seschrock *slash = '/'; 5405363Seschrock break; 5415094Slling } 5425094Slling } 5435094Slling 5445094Slling return (retprops); 5455094Slling error: 5465094Slling nvlist_free(retprops); 5475094Slling return (NULL); 5485094Slling } 5495094Slling 5505094Slling /* 5515094Slling * Set zpool property : propname=propval. 5525094Slling */ 5535094Slling int 5545094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5555094Slling { 5565094Slling zfs_cmd_t zc = { 0 }; 5575094Slling int ret = -1; 5585094Slling char errbuf[1024]; 5595094Slling nvlist_t *nvl = NULL; 5605094Slling nvlist_t *realprops; 5615094Slling uint64_t version; 5625094Slling 5635094Slling (void) snprintf(errbuf, sizeof (errbuf), 5645094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 5655094Slling zhp->zpool_name); 5665094Slling 5675094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5685094Slling return (no_memory(zhp->zpool_hdl)); 5695094Slling 5705094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 5715094Slling nvlist_free(nvl); 5725094Slling return (no_memory(zhp->zpool_hdl)); 5735094Slling } 5745094Slling 5755094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5767184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 5775094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 5785094Slling nvlist_free(nvl); 5795094Slling return (-1); 5805094Slling } 5815094Slling 5825094Slling nvlist_free(nvl); 5835094Slling nvl = realprops; 5845094Slling 5855094Slling /* 5865094Slling * Execute the corresponding ioctl() to set this property. 5875094Slling */ 5885094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 5895094Slling 5905094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 5915094Slling nvlist_free(nvl); 5925094Slling return (-1); 5935094Slling } 5945094Slling 5955094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 5965094Slling 5975094Slling zcmd_free_nvlists(&zc); 5985094Slling nvlist_free(nvl); 5995094Slling 6005094Slling if (ret) 6015094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6025094Slling else 6035094Slling (void) zpool_props_refresh(zhp); 6045094Slling 6055094Slling return (ret); 6065094Slling } 6075094Slling 6085094Slling int 6095094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6105094Slling { 6115094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6125094Slling zprop_list_t *entry; 6135094Slling char buf[ZFS_MAXPROPLEN]; 6145094Slling 6155094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6165094Slling return (-1); 6175094Slling 6185094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6195094Slling 6205094Slling if (entry->pl_fixed) 6215094Slling continue; 6225094Slling 6235094Slling if (entry->pl_prop != ZPROP_INVAL && 6245094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6255094Slling NULL) == 0) { 6265094Slling if (strlen(buf) > entry->pl_width) 6275094Slling entry->pl_width = strlen(buf); 6285094Slling } 6295094Slling } 6305094Slling 6315094Slling return (0); 6325094Slling } 6335094Slling 6345094Slling 635789Sahrens /* 636*9816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 637*9816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 638*9816SGeorge.Wilson@Sun.COM */ 639*9816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 640*9816SGeorge.Wilson@Sun.COM 641*9816SGeorge.Wilson@Sun.COM /* 642789Sahrens * Validate the given pool name, optionally putting an extended error message in 643789Sahrens * 'buf'. 644789Sahrens */ 6456423Sgw25295 boolean_t 6462082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 647789Sahrens { 648789Sahrens namecheck_err_t why; 649789Sahrens char what; 6501773Seschrock int ret; 651789Sahrens 6521773Seschrock ret = pool_namecheck(pool, &why, &what); 6531773Seschrock 6541773Seschrock /* 6551773Seschrock * The rules for reserved pool names were extended at a later point. 6561773Seschrock * But we need to support users with existing pools that may now be 6571773Seschrock * invalid. So we only check for this expanded set of names during a 6581773Seschrock * create (or import), and only in userland. 6591773Seschrock */ 6601773Seschrock if (ret == 0 && !isopen && 6611773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6621773Seschrock strncmp(pool, "raidz", 5) == 0 || 6634527Sperrin strncmp(pool, "spare", 5) == 0 || 6644527Sperrin strcmp(pool, "log") == 0)) { 6656423Sgw25295 if (hdl != NULL) 6666423Sgw25295 zfs_error_aux(hdl, 6676423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 6682082Seschrock return (B_FALSE); 6691773Seschrock } 6701773Seschrock 6711773Seschrock 6721773Seschrock if (ret != 0) { 6732082Seschrock if (hdl != NULL) { 674789Sahrens switch (why) { 6751003Slling case NAME_ERR_TOOLONG: 6762082Seschrock zfs_error_aux(hdl, 6771003Slling dgettext(TEXT_DOMAIN, "name is too long")); 6781003Slling break; 6791003Slling 680789Sahrens case NAME_ERR_INVALCHAR: 6812082Seschrock zfs_error_aux(hdl, 682789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 683789Sahrens "'%c' in pool name"), what); 684789Sahrens break; 685789Sahrens 686789Sahrens case NAME_ERR_NOLETTER: 6872082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6882082Seschrock "name must begin with a letter")); 689789Sahrens break; 690789Sahrens 691789Sahrens case NAME_ERR_RESERVED: 6922082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6932082Seschrock "name is reserved")); 694789Sahrens break; 695789Sahrens 696789Sahrens case NAME_ERR_DISKLIKE: 6972082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6982082Seschrock "pool name is reserved")); 699789Sahrens break; 7002856Snd150628 7012856Snd150628 case NAME_ERR_LEADING_SLASH: 7022856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7032856Snd150628 "leading slash in name")); 7042856Snd150628 break; 7052856Snd150628 7062856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7072856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7082856Snd150628 "empty component in name")); 7092856Snd150628 break; 7102856Snd150628 7112856Snd150628 case NAME_ERR_TRAILING_SLASH: 7122856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7132856Snd150628 "trailing slash in name")); 7142856Snd150628 break; 7152856Snd150628 7162856Snd150628 case NAME_ERR_MULTIPLE_AT: 7172856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7182856Snd150628 "multiple '@' delimiters in name")); 7192856Snd150628 break; 7202856Snd150628 721789Sahrens } 722789Sahrens } 7232082Seschrock return (B_FALSE); 724789Sahrens } 725789Sahrens 7262082Seschrock return (B_TRUE); 727789Sahrens } 728789Sahrens 729789Sahrens /* 730789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 731789Sahrens * state. 732789Sahrens */ 733789Sahrens zpool_handle_t * 7342082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 735789Sahrens { 736789Sahrens zpool_handle_t *zhp; 7372142Seschrock boolean_t missing; 738789Sahrens 739789Sahrens /* 740789Sahrens * Make sure the pool name is valid. 741789Sahrens */ 7422082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7433237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7442082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7452082Seschrock pool); 746789Sahrens return (NULL); 747789Sahrens } 748789Sahrens 7492082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7502082Seschrock return (NULL); 751789Sahrens 7522082Seschrock zhp->zpool_hdl = hdl; 753789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 754789Sahrens 7552142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7562142Seschrock zpool_close(zhp); 7572142Seschrock return (NULL); 7582142Seschrock } 7592142Seschrock 7602142Seschrock if (missing) { 7615094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7623237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 7635094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 7642142Seschrock zpool_close(zhp); 7652142Seschrock return (NULL); 766789Sahrens } 767789Sahrens 768789Sahrens return (zhp); 769789Sahrens } 770789Sahrens 771789Sahrens /* 772789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 773789Sahrens * the configuration cache may be out of date). 774789Sahrens */ 7752142Seschrock int 7762142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 777789Sahrens { 778789Sahrens zpool_handle_t *zhp; 7792142Seschrock boolean_t missing; 780789Sahrens 7812142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7822142Seschrock return (-1); 783789Sahrens 7842082Seschrock zhp->zpool_hdl = hdl; 785789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 786789Sahrens 7872142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7882142Seschrock zpool_close(zhp); 7892142Seschrock return (-1); 790789Sahrens } 791789Sahrens 7922142Seschrock if (missing) { 7932142Seschrock zpool_close(zhp); 7942142Seschrock *ret = NULL; 7952142Seschrock return (0); 7962142Seschrock } 7972142Seschrock 7982142Seschrock *ret = zhp; 7992142Seschrock return (0); 800789Sahrens } 801789Sahrens 802789Sahrens /* 803789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 804789Sahrens * state. 805789Sahrens */ 806789Sahrens zpool_handle_t * 8072082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 808789Sahrens { 809789Sahrens zpool_handle_t *zhp; 810789Sahrens 8112082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 812789Sahrens return (NULL); 813789Sahrens 814789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8153237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8162082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 817789Sahrens zpool_close(zhp); 818789Sahrens return (NULL); 819789Sahrens } 820789Sahrens 821789Sahrens return (zhp); 822789Sahrens } 823789Sahrens 824789Sahrens /* 825789Sahrens * Close the handle. Simply frees the memory associated with the handle. 826789Sahrens */ 827789Sahrens void 828789Sahrens zpool_close(zpool_handle_t *zhp) 829789Sahrens { 830789Sahrens if (zhp->zpool_config) 831789Sahrens nvlist_free(zhp->zpool_config); 832952Seschrock if (zhp->zpool_old_config) 833952Seschrock nvlist_free(zhp->zpool_old_config); 8343912Slling if (zhp->zpool_props) 8353912Slling nvlist_free(zhp->zpool_props); 836789Sahrens free(zhp); 837789Sahrens } 838789Sahrens 839789Sahrens /* 840789Sahrens * Return the name of the pool. 841789Sahrens */ 842789Sahrens const char * 843789Sahrens zpool_get_name(zpool_handle_t *zhp) 844789Sahrens { 845789Sahrens return (zhp->zpool_name); 846789Sahrens } 847789Sahrens 848789Sahrens 849789Sahrens /* 850789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 851789Sahrens */ 852789Sahrens int 853789Sahrens zpool_get_state(zpool_handle_t *zhp) 854789Sahrens { 855789Sahrens return (zhp->zpool_state); 856789Sahrens } 857789Sahrens 858789Sahrens /* 859789Sahrens * Create the named pool, using the provided vdev list. It is assumed 860789Sahrens * that the consumer has already validated the contents of the nvlist, so we 861789Sahrens * don't have to worry about error semantics. 862789Sahrens */ 863789Sahrens int 8642082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8657184Stimh nvlist_t *props, nvlist_t *fsprops) 866789Sahrens { 867789Sahrens zfs_cmd_t zc = { 0 }; 8687184Stimh nvlist_t *zc_fsprops = NULL; 8697184Stimh nvlist_t *zc_props = NULL; 8702082Seschrock char msg[1024]; 8715094Slling char *altroot; 8727184Stimh int ret = -1; 8732082Seschrock 8742082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 8752082Seschrock "cannot create '%s'"), pool); 876789Sahrens 8772082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 8782082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 8792082Seschrock 8805320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 8815320Slling return (-1); 8825320Slling 8837184Stimh if (props) { 8847184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8857184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8867184Stimh goto create_failed; 8877184Stimh } 8885320Slling } 889789Sahrens 8907184Stimh if (fsprops) { 8917184Stimh uint64_t zoned; 8927184Stimh char *zonestr; 8937184Stimh 8947184Stimh zoned = ((nvlist_lookup_string(fsprops, 8957184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8967184Stimh strcmp(zonestr, "on") == 0); 8977184Stimh 8987184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 8997184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9007184Stimh goto create_failed; 9017184Stimh } 9027184Stimh if (!zc_props && 9037184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9047184Stimh goto create_failed; 9057184Stimh } 9067184Stimh if (nvlist_add_nvlist(zc_props, 9077184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9087184Stimh goto create_failed; 9097184Stimh } 9107184Stimh } 9117184Stimh 9127184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9137184Stimh goto create_failed; 9147184Stimh 915789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 916789Sahrens 9177184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9185320Slling 9192676Seschrock zcmd_free_nvlists(&zc); 9207184Stimh nvlist_free(zc_props); 9217184Stimh nvlist_free(zc_fsprops); 9222082Seschrock 923789Sahrens switch (errno) { 924789Sahrens case EBUSY: 925789Sahrens /* 926789Sahrens * This can happen if the user has specified the same 927789Sahrens * device multiple times. We can't reliably detect this 928789Sahrens * until we try to add it and see we already have a 929789Sahrens * label. 930789Sahrens */ 9312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9322082Seschrock "one or more vdevs refer to the same device")); 9332082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 934789Sahrens 935789Sahrens case EOVERFLOW: 936789Sahrens /* 9372082Seschrock * This occurs when one of the devices is below 938789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 939789Sahrens * device was the problem device since there's no 940789Sahrens * reliable way to determine device size from userland. 941789Sahrens */ 942789Sahrens { 943789Sahrens char buf[64]; 944789Sahrens 945789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 946789Sahrens 9472082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9482082Seschrock "one or more devices is less than the " 9492082Seschrock "minimum size (%s)"), buf); 950789Sahrens } 9512082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 952789Sahrens 953789Sahrens case ENOSPC: 9542082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9552082Seschrock "one or more devices is out of space")); 9562082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 957789Sahrens 9585450Sbrendan case ENOTBLK: 9595450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9605450Sbrendan "cache device must be a disk or disk slice")); 9615450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9625450Sbrendan 963789Sahrens default: 9642082Seschrock return (zpool_standard_error(hdl, errno, msg)); 965789Sahrens } 966789Sahrens } 967789Sahrens 968789Sahrens /* 969789Sahrens * If this is an alternate root pool, then we automatically set the 9702676Seschrock * mountpoint of the root dataset to be '/'. 971789Sahrens */ 9725094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 9735094Slling &altroot) == 0) { 974789Sahrens zfs_handle_t *zhp; 975789Sahrens 9765094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 9772676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 9782676Seschrock "/") == 0); 979789Sahrens 980789Sahrens zfs_close(zhp); 981789Sahrens } 982789Sahrens 9837184Stimh create_failed: 9845320Slling zcmd_free_nvlists(&zc); 9857184Stimh nvlist_free(zc_props); 9867184Stimh nvlist_free(zc_fsprops); 9877184Stimh return (ret); 988789Sahrens } 989789Sahrens 990789Sahrens /* 991789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 992789Sahrens * datasets left in the pool. 993789Sahrens */ 994789Sahrens int 995789Sahrens zpool_destroy(zpool_handle_t *zhp) 996789Sahrens { 997789Sahrens zfs_cmd_t zc = { 0 }; 998789Sahrens zfs_handle_t *zfp = NULL; 9992082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10002082Seschrock char msg[1024]; 1001789Sahrens 1002789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 10032082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 10042082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1005789Sahrens return (-1); 1006789Sahrens 10072856Snd150628 if (zpool_remove_zvol_links(zhp) != 0) 1008789Sahrens return (-1); 1009789Sahrens 1010789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1011789Sahrens 10124543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10132082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10142082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1015789Sahrens 10162082Seschrock if (errno == EROFS) { 10172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10182082Seschrock "one or more devices is read only")); 10192082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10202082Seschrock } else { 10212082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1022789Sahrens } 1023789Sahrens 1024789Sahrens if (zfp) 1025789Sahrens zfs_close(zfp); 1026789Sahrens return (-1); 1027789Sahrens } 1028789Sahrens 1029789Sahrens if (zfp) { 1030789Sahrens remove_mountpoint(zfp); 1031789Sahrens zfs_close(zfp); 1032789Sahrens } 1033789Sahrens 1034789Sahrens return (0); 1035789Sahrens } 1036789Sahrens 1037789Sahrens /* 1038789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1039789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1040789Sahrens */ 1041789Sahrens int 1042789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1043789Sahrens { 10442676Seschrock zfs_cmd_t zc = { 0 }; 10452082Seschrock int ret; 10462082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10472082Seschrock char msg[1024]; 10485450Sbrendan nvlist_t **spares, **l2cache; 10495450Sbrendan uint_t nspares, nl2cache; 10502082Seschrock 10512082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10522082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10532082Seschrock 10545450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10555450Sbrendan SPA_VERSION_SPARES && 10562082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10572082Seschrock &spares, &nspares) == 0) { 10582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10592082Seschrock "upgraded to add hot spares")); 10602082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10612082Seschrock } 1062789Sahrens 10637965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10647965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10657965SGeorge.Wilson@Sun.COM uint64_t s; 10667965SGeorge.Wilson@Sun.COM 10677965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 10687965SGeorge.Wilson@Sun.COM char *path; 10697965SGeorge.Wilson@Sun.COM 10707965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 10717965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 10727965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10737965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 10747965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 10757965SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s])); 10767965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 10777965SGeorge.Wilson@Sun.COM } 10787965SGeorge.Wilson@Sun.COM } 10797965SGeorge.Wilson@Sun.COM } 10807965SGeorge.Wilson@Sun.COM 10815450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10825450Sbrendan SPA_VERSION_L2CACHE && 10835450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 10845450Sbrendan &l2cache, &nl2cache) == 0) { 10855450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10865450Sbrendan "upgraded to add cache devices")); 10875450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10885450Sbrendan } 10895450Sbrendan 10905094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 10912082Seschrock return (-1); 1092789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1093789Sahrens 10944543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1095789Sahrens switch (errno) { 1096789Sahrens case EBUSY: 1097789Sahrens /* 1098789Sahrens * This can happen if the user has specified the same 1099789Sahrens * device multiple times. We can't reliably detect this 1100789Sahrens * until we try to add it and see we already have a 1101789Sahrens * label. 1102789Sahrens */ 11032082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11042082Seschrock "one or more vdevs refer to the same device")); 11052082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1106789Sahrens break; 1107789Sahrens 1108789Sahrens case EOVERFLOW: 1109789Sahrens /* 1110789Sahrens * This occurrs when one of the devices is below 1111789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1112789Sahrens * device was the problem device since there's no 1113789Sahrens * reliable way to determine device size from userland. 1114789Sahrens */ 1115789Sahrens { 1116789Sahrens char buf[64]; 1117789Sahrens 1118789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1119789Sahrens 11202082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11212082Seschrock "device is less than the minimum " 11222082Seschrock "size (%s)"), buf); 1123789Sahrens } 11242082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11252082Seschrock break; 11262082Seschrock 11272082Seschrock case ENOTSUP: 11282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11294527Sperrin "pool must be upgraded to add these vdevs")); 11302082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1131789Sahrens break; 1132789Sahrens 11333912Slling case EDOM: 11343912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11354527Sperrin "root pool can not have multiple vdevs" 11364527Sperrin " or separate logs")); 11373912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11383912Slling break; 11393912Slling 11405450Sbrendan case ENOTBLK: 11415450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11425450Sbrendan "cache device must be a disk or disk slice")); 11435450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11445450Sbrendan break; 11455450Sbrendan 1146789Sahrens default: 11472082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1148789Sahrens } 1149789Sahrens 11502082Seschrock ret = -1; 11512082Seschrock } else { 11522082Seschrock ret = 0; 1153789Sahrens } 1154789Sahrens 11552676Seschrock zcmd_free_nvlists(&zc); 1156789Sahrens 11572082Seschrock return (ret); 1158789Sahrens } 1159789Sahrens 1160789Sahrens /* 1161789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1162789Sahrens * mounted datasets in the pool. 1163789Sahrens */ 1164789Sahrens int 11658211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1166789Sahrens { 1167789Sahrens zfs_cmd_t zc = { 0 }; 11687214Slling char msg[1024]; 1169789Sahrens 1170789Sahrens if (zpool_remove_zvol_links(zhp) != 0) 1171789Sahrens return (-1); 1172789Sahrens 11737214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 11747214Slling "cannot export '%s'"), zhp->zpool_name); 11757214Slling 1176789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 11777214Slling zc.zc_cookie = force; 11788211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 11797214Slling 11807214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 11817214Slling switch (errno) { 11827214Slling case EXDEV: 11837214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 11847214Slling "use '-f' to override the following errors:\n" 11857214Slling "'%s' has an active shared spare which could be" 11867214Slling " used by other pools once '%s' is exported."), 11877214Slling zhp->zpool_name, zhp->zpool_name); 11887214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 11897214Slling msg)); 11907214Slling default: 11917214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 11927214Slling msg)); 11937214Slling } 11947214Slling } 11957214Slling 1196789Sahrens return (0); 1197789Sahrens } 1198789Sahrens 11998211SGeorge.Wilson@Sun.COM int 12008211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 12018211SGeorge.Wilson@Sun.COM { 12028211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12038211SGeorge.Wilson@Sun.COM } 12048211SGeorge.Wilson@Sun.COM 12058211SGeorge.Wilson@Sun.COM int 12068211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12078211SGeorge.Wilson@Sun.COM { 12088211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12098211SGeorge.Wilson@Sun.COM } 12108211SGeorge.Wilson@Sun.COM 1211789Sahrens /* 12125094Slling * zpool_import() is a contracted interface. Should be kept the same 12135094Slling * if possible. 12145094Slling * 12155094Slling * Applications should use zpool_import_props() to import a pool with 12165094Slling * new properties value to be set. 1217789Sahrens */ 1218789Sahrens int 12192082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12205094Slling char *altroot) 12215094Slling { 12225094Slling nvlist_t *props = NULL; 12235094Slling int ret; 12245094Slling 12255094Slling if (altroot != NULL) { 12265094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 12275094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12285094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12295094Slling newname)); 12305094Slling } 12315094Slling 12325094Slling if (nvlist_add_string(props, 12338084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 12348084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 12358084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 12365094Slling nvlist_free(props); 12375094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12385094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12395094Slling newname)); 12405094Slling } 12415094Slling } 12425094Slling 12436643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 12445094Slling if (props) 12455094Slling nvlist_free(props); 12465094Slling return (ret); 12475094Slling } 12485094Slling 12495094Slling /* 12505094Slling * Import the given pool using the known configuration and a list of 12515094Slling * properties to be set. The configuration should have come from 12525094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 12535094Slling * is imported with a different name. 12545094Slling */ 12555094Slling int 12565094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12576643Seschrock nvlist_t *props, boolean_t importfaulted) 1258789Sahrens { 12592676Seschrock zfs_cmd_t zc = { 0 }; 1260789Sahrens char *thename; 1261789Sahrens char *origname; 1262789Sahrens int ret; 12635094Slling char errbuf[1024]; 1264789Sahrens 1265789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1266789Sahrens &origname) == 0); 1267789Sahrens 12685094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 12695094Slling "cannot import pool '%s'"), origname); 12705094Slling 1271789Sahrens if (newname != NULL) { 12722082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 12733237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 12742082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12752082Seschrock newname)); 1276789Sahrens thename = (char *)newname; 1277789Sahrens } else { 1278789Sahrens thename = origname; 1279789Sahrens } 1280789Sahrens 12815094Slling if (props) { 12825094Slling uint64_t version; 12835094Slling 12845094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 12855094Slling &version) == 0); 12865094Slling 12877184Stimh if ((props = zpool_valid_proplist(hdl, origname, 12885320Slling props, version, B_TRUE, errbuf)) == NULL) { 12895094Slling return (-1); 12905320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 12915320Slling nvlist_free(props); 12925094Slling return (-1); 12935320Slling } 12945094Slling } 1295789Sahrens 1296789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1297789Sahrens 1298789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 12991544Seschrock &zc.zc_guid) == 0); 1300789Sahrens 13015320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 13025320Slling nvlist_free(props); 13032082Seschrock return (-1); 13045320Slling } 1305789Sahrens 13066643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1307789Sahrens ret = 0; 13084543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1309789Sahrens char desc[1024]; 1310789Sahrens if (newname == NULL) 1311789Sahrens (void) snprintf(desc, sizeof (desc), 1312789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1313789Sahrens thename); 1314789Sahrens else 1315789Sahrens (void) snprintf(desc, sizeof (desc), 1316789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1317789Sahrens origname, thename); 1318789Sahrens 1319789Sahrens switch (errno) { 13201544Seschrock case ENOTSUP: 13211544Seschrock /* 13221544Seschrock * Unsupported version. 13231544Seschrock */ 13242082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 13251544Seschrock break; 13261544Seschrock 13272174Seschrock case EINVAL: 13282174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 13292174Seschrock break; 13302174Seschrock 1331789Sahrens default: 13322082Seschrock (void) zpool_standard_error(hdl, errno, desc); 1333789Sahrens } 1334789Sahrens 1335789Sahrens ret = -1; 1336789Sahrens } else { 1337789Sahrens zpool_handle_t *zhp; 13384543Smarks 1339789Sahrens /* 1340789Sahrens * This should never fail, but play it safe anyway. 1341789Sahrens */ 13422142Seschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 13432142Seschrock ret = -1; 13442142Seschrock } else if (zhp != NULL) { 1345789Sahrens ret = zpool_create_zvol_links(zhp); 1346789Sahrens zpool_close(zhp); 1347789Sahrens } 13484543Smarks 1349789Sahrens } 1350789Sahrens 13512676Seschrock zcmd_free_nvlists(&zc); 13525320Slling nvlist_free(props); 13535320Slling 1354789Sahrens return (ret); 1355789Sahrens } 1356789Sahrens 1357789Sahrens /* 1358789Sahrens * Scrub the pool. 1359789Sahrens */ 1360789Sahrens int 1361789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1362789Sahrens { 1363789Sahrens zfs_cmd_t zc = { 0 }; 1364789Sahrens char msg[1024]; 13652082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1366789Sahrens 1367789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1368789Sahrens zc.zc_cookie = type; 1369789Sahrens 13704543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1371789Sahrens return (0); 1372789Sahrens 1373789Sahrens (void) snprintf(msg, sizeof (msg), 1374789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1375789Sahrens 13762082Seschrock if (errno == EBUSY) 13772082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 13782082Seschrock else 13792082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1380789Sahrens } 1381789Sahrens 13822468Sek110237 /* 1383*9816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 1384*9816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 13852468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 13862468Sek110237 * spare; but FALSE if its an INUSE spare. 13872468Sek110237 */ 13882082Seschrock static nvlist_t * 1389*9816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 1390*9816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 13911544Seschrock { 13921544Seschrock uint_t c, children; 13931544Seschrock nvlist_t **child; 13942082Seschrock nvlist_t *ret; 13957326SEric.Schrock@Sun.COM uint64_t is_log; 1396*9816SGeorge.Wilson@Sun.COM char *srchkey; 1397*9816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 1398*9816SGeorge.Wilson@Sun.COM 1399*9816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 1400*9816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 1401*9816SGeorge.Wilson@Sun.COM return (NULL); 1402*9816SGeorge.Wilson@Sun.COM 1403*9816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 1404*9816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 1405*9816SGeorge.Wilson@Sun.COM 1406*9816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 1407*9816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 1408*9816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 1409*9816SGeorge.Wilson@Sun.COM 1410*9816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 1411*9816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 1412*9816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1413*9816SGeorge.Wilson@Sun.COM &present) == 0) { 1414*9816SGeorge.Wilson@Sun.COM /* 1415*9816SGeorge.Wilson@Sun.COM * If the device has never been present since 1416*9816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 1417*9816SGeorge.Wilson@Sun.COM * vdev is by GUID. 1418*9816SGeorge.Wilson@Sun.COM */ 1419*9816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 1420*9816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 1421*9816SGeorge.Wilson@Sun.COM if (theguid == srchval) 1422*9816SGeorge.Wilson@Sun.COM return (nv); 1423*9816SGeorge.Wilson@Sun.COM } 1424*9816SGeorge.Wilson@Sun.COM } 1425*9816SGeorge.Wilson@Sun.COM break; 1426*9816SGeorge.Wilson@Sun.COM } 1427*9816SGeorge.Wilson@Sun.COM 1428*9816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 1429*9816SGeorge.Wilson@Sun.COM char *srchval, *val; 1430*9816SGeorge.Wilson@Sun.COM 1431*9816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 1432*9816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 1433*9816SGeorge.Wilson@Sun.COM break; 1434*9816SGeorge.Wilson@Sun.COM 14351544Seschrock /* 1436*9816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 1437*9816SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk. Otherwise, 1438*9816SGeorge.Wilson@Sun.COM * all other searches are simple string compares. 14391544Seschrock */ 1440*9816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 1441*9816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 1442*9816SGeorge.Wilson@Sun.COM 1443*9816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1444*9816SGeorge.Wilson@Sun.COM &wholedisk); 1445*9816SGeorge.Wilson@Sun.COM if (wholedisk) { 1446*9816SGeorge.Wilson@Sun.COM /* 1447*9816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 1448*9816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 1449*9816SGeorge.Wilson@Sun.COM */ 1450*9816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 1451*9816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 1452*9816SGeorge.Wilson@Sun.COM return (nv); 1453*9816SGeorge.Wilson@Sun.COM break; 1454*9816SGeorge.Wilson@Sun.COM } 1455*9816SGeorge.Wilson@Sun.COM } 1456*9816SGeorge.Wilson@Sun.COM 1457*9816SGeorge.Wilson@Sun.COM /* 1458*9816SGeorge.Wilson@Sun.COM * Common case 1459*9816SGeorge.Wilson@Sun.COM */ 1460*9816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 14612082Seschrock return (nv); 1462*9816SGeorge.Wilson@Sun.COM break; 1463*9816SGeorge.Wilson@Sun.COM } 1464*9816SGeorge.Wilson@Sun.COM 1465*9816SGeorge.Wilson@Sun.COM default: 1466*9816SGeorge.Wilson@Sun.COM break; 14671544Seschrock } 14681544Seschrock 14691544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 14701544Seschrock &child, &children) != 0) 14712082Seschrock return (NULL); 14721544Seschrock 14737326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 1474*9816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 14757326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 14767326SEric.Schrock@Sun.COM /* 14777326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 14787326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 14797326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 14807326SEric.Schrock@Sun.COM * 'log' is non-NULL). 14817326SEric.Schrock@Sun.COM */ 14827326SEric.Schrock@Sun.COM if (log != NULL && 14837326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 14847326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 14857326SEric.Schrock@Sun.COM is_log) { 14867326SEric.Schrock@Sun.COM *log = B_TRUE; 14877326SEric.Schrock@Sun.COM } 14881544Seschrock return (ret); 14897326SEric.Schrock@Sun.COM } 14907326SEric.Schrock@Sun.COM } 14911544Seschrock 14922082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 14932082Seschrock &child, &children) == 0) { 14942082Seschrock for (c = 0; c < children; c++) { 1495*9816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 14967326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 14972468Sek110237 *avail_spare = B_TRUE; 14982082Seschrock return (ret); 14992082Seschrock } 15002082Seschrock } 15012082Seschrock } 15022082Seschrock 15035450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 15045450Sbrendan &child, &children) == 0) { 15055450Sbrendan for (c = 0; c < children; c++) { 1506*9816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15077326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15085450Sbrendan *l2cache = B_TRUE; 15095450Sbrendan return (ret); 15105450Sbrendan } 15115450Sbrendan } 15125450Sbrendan } 15135450Sbrendan 15142082Seschrock return (NULL); 15151544Seschrock } 15161544Seschrock 1517*9816SGeorge.Wilson@Sun.COM /* 1518*9816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 1519*9816SGeorge.Wilson@Sun.COM * associated vdev. 1520*9816SGeorge.Wilson@Sun.COM */ 1521*9816SGeorge.Wilson@Sun.COM nvlist_t * 1522*9816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 1523*9816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 1524*9816SGeorge.Wilson@Sun.COM { 1525*9816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 1526*9816SGeorge.Wilson@Sun.COM 1527*9816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1528*9816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 1529*9816SGeorge.Wilson@Sun.COM 1530*9816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1531*9816SGeorge.Wilson@Sun.COM &nvroot) == 0); 1532*9816SGeorge.Wilson@Sun.COM 1533*9816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 1534*9816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1535*9816SGeorge.Wilson@Sun.COM nvlist_free(search); 1536*9816SGeorge.Wilson@Sun.COM 1537*9816SGeorge.Wilson@Sun.COM return (ret); 1538*9816SGeorge.Wilson@Sun.COM } 1539*9816SGeorge.Wilson@Sun.COM 15402082Seschrock nvlist_t * 15415450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 15427326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 15431544Seschrock { 15441544Seschrock char buf[MAXPATHLEN]; 15451544Seschrock char *end; 1546*9816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 15471544Seschrock uint64_t guid; 15481544Seschrock 1549*9816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1550*9816SGeorge.Wilson@Sun.COM 15511613Seschrock guid = strtoull(path, &end, 10); 15521544Seschrock if (guid != 0 && *end == '\0') { 1553*9816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 15541544Seschrock } else if (path[0] != '/') { 15551544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 1556*9816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 15571544Seschrock } else { 1558*9816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 15591544Seschrock } 15601544Seschrock 15611544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 15621544Seschrock &nvroot) == 0); 15631544Seschrock 15642468Sek110237 *avail_spare = B_FALSE; 15655450Sbrendan *l2cache = B_FALSE; 15667326SEric.Schrock@Sun.COM if (log != NULL) 15677326SEric.Schrock@Sun.COM *log = B_FALSE; 1568*9816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1569*9816SGeorge.Wilson@Sun.COM nvlist_free(search); 1570*9816SGeorge.Wilson@Sun.COM 1571*9816SGeorge.Wilson@Sun.COM return (ret); 15722468Sek110237 } 15732468Sek110237 15747656SSherry.Moore@Sun.COM static int 15757656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 15767656SSherry.Moore@Sun.COM { 15777656SSherry.Moore@Sun.COM uint64_t ival; 15787656SSherry.Moore@Sun.COM 15797656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 15807656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 15817656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 15827656SSherry.Moore@Sun.COM return (0); 15837656SSherry.Moore@Sun.COM 15847656SSherry.Moore@Sun.COM return (1); 15857656SSherry.Moore@Sun.COM } 15867656SSherry.Moore@Sun.COM 15877656SSherry.Moore@Sun.COM /* 15889790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 15897656SSherry.Moore@Sun.COM */ 15909160SSherry.Moore@Sun.COM static int 15919790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 15929160SSherry.Moore@Sun.COM size_t *bytes_written) 15937656SSherry.Moore@Sun.COM { 15949160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 15959160SSherry.Moore@Sun.COM char *tmppath; 15969160SSherry.Moore@Sun.COM const char *format; 15979160SSherry.Moore@Sun.COM 15989160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 15999160SSherry.Moore@Sun.COM &tmppath) != 0) 16009160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 16019160SSherry.Moore@Sun.COM 16029160SSherry.Moore@Sun.COM pos = *bytes_written; 16039160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 16049160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 16059160SSherry.Moore@Sun.COM 16069160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 16079160SSherry.Moore@Sun.COM *bytes_written += rsz; 16089160SSherry.Moore@Sun.COM 16099160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 16109160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 16119160SSherry.Moore@Sun.COM if (bytes_left != 0) { 16129160SSherry.Moore@Sun.COM physpath[pos] = 0; 16139160SSherry.Moore@Sun.COM } 16149160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 16159160SSherry.Moore@Sun.COM } 16169160SSherry.Moore@Sun.COM return (0); 16179160SSherry.Moore@Sun.COM } 16189160SSherry.Moore@Sun.COM 16199790SLin.Ling@Sun.COM static int 16209790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 16219790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 16229790SLin.Ling@Sun.COM { 16239790SLin.Ling@Sun.COM char *type; 16249790SLin.Ling@Sun.COM int ret; 16259790SLin.Ling@Sun.COM 16269790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 16279790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16289790SLin.Ling@Sun.COM 16299790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 16309790SLin.Ling@Sun.COM /* 16319790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 16329790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 16339790SLin.Ling@Sun.COM * spare device. 16349790SLin.Ling@Sun.COM */ 16359790SLin.Ling@Sun.COM if (is_spare) { 16369790SLin.Ling@Sun.COM uint64_t spare = 0; 16379790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 16389790SLin.Ling@Sun.COM &spare); 16399790SLin.Ling@Sun.COM if (!spare) 16409790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16419790SLin.Ling@Sun.COM } 16429790SLin.Ling@Sun.COM 16439790SLin.Ling@Sun.COM if (vdev_online(nv)) { 16449790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 16459790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 16469790SLin.Ling@Sun.COM return (ret); 16479790SLin.Ling@Sun.COM } 16489790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 16499790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 16509790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 16519790SLin.Ling@Sun.COM nvlist_t **child; 16529790SLin.Ling@Sun.COM uint_t count; 16539790SLin.Ling@Sun.COM int i, ret; 16549790SLin.Ling@Sun.COM 16559790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 16569790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 16579790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16589790SLin.Ling@Sun.COM 16599790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 16609790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 16619790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 16629790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 16639790SLin.Ling@Sun.COM return (ret); 16649790SLin.Ling@Sun.COM } 16659790SLin.Ling@Sun.COM } 16669790SLin.Ling@Sun.COM 16679790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 16689790SLin.Ling@Sun.COM } 16699790SLin.Ling@Sun.COM 16709160SSherry.Moore@Sun.COM /* 16719160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 16729160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 16739160SSherry.Moore@Sun.COM */ 16749160SSherry.Moore@Sun.COM static int 16759160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 16769160SSherry.Moore@Sun.COM { 16779160SSherry.Moore@Sun.COM size_t rsz; 16787656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 16797656SSherry.Moore@Sun.COM nvlist_t **child; 16807656SSherry.Moore@Sun.COM uint_t count; 16819160SSherry.Moore@Sun.COM char *type; 16829160SSherry.Moore@Sun.COM 16839160SSherry.Moore@Sun.COM rsz = 0; 16849160SSherry.Moore@Sun.COM 16859160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 16869160SSherry.Moore@Sun.COM &vdev_root) != 0) 16879160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 16889160SSherry.Moore@Sun.COM 16899160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 16909160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 16919160SSherry.Moore@Sun.COM &child, &count) != 0) 16929160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 16937656SSherry.Moore@Sun.COM 16947656SSherry.Moore@Sun.COM /* 16959160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 16969160SSherry.Moore@Sun.COM * a single top-level vdev. 16977656SSherry.Moore@Sun.COM */ 16989160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 16999160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 17009160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 17019160SSherry.Moore@Sun.COM 17029790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 17039790SLin.Ling@Sun.COM B_FALSE); 17047656SSherry.Moore@Sun.COM 17059160SSherry.Moore@Sun.COM /* No online devices */ 17069160SSherry.Moore@Sun.COM if (rsz == 0) 17079160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 17089160SSherry.Moore@Sun.COM 17097656SSherry.Moore@Sun.COM return (0); 17107656SSherry.Moore@Sun.COM } 17117656SSherry.Moore@Sun.COM 17122468Sek110237 /* 17139160SSherry.Moore@Sun.COM * Get phys_path for a root pool 17149160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 17159160SSherry.Moore@Sun.COM */ 17169160SSherry.Moore@Sun.COM int 17179160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 17189160SSherry.Moore@Sun.COM { 17199160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 17209160SSherry.Moore@Sun.COM phypath_size)); 17219160SSherry.Moore@Sun.COM } 17229160SSherry.Moore@Sun.COM 17239160SSherry.Moore@Sun.COM /* 17245450Sbrendan * Returns TRUE if the given guid corresponds to the given type. 17255450Sbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 17265450Sbrendan * devices. 17272468Sek110237 */ 17282468Sek110237 static boolean_t 17295450Sbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 17302468Sek110237 { 17315450Sbrendan uint64_t target_guid; 17322468Sek110237 nvlist_t *nvroot; 17335450Sbrendan nvlist_t **list; 17345450Sbrendan uint_t count; 17352468Sek110237 int i; 17362468Sek110237 17372468Sek110237 verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 17382468Sek110237 &nvroot) == 0); 17395450Sbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 17405450Sbrendan for (i = 0; i < count; i++) { 17415450Sbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 17425450Sbrendan &target_guid) == 0); 17435450Sbrendan if (guid == target_guid) 17442468Sek110237 return (B_TRUE); 17452468Sek110237 } 17462468Sek110237 } 17472468Sek110237 17482468Sek110237 return (B_FALSE); 17491544Seschrock } 17501544Seschrock 1751789Sahrens /* 1752*9816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 1753*9816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 1754*9816SGeorge.Wilson@Sun.COM */ 1755*9816SGeorge.Wilson@Sun.COM static int 1756*9816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 1757*9816SGeorge.Wilson@Sun.COM { 1758*9816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 1759*9816SGeorge.Wilson@Sun.COM char errbuf[1024]; 1760*9816SGeorge.Wilson@Sun.COM int fd, error; 1761*9816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 1762*9816SGeorge.Wilson@Sun.COM 1763*9816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 1764*9816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 1765*9816SGeorge.Wilson@Sun.COM return (-1); 1766*9816SGeorge.Wilson@Sun.COM 1767*9816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 1768*9816SGeorge.Wilson@Sun.COM 1769*9816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 1770*9816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 1771*9816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 1772*9816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 1773*9816SGeorge.Wilson@Sun.COM } 1774*9816SGeorge.Wilson@Sun.COM 1775*9816SGeorge.Wilson@Sun.COM /* 1776*9816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 1777*9816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 1778*9816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 1779*9816SGeorge.Wilson@Sun.COM */ 1780*9816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 1781*9816SGeorge.Wilson@Sun.COM (void) close(fd); 1782*9816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 1783*9816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 1784*9816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 1785*9816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 1786*9816SGeorge.Wilson@Sun.COM } 1787*9816SGeorge.Wilson@Sun.COM return (0); 1788*9816SGeorge.Wilson@Sun.COM } 1789*9816SGeorge.Wilson@Sun.COM 1790*9816SGeorge.Wilson@Sun.COM /* 17914451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 17924451Seschrock * ZFS_ONLINE_* flags. 1793789Sahrens */ 1794789Sahrens int 17954451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 17964451Seschrock vdev_state_t *newstate) 1797789Sahrens { 1798789Sahrens zfs_cmd_t zc = { 0 }; 1799789Sahrens char msg[1024]; 18002082Seschrock nvlist_t *tgt; 1801*9816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 18022082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1803789Sahrens 1804*9816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 1805*9816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 1806*9816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 1807*9816SGeorge.Wilson@Sun.COM } else { 1808*9816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 1809*9816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 1810*9816SGeorge.Wilson@Sun.COM } 1811789Sahrens 18121544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 18137326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1814*9816SGeorge.Wilson@Sun.COM &islog)) == NULL) 18152082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1816789Sahrens 18172468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 18182468Sek110237 18195450Sbrendan if (avail_spare || 18205450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 18212082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 18222082Seschrock 1823*9816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 1824*9816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 1825*9816SGeorge.Wilson@Sun.COM char *pathname = NULL; 1826*9816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 1827*9816SGeorge.Wilson@Sun.COM 1828*9816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 1829*9816SGeorge.Wilson@Sun.COM &wholedisk); 1830*9816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 1831*9816SGeorge.Wilson@Sun.COM &pathname) == 0); 1832*9816SGeorge.Wilson@Sun.COM 1833*9816SGeorge.Wilson@Sun.COM /* 1834*9816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 1835*9816SGeorge.Wilson@Sun.COM */ 1836*9816SGeorge.Wilson@Sun.COM if (l2cache) { 1837*9816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1838*9816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 1839*9816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 1840*9816SGeorge.Wilson@Sun.COM } 1841*9816SGeorge.Wilson@Sun.COM 1842*9816SGeorge.Wilson@Sun.COM if (wholedisk) { 1843*9816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 1844*9816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 1845*9816SGeorge.Wilson@Sun.COM } 1846*9816SGeorge.Wilson@Sun.COM } 1847*9816SGeorge.Wilson@Sun.COM 18484451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 18494451Seschrock zc.zc_obj = flags; 18504451Seschrock 18514543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 18524451Seschrock return (zpool_standard_error(hdl, errno, msg)); 18534451Seschrock 18544451Seschrock *newstate = zc.zc_cookie; 18554451Seschrock return (0); 1856789Sahrens } 1857789Sahrens 1858789Sahrens /* 1859789Sahrens * Take the specified vdev offline 1860789Sahrens */ 1861789Sahrens int 18624451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1863789Sahrens { 1864789Sahrens zfs_cmd_t zc = { 0 }; 1865789Sahrens char msg[1024]; 18662082Seschrock nvlist_t *tgt; 18675450Sbrendan boolean_t avail_spare, l2cache; 18682082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1869789Sahrens 18701544Seschrock (void) snprintf(msg, sizeof (msg), 18711544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 18721544Seschrock 1873789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 18747326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 18757326SEric.Schrock@Sun.COM NULL)) == NULL) 18762082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 18772082Seschrock 18782468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 18792468Sek110237 18805450Sbrendan if (avail_spare || 18815450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 18822082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 18832082Seschrock 18844451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 18854451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 18861485Slling 18874543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1888789Sahrens return (0); 1889789Sahrens 1890789Sahrens switch (errno) { 18912082Seschrock case EBUSY: 1892789Sahrens 1893789Sahrens /* 1894789Sahrens * There are no other replicas of this device. 1895789Sahrens */ 18962082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 18972082Seschrock 18989701SGeorge.Wilson@Sun.COM case EEXIST: 18999701SGeorge.Wilson@Sun.COM /* 19009701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 19019701SGeorge.Wilson@Sun.COM */ 19029701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 19039701SGeorge.Wilson@Sun.COM 19042082Seschrock default: 19052082Seschrock return (zpool_standard_error(hdl, errno, msg)); 19062082Seschrock } 19072082Seschrock } 1908789Sahrens 19092082Seschrock /* 19104451Seschrock * Mark the given vdev faulted. 19114451Seschrock */ 19124451Seschrock int 19134451Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 19144451Seschrock { 19154451Seschrock zfs_cmd_t zc = { 0 }; 19164451Seschrock char msg[1024]; 19174451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19184451Seschrock 19194451Seschrock (void) snprintf(msg, sizeof (msg), 19204451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 19214451Seschrock 19224451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19234451Seschrock zc.zc_guid = guid; 19244451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 19254451Seschrock 19264451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19274451Seschrock return (0); 19284451Seschrock 19294451Seschrock switch (errno) { 19304451Seschrock case EBUSY: 19314451Seschrock 19324451Seschrock /* 19334451Seschrock * There are no other replicas of this device. 19344451Seschrock */ 19354451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 19364451Seschrock 19374451Seschrock default: 19384451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19394451Seschrock } 19404451Seschrock 19414451Seschrock } 19424451Seschrock 19434451Seschrock /* 19444451Seschrock * Mark the given vdev degraded. 19454451Seschrock */ 19464451Seschrock int 19474451Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 19484451Seschrock { 19494451Seschrock zfs_cmd_t zc = { 0 }; 19504451Seschrock char msg[1024]; 19514451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19524451Seschrock 19534451Seschrock (void) snprintf(msg, sizeof (msg), 19544451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 19554451Seschrock 19564451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19574451Seschrock zc.zc_guid = guid; 19584451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 19594451Seschrock 19604451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19614451Seschrock return (0); 19624451Seschrock 19634451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19644451Seschrock } 19654451Seschrock 19664451Seschrock /* 19672082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 19682082Seschrock * a hot spare. 19692082Seschrock */ 19702082Seschrock static boolean_t 19712082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 19722082Seschrock { 19732082Seschrock nvlist_t **child; 19742082Seschrock uint_t c, children; 19752082Seschrock char *type; 19762082Seschrock 19772082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 19782082Seschrock &children) == 0) { 19792082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 19802082Seschrock &type) == 0); 19812082Seschrock 19822082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 19832082Seschrock children == 2 && child[which] == tgt) 19842082Seschrock return (B_TRUE); 19852082Seschrock 19862082Seschrock for (c = 0; c < children; c++) 19872082Seschrock if (is_replacing_spare(child[c], tgt, which)) 19882082Seschrock return (B_TRUE); 1989789Sahrens } 19902082Seschrock 19912082Seschrock return (B_FALSE); 1992789Sahrens } 1993789Sahrens 1994789Sahrens /* 1995789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 19964527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 1997789Sahrens */ 1998789Sahrens int 1999789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2000789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2001789Sahrens { 2002789Sahrens zfs_cmd_t zc = { 0 }; 2003789Sahrens char msg[1024]; 2004789Sahrens int ret; 20052082Seschrock nvlist_t *tgt; 20067326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 20077326SEric.Schrock@Sun.COM uint64_t val; 20087041Seschrock char *path, *newname; 20092082Seschrock nvlist_t **child; 20102082Seschrock uint_t children; 20112082Seschrock nvlist_t *config_root; 20122082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 20137965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2014789Sahrens 20151544Seschrock if (replacing) 20161544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20171544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 20181544Seschrock else 20191544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20201544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 20211544Seschrock 20227965SGeorge.Wilson@Sun.COM /* 20237965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 20247965SGeorge.Wilson@Sun.COM * EFI labeled device. 20257965SGeorge.Wilson@Sun.COM */ 20267965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 20277965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20287965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 20297965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 20307965SGeorge.Wilson@Sun.COM } 20317965SGeorge.Wilson@Sun.COM 2032789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20337326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 20347326SEric.Schrock@Sun.COM &islog)) == 0) 20352082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 20362082Seschrock 20372468Sek110237 if (avail_spare) 20382082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20392082Seschrock 20405450Sbrendan if (l2cache) 20415450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 20425450Sbrendan 20432082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20442082Seschrock zc.zc_cookie = replacing; 20452082Seschrock 20462082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 20472082Seschrock &child, &children) != 0 || children != 1) { 20482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20492082Seschrock "new device must be a single disk")); 20502082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 20511544Seschrock } 20522082Seschrock 20532082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 20542082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 20552082Seschrock 20567041Seschrock if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL) 20577041Seschrock return (-1); 20587041Seschrock 20592082Seschrock /* 20602082Seschrock * If the target is a hot spare that has been swapped in, we can only 20612082Seschrock * replace it with another hot spare. 20622082Seschrock */ 20632082Seschrock if (replacing && 20642082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 20657326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 20667326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 20677326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 20682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20692082Seschrock "can only be replaced by another hot spare")); 20707041Seschrock free(newname); 20712082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 20722082Seschrock } 20732082Seschrock 20742082Seschrock /* 20752082Seschrock * If we are attempting to replace a spare, it canot be applied to an 20762082Seschrock * already spared device. 20772082Seschrock */ 20782082Seschrock if (replacing && 20792082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 20807326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 20817326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 20827326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 20832082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20842082Seschrock "device has already been replaced with a spare")); 20857041Seschrock free(newname); 20862082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 20872082Seschrock } 2088789Sahrens 20897041Seschrock free(newname); 20907041Seschrock 20915094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 20922082Seschrock return (-1); 2093789Sahrens 20944543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2095789Sahrens 20962676Seschrock zcmd_free_nvlists(&zc); 2097789Sahrens 20987965SGeorge.Wilson@Sun.COM if (ret == 0) { 20997965SGeorge.Wilson@Sun.COM if (rootpool) { 21007965SGeorge.Wilson@Sun.COM /* 21017965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 21027965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 21037965SGeorge.Wilson@Sun.COM * newly attached disk. 21047965SGeorge.Wilson@Sun.COM */ 21057965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 21067965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 21077965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 21089790SLin.Ling@Sun.COM 21099790SLin.Ling@Sun.COM /* 21109790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 21119790SLin.Ling@Sun.COM * booting up a half-baked vdev. 21129790SLin.Ling@Sun.COM */ 21139790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 21149790SLin.Ling@Sun.COM "sure to wait until resilver is done " 21159790SLin.Ling@Sun.COM "before rebooting.\n")); 21167965SGeorge.Wilson@Sun.COM } 2117789Sahrens return (0); 21187965SGeorge.Wilson@Sun.COM } 2119789Sahrens 2120789Sahrens switch (errno) { 21211544Seschrock case ENOTSUP: 2122789Sahrens /* 2123789Sahrens * Can't attach to or replace this type of vdev. 2124789Sahrens */ 21254527Sperrin if (replacing) { 21267326SEric.Schrock@Sun.COM if (islog) 21274527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21284527Sperrin "cannot replace a log with a spare")); 21294527Sperrin else 21304527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21314527Sperrin "cannot replace a replacing device")); 21324527Sperrin } else { 21332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21342082Seschrock "can only attach to mirrors and top-level " 21352082Seschrock "disks")); 21364527Sperrin } 21372082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2138789Sahrens break; 2139789Sahrens 21401544Seschrock case EINVAL: 2141789Sahrens /* 2142789Sahrens * The new device must be a single disk. 2143789Sahrens */ 21442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21452082Seschrock "new device must be a single disk")); 21462082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2147789Sahrens break; 2148789Sahrens 21491544Seschrock case EBUSY: 21502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 21512082Seschrock new_disk); 21522082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2153789Sahrens break; 2154789Sahrens 21551544Seschrock case EOVERFLOW: 2156789Sahrens /* 2157789Sahrens * The new device is too small. 2158789Sahrens */ 21592082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21602082Seschrock "device is too small")); 21612082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2162789Sahrens break; 2163789Sahrens 21641544Seschrock case EDOM: 2165789Sahrens /* 2166789Sahrens * The new device has a different alignment requirement. 2167789Sahrens */ 21682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21692082Seschrock "devices have different sector alignment")); 21702082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2171789Sahrens break; 2172789Sahrens 21731544Seschrock case ENAMETOOLONG: 2174789Sahrens /* 2175789Sahrens * The resulting top-level vdev spec won't fit in the label. 2176789Sahrens */ 21772082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2178789Sahrens break; 2179789Sahrens 21801544Seschrock default: 21812082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2182789Sahrens } 2183789Sahrens 21842082Seschrock return (-1); 2185789Sahrens } 2186789Sahrens 2187789Sahrens /* 2188789Sahrens * Detach the specified device. 2189789Sahrens */ 2190789Sahrens int 2191789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2192789Sahrens { 2193789Sahrens zfs_cmd_t zc = { 0 }; 2194789Sahrens char msg[1024]; 21952082Seschrock nvlist_t *tgt; 21965450Sbrendan boolean_t avail_spare, l2cache; 21972082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2198789Sahrens 21991544Seschrock (void) snprintf(msg, sizeof (msg), 22001544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 22011544Seschrock 2202789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22037326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22047326SEric.Schrock@Sun.COM NULL)) == 0) 22052082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2206789Sahrens 22072468Sek110237 if (avail_spare) 22082082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22092082Seschrock 22105450Sbrendan if (l2cache) 22115450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 22125450Sbrendan 22132082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22142082Seschrock 22154543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2216789Sahrens return (0); 2217789Sahrens 2218789Sahrens switch (errno) { 2219789Sahrens 22201544Seschrock case ENOTSUP: 2221789Sahrens /* 2222789Sahrens * Can't detach from this type of vdev. 2223789Sahrens */ 22242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 22252082Seschrock "applicable to mirror and replacing vdevs")); 22262082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2227789Sahrens break; 2228789Sahrens 22291544Seschrock case EBUSY: 2230789Sahrens /* 2231789Sahrens * There are no other replicas of this device. 2232789Sahrens */ 22332082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2234789Sahrens break; 2235789Sahrens 22361544Seschrock default: 22372082Seschrock (void) zpool_standard_error(hdl, errno, msg); 22381544Seschrock } 22391544Seschrock 22402082Seschrock return (-1); 22412082Seschrock } 22422082Seschrock 22432082Seschrock /* 22445450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 22455450Sbrendan * and level 2 cache devices. 22462082Seschrock */ 22472082Seschrock int 22482082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 22492082Seschrock { 22502082Seschrock zfs_cmd_t zc = { 0 }; 22512082Seschrock char msg[1024]; 22522082Seschrock nvlist_t *tgt; 22535450Sbrendan boolean_t avail_spare, l2cache; 22542082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22552082Seschrock 22562082Seschrock (void) snprintf(msg, sizeof (msg), 22572082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 22582082Seschrock 22592082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22607326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22617326SEric.Schrock@Sun.COM NULL)) == 0) 22622082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22632082Seschrock 22645450Sbrendan if (!avail_spare && !l2cache) { 22652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22665450Sbrendan "only inactive hot spares or cache devices " 22675450Sbrendan "can be removed")); 22682082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22692082Seschrock } 22702082Seschrock 22712082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22722082Seschrock 22734543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 22742082Seschrock return (0); 22752082Seschrock 22762082Seschrock return (zpool_standard_error(hdl, errno, msg)); 22771544Seschrock } 22781544Seschrock 22791544Seschrock /* 22801544Seschrock * Clear the errors for the pool, or the particular device if specified. 22811544Seschrock */ 22821544Seschrock int 22831544Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 22841544Seschrock { 22851544Seschrock zfs_cmd_t zc = { 0 }; 22861544Seschrock char msg[1024]; 22872082Seschrock nvlist_t *tgt; 22885450Sbrendan boolean_t avail_spare, l2cache; 22892082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22901544Seschrock 22911544Seschrock if (path) 22921544Seschrock (void) snprintf(msg, sizeof (msg), 22931544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 22942676Seschrock path); 22951544Seschrock else 22961544Seschrock (void) snprintf(msg, sizeof (msg), 22971544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 22981544Seschrock zhp->zpool_name); 22991544Seschrock 23001544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23012082Seschrock if (path) { 23025450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 23037326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 23042082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23052082Seschrock 23065450Sbrendan /* 23075450Sbrendan * Don't allow error clearing for hot spares. Do allow 23085450Sbrendan * error clearing for l2cache devices. 23095450Sbrendan */ 23102468Sek110237 if (avail_spare) 23112082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 23122082Seschrock 23132082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 23142082Seschrock &zc.zc_guid) == 0); 23151544Seschrock } 23161544Seschrock 23174543Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 23181544Seschrock return (0); 23191544Seschrock 23202082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2321789Sahrens } 2322789Sahrens 23233126Sahl /* 23244451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 23254451Seschrock */ 23264451Seschrock int 23274451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 23284451Seschrock { 23294451Seschrock zfs_cmd_t zc = { 0 }; 23304451Seschrock char msg[1024]; 23314451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23324451Seschrock 23334451Seschrock (void) snprintf(msg, sizeof (msg), 23344451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 23354451Seschrock guid); 23364451Seschrock 23374451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23384451Seschrock zc.zc_guid = guid; 23394451Seschrock 23404451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 23414451Seschrock return (0); 23424451Seschrock 23434451Seschrock return (zpool_standard_error(hdl, errno, msg)); 23444451Seschrock } 23454451Seschrock 23464451Seschrock /* 23473126Sahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 23483126Sahl * hierarchy. 23493126Sahl */ 23503126Sahl int 23513126Sahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 23523126Sahl void *data) 2353789Sahrens { 23543126Sahl libzfs_handle_t *hdl = zhp->zpool_hdl; 23553126Sahl char (*paths)[MAXPATHLEN]; 23563126Sahl size_t size = 4; 23573126Sahl int curr, fd, base, ret = 0; 23583126Sahl DIR *dirp; 23593126Sahl struct dirent *dp; 23603126Sahl struct stat st; 23613126Sahl 23623126Sahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 23633126Sahl return (errno == ENOENT ? 0 : -1); 23643126Sahl 23653126Sahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 23663126Sahl int err = errno; 23673126Sahl (void) close(base); 23683126Sahl return (err == ENOENT ? 0 : -1); 23693126Sahl } 2370789Sahrens 2371789Sahrens /* 23723126Sahl * Oddly this wasn't a directory -- ignore that failure since we 23733126Sahl * know there are no links lower in the (non-existant) hierarchy. 2374789Sahrens */ 23753126Sahl if (!S_ISDIR(st.st_mode)) { 23763126Sahl (void) close(base); 23773126Sahl return (0); 23783126Sahl } 23793126Sahl 23803126Sahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 23813126Sahl (void) close(base); 23823126Sahl return (-1); 2383789Sahrens } 2384789Sahrens 23853126Sahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 23863126Sahl curr = 0; 23873126Sahl 23883126Sahl while (curr >= 0) { 23893126Sahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 23903126Sahl goto err; 23913126Sahl 23923126Sahl if (S_ISDIR(st.st_mode)) { 23933126Sahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 23943126Sahl goto err; 23953126Sahl 23963126Sahl if ((dirp = fdopendir(fd)) == NULL) { 23973126Sahl (void) close(fd); 23983126Sahl goto err; 23993126Sahl } 24003126Sahl 24013126Sahl while ((dp = readdir(dirp)) != NULL) { 24023126Sahl if (dp->d_name[0] == '.') 24033126Sahl continue; 24043126Sahl 24053126Sahl if (curr + 1 == size) { 24063126Sahl paths = zfs_realloc(hdl, paths, 24073126Sahl size * sizeof (paths[0]), 24083126Sahl size * 2 * sizeof (paths[0])); 24093126Sahl if (paths == NULL) { 24103126Sahl (void) closedir(dirp); 24113126Sahl (void) close(fd); 24123126Sahl goto err; 24133126Sahl } 24143126Sahl 24153126Sahl size *= 2; 24163126Sahl } 24173126Sahl 24183126Sahl (void) strlcpy(paths[curr + 1], paths[curr], 24193126Sahl sizeof (paths[curr + 1])); 24203126Sahl (void) strlcat(paths[curr], "/", 24213126Sahl sizeof (paths[curr])); 24223126Sahl (void) strlcat(paths[curr], dp->d_name, 24233126Sahl sizeof (paths[curr])); 24243126Sahl curr++; 24253126Sahl } 24263126Sahl 24273126Sahl (void) closedir(dirp); 24283126Sahl 24293126Sahl } else { 24303126Sahl if ((ret = cb(paths[curr], data)) != 0) 24313126Sahl break; 24323126Sahl } 24333126Sahl 24343126Sahl curr--; 24353126Sahl } 24363126Sahl 24373126Sahl free(paths); 24383126Sahl (void) close(base); 24393126Sahl 24403126Sahl return (ret); 24413126Sahl 24423126Sahl err: 24433126Sahl free(paths); 24443126Sahl (void) close(base); 24453126Sahl return (-1); 24463126Sahl } 24473126Sahl 24483126Sahl typedef struct zvol_cb { 24493126Sahl zpool_handle_t *zcb_pool; 24503126Sahl boolean_t zcb_create; 24513126Sahl } zvol_cb_t; 24523126Sahl 24533126Sahl /*ARGSUSED*/ 24543126Sahl static int 24553126Sahl do_zvol_create(zfs_handle_t *zhp, void *data) 24563126Sahl { 24574657Sahrens int ret = 0; 24583126Sahl 24594657Sahrens if (ZFS_IS_VOLUME(zhp)) { 24603126Sahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 24614657Sahrens ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL); 24624657Sahrens } 24633126Sahl 24644657Sahrens if (ret == 0) 24654657Sahrens ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL); 2466789Sahrens 2467789Sahrens zfs_close(zhp); 24683126Sahl 2469789Sahrens return (ret); 2470789Sahrens } 2471789Sahrens 2472789Sahrens /* 2473789Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 2474789Sahrens */ 2475789Sahrens int 2476789Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 2477789Sahrens { 2478789Sahrens zfs_handle_t *zfp; 2479789Sahrens int ret; 2480789Sahrens 2481789Sahrens /* 2482789Sahrens * If the pool is unavailable, just return success. 2483789Sahrens */ 24842082Seschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 24852082Seschrock zhp->zpool_name)) == NULL) 2486789Sahrens return (0); 2487789Sahrens 24884657Sahrens ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL); 2489789Sahrens 2490789Sahrens zfs_close(zfp); 2491789Sahrens return (ret); 2492789Sahrens } 2493789Sahrens 24943126Sahl static int 24953126Sahl do_zvol_remove(const char *dataset, void *data) 24963126Sahl { 24973126Sahl zpool_handle_t *zhp = data; 24983126Sahl 24993126Sahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 25003126Sahl } 25013126Sahl 2502789Sahrens /* 25033126Sahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 25043126Sahl * by examining the /dev links so that a corrupted pool doesn't impede this 25053126Sahl * operation. 2506789Sahrens */ 2507789Sahrens int 2508789Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 2509789Sahrens { 25103126Sahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 2511789Sahrens } 25121354Seschrock 25131354Seschrock /* 25141354Seschrock * Convert from a devid string to a path. 25151354Seschrock */ 25161354Seschrock static char * 25171354Seschrock devid_to_path(char *devid_str) 25181354Seschrock { 25191354Seschrock ddi_devid_t devid; 25201354Seschrock char *minor; 25211354Seschrock char *path; 25221354Seschrock devid_nmlist_t *list = NULL; 25231354Seschrock int ret; 25241354Seschrock 25251354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 25261354Seschrock return (NULL); 25271354Seschrock 25281354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 25291354Seschrock 25301354Seschrock devid_str_free(minor); 25311354Seschrock devid_free(devid); 25321354Seschrock 25331354Seschrock if (ret != 0) 25341354Seschrock return (NULL); 25351354Seschrock 25362082Seschrock if ((path = strdup(list[0].devname)) == NULL) 25372082Seschrock return (NULL); 25382082Seschrock 25391354Seschrock devid_free_nmlist(list); 25401354Seschrock 25411354Seschrock return (path); 25421354Seschrock } 25431354Seschrock 25441354Seschrock /* 25451354Seschrock * Convert from a path to a devid string. 25461354Seschrock */ 25471354Seschrock static char * 25481354Seschrock path_to_devid(const char *path) 25491354Seschrock { 25501354Seschrock int fd; 25511354Seschrock ddi_devid_t devid; 25521354Seschrock char *minor, *ret; 25531354Seschrock 25541354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 25551354Seschrock return (NULL); 25561354Seschrock 25571354Seschrock minor = NULL; 25581354Seschrock ret = NULL; 25591354Seschrock if (devid_get(fd, &devid) == 0) { 25601354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 25611354Seschrock ret = devid_str_encode(devid, minor); 25621354Seschrock if (minor != NULL) 25631354Seschrock devid_str_free(minor); 25641354Seschrock devid_free(devid); 25651354Seschrock } 25661354Seschrock (void) close(fd); 25671354Seschrock 25681354Seschrock return (ret); 25691354Seschrock } 25701354Seschrock 25711354Seschrock /* 25721354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 25731354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 25741354Seschrock * type 'zpool status', and we'll display the correct information anyway. 25751354Seschrock */ 25761354Seschrock static void 25771354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 25781354Seschrock { 25791354Seschrock zfs_cmd_t zc = { 0 }; 25801354Seschrock 25811354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25822676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 25831354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 25841544Seschrock &zc.zc_guid) == 0); 25851354Seschrock 25862082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 25871354Seschrock } 25881354Seschrock 25891354Seschrock /* 25901354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 25911354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 25921354Seschrock * We also check if this is a whole disk, in which case we strip off the 25931354Seschrock * trailing 's0' slice name. 25941354Seschrock * 25951354Seschrock * This routine is also responsible for identifying when disks have been 25961354Seschrock * reconfigured in a new location. The kernel will have opened the device by 25971354Seschrock * devid, but the path will still refer to the old location. To catch this, we 25981354Seschrock * first do a path -> devid translation (which is fast for the common case). If 25991354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 26001354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 26011354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 26021354Seschrock * of these checks. 26031354Seschrock */ 26041354Seschrock char * 26052082Seschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 26061354Seschrock { 26071354Seschrock char *path, *devid; 26081544Seschrock uint64_t value; 26091544Seschrock char buf[64]; 26104451Seschrock vdev_stat_t *vs; 26114451Seschrock uint_t vsc; 26121354Seschrock 26131544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 26141544Seschrock &value) == 0) { 26151544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 26161544Seschrock &value) == 0); 26172856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 26182856Snd150628 (u_longlong_t)value); 26191544Seschrock path = buf; 26201544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 26211354Seschrock 26224451Seschrock /* 26234451Seschrock * If the device is dead (faulted, offline, etc) then don't 26244451Seschrock * bother opening it. Otherwise we may be forcing the user to 26254451Seschrock * open a misbehaving device, which can have undesirable 26264451Seschrock * effects. 26274451Seschrock */ 26284451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 26294451Seschrock (uint64_t **)&vs, &vsc) != 0 || 26304451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 26314451Seschrock zhp != NULL && 26321354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 26331354Seschrock /* 26341354Seschrock * Determine if the current path is correct. 26351354Seschrock */ 26361354Seschrock char *newdevid = path_to_devid(path); 26371354Seschrock 26381354Seschrock if (newdevid == NULL || 26391354Seschrock strcmp(devid, newdevid) != 0) { 26401354Seschrock char *newpath; 26411354Seschrock 26421354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 26431354Seschrock /* 26441354Seschrock * Update the path appropriately. 26451354Seschrock */ 26461354Seschrock set_path(zhp, nv, newpath); 26472082Seschrock if (nvlist_add_string(nv, 26482082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 26492082Seschrock verify(nvlist_lookup_string(nv, 26502082Seschrock ZPOOL_CONFIG_PATH, 26512082Seschrock &path) == 0); 26521354Seschrock free(newpath); 26531354Seschrock } 26541354Seschrock } 26551354Seschrock 26562082Seschrock if (newdevid) 26572082Seschrock devid_str_free(newdevid); 26581354Seschrock } 26591354Seschrock 26601354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 26611354Seschrock path += 9; 26621354Seschrock 26631354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 26641544Seschrock &value) == 0 && value) { 26652082Seschrock char *tmp = zfs_strdup(hdl, path); 26662082Seschrock if (tmp == NULL) 26672082Seschrock return (NULL); 26681354Seschrock tmp[strlen(path) - 2] = '\0'; 26691354Seschrock return (tmp); 26701354Seschrock } 26711354Seschrock } else { 26721354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 26732082Seschrock 26742082Seschrock /* 26752082Seschrock * If it's a raidz device, we need to stick in the parity level. 26762082Seschrock */ 26772082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 26782082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 26792082Seschrock &value) == 0); 26802082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 26812856Snd150628 (u_longlong_t)value); 26822082Seschrock path = buf; 26832082Seschrock } 26841354Seschrock } 26851354Seschrock 26862082Seschrock return (zfs_strdup(hdl, path)); 26871354Seschrock } 26881544Seschrock 26891544Seschrock static int 26901544Seschrock zbookmark_compare(const void *a, const void *b) 26911544Seschrock { 26921544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 26931544Seschrock } 26941544Seschrock 26951544Seschrock /* 26961544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 26971544Seschrock * caller. 26981544Seschrock */ 26991544Seschrock int 27003444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 27011544Seschrock { 27021544Seschrock zfs_cmd_t zc = { 0 }; 27031544Seschrock uint64_t count; 27042676Seschrock zbookmark_t *zb = NULL; 27053444Sek110237 int i; 27061544Seschrock 27071544Seschrock /* 27081544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 27091544Seschrock * has increased, allocate more space and continue until we get the 27101544Seschrock * entire list. 27111544Seschrock */ 27121544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 27131544Seschrock &count) == 0); 27144820Sek110237 if (count == 0) 27154820Sek110237 return (0); 27162676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 27172856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 27182082Seschrock return (-1); 27192676Seschrock zc.zc_nvlist_dst_size = count; 27201544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 27211544Seschrock for (;;) { 27222082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 27232082Seschrock &zc) != 0) { 27242676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 27251544Seschrock if (errno == ENOMEM) { 27263823Svb160487 count = zc.zc_nvlist_dst_size; 27272676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 27283823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 27293823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 27302082Seschrock return (-1); 27311544Seschrock } else { 27321544Seschrock return (-1); 27331544Seschrock } 27341544Seschrock } else { 27351544Seschrock break; 27361544Seschrock } 27371544Seschrock } 27381544Seschrock 27391544Seschrock /* 27401544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 27411544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 27422676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 27431544Seschrock * _not_ copied as part of the process. So we point the start of our 27441544Seschrock * array appropriate and decrement the total number of elements. 27451544Seschrock */ 27462676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 27472676Seschrock zc.zc_nvlist_dst_size; 27482676Seschrock count -= zc.zc_nvlist_dst_size; 27491544Seschrock 27501544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 27511544Seschrock 27523444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 27531544Seschrock 27541544Seschrock /* 27553444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 27561544Seschrock */ 27571544Seschrock for (i = 0; i < count; i++) { 27581544Seschrock nvlist_t *nv; 27591544Seschrock 27603700Sek110237 /* ignoring zb_blkid and zb_level for now */ 27613700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 27623700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 27631544Seschrock continue; 27641544Seschrock 27653444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 27663444Sek110237 goto nomem; 27673444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 27683444Sek110237 zb[i].zb_objset) != 0) { 27693444Sek110237 nvlist_free(nv); 27702082Seschrock goto nomem; 27713444Sek110237 } 27723444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 27733444Sek110237 zb[i].zb_object) != 0) { 27743444Sek110237 nvlist_free(nv); 27753444Sek110237 goto nomem; 27761544Seschrock } 27773444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 27783444Sek110237 nvlist_free(nv); 27793444Sek110237 goto nomem; 27803444Sek110237 } 27813444Sek110237 nvlist_free(nv); 27821544Seschrock } 27831544Seschrock 27843265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 27851544Seschrock return (0); 27862082Seschrock 27872082Seschrock nomem: 27882676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 27892082Seschrock return (no_memory(zhp->zpool_hdl)); 27901544Seschrock } 27911760Seschrock 27921760Seschrock /* 27931760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 27941760Seschrock */ 27951760Seschrock int 27965094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 27971760Seschrock { 27981760Seschrock zfs_cmd_t zc = { 0 }; 27992082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 28001760Seschrock 28011760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 28025094Slling zc.zc_cookie = new_version; 28035094Slling 28044543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 28053237Slling return (zpool_standard_error_fmt(hdl, errno, 28062082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 28072082Seschrock zhp->zpool_name)); 28081760Seschrock return (0); 28091760Seschrock } 28102926Sek110237 28114988Sek110237 void 28124988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 28134988Sek110237 char *history_str) 28144988Sek110237 { 28154988Sek110237 int i; 28164988Sek110237 28174988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 28184988Sek110237 for (i = 1; i < argc; i++) { 28194988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 28204988Sek110237 HIS_MAX_RECORD_LEN) 28214988Sek110237 break; 28224988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 28234988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 28244988Sek110237 } 28254988Sek110237 } 28264988Sek110237 28272926Sek110237 /* 28284988Sek110237 * Stage command history for logging. 28292926Sek110237 */ 28304988Sek110237 int 28314988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 28322926Sek110237 { 28334988Sek110237 if (history_str == NULL) 28344988Sek110237 return (EINVAL); 28354988Sek110237 28364988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 28374988Sek110237 return (EINVAL); 28382926Sek110237 28394715Sek110237 if (hdl->libzfs_log_str != NULL) 28404543Smarks free(hdl->libzfs_log_str); 28412926Sek110237 28424988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 28434988Sek110237 return (no_memory(hdl)); 28444543Smarks 28454988Sek110237 return (0); 28462926Sek110237 } 28472926Sek110237 28482926Sek110237 /* 28492926Sek110237 * Perform ioctl to get some command history of a pool. 28502926Sek110237 * 28512926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 28522926Sek110237 * logical offset of the history buffer to start reading from. 28532926Sek110237 * 28542926Sek110237 * Upon return, 'off' is the next logical offset to read from and 28552926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 28562926Sek110237 */ 28572926Sek110237 static int 28582926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 28592926Sek110237 { 28602926Sek110237 zfs_cmd_t zc = { 0 }; 28612926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 28622926Sek110237 28632926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28642926Sek110237 28652926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 28662926Sek110237 zc.zc_history_len = *len; 28672926Sek110237 zc.zc_history_offset = *off; 28682926Sek110237 28692926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 28702926Sek110237 switch (errno) { 28712926Sek110237 case EPERM: 28723237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 28733237Slling dgettext(TEXT_DOMAIN, 28742926Sek110237 "cannot show history for pool '%s'"), 28752926Sek110237 zhp->zpool_name)); 28762926Sek110237 case ENOENT: 28773237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 28782926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 28792926Sek110237 "'%s'"), zhp->zpool_name)); 28803863Sek110237 case ENOTSUP: 28813863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 28823863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 28833863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 28842926Sek110237 default: 28853237Slling return (zpool_standard_error_fmt(hdl, errno, 28862926Sek110237 dgettext(TEXT_DOMAIN, 28872926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 28882926Sek110237 } 28892926Sek110237 } 28902926Sek110237 28912926Sek110237 *len = zc.zc_history_len; 28922926Sek110237 *off = zc.zc_history_offset; 28932926Sek110237 28942926Sek110237 return (0); 28952926Sek110237 } 28962926Sek110237 28972926Sek110237 /* 28982926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 28992926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 29002926Sek110237 * processed as there wasn't a complete record. 29012926Sek110237 */ 29022926Sek110237 static int 29032926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 29042926Sek110237 nvlist_t ***records, uint_t *numrecords) 29052926Sek110237 { 29062926Sek110237 uint64_t reclen; 29072926Sek110237 nvlist_t *nv; 29082926Sek110237 int i; 29092926Sek110237 29102926Sek110237 while (bytes_read > sizeof (reclen)) { 29112926Sek110237 29122926Sek110237 /* get length of packed record (stored as little endian) */ 29132926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 29142926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 29152926Sek110237 29162926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 29172926Sek110237 break; 29182926Sek110237 29192926Sek110237 /* unpack record */ 29202926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 29212926Sek110237 return (ENOMEM); 29222926Sek110237 bytes_read -= sizeof (reclen) + reclen; 29232926Sek110237 buf += sizeof (reclen) + reclen; 29242926Sek110237 29252926Sek110237 /* add record to nvlist array */ 29262926Sek110237 (*numrecords)++; 29272926Sek110237 if (ISP2(*numrecords + 1)) { 29282926Sek110237 *records = realloc(*records, 29292926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 29302926Sek110237 } 29312926Sek110237 (*records)[*numrecords - 1] = nv; 29322926Sek110237 } 29332926Sek110237 29342926Sek110237 *leftover = bytes_read; 29352926Sek110237 return (0); 29362926Sek110237 } 29372926Sek110237 29382926Sek110237 #define HIS_BUF_LEN (128*1024) 29392926Sek110237 29402926Sek110237 /* 29412926Sek110237 * Retrieve the command history of a pool. 29422926Sek110237 */ 29432926Sek110237 int 29442926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 29452926Sek110237 { 29462926Sek110237 char buf[HIS_BUF_LEN]; 29472926Sek110237 uint64_t off = 0; 29482926Sek110237 nvlist_t **records = NULL; 29492926Sek110237 uint_t numrecords = 0; 29502926Sek110237 int err, i; 29512926Sek110237 29522926Sek110237 do { 29532926Sek110237 uint64_t bytes_read = sizeof (buf); 29542926Sek110237 uint64_t leftover; 29552926Sek110237 29562926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 29572926Sek110237 break; 29582926Sek110237 29592926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 29602926Sek110237 if (!bytes_read) 29612926Sek110237 break; 29622926Sek110237 29632926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 29642926Sek110237 &leftover, &records, &numrecords)) != 0) 29652926Sek110237 break; 29662926Sek110237 off -= leftover; 29672926Sek110237 29682926Sek110237 /* CONSTCOND */ 29692926Sek110237 } while (1); 29702926Sek110237 29712926Sek110237 if (!err) { 29722926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 29732926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 29742926Sek110237 records, numrecords) == 0); 29752926Sek110237 } 29762926Sek110237 for (i = 0; i < numrecords; i++) 29772926Sek110237 nvlist_free(records[i]); 29782926Sek110237 free(records); 29792926Sek110237 29802926Sek110237 return (err); 29812926Sek110237 } 29823444Sek110237 29833444Sek110237 void 29843444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 29853444Sek110237 char *pathname, size_t len) 29863444Sek110237 { 29873444Sek110237 zfs_cmd_t zc = { 0 }; 29883444Sek110237 boolean_t mounted = B_FALSE; 29893444Sek110237 char *mntpnt = NULL; 29903444Sek110237 char dsname[MAXNAMELEN]; 29913444Sek110237 29923444Sek110237 if (dsobj == 0) { 29933444Sek110237 /* special case for the MOS */ 29943444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 29953444Sek110237 return; 29963444Sek110237 } 29973444Sek110237 29983444Sek110237 /* get the dataset's name */ 29993444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 30003444Sek110237 zc.zc_obj = dsobj; 30013444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 30023444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 30033444Sek110237 /* just write out a path of two object numbers */ 30043444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 30053444Sek110237 dsobj, obj); 30063444Sek110237 return; 30073444Sek110237 } 30083444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 30093444Sek110237 30103444Sek110237 /* find out if the dataset is mounted */ 30113444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 30123444Sek110237 30133444Sek110237 /* get the corrupted object's path */ 30143444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 30153444Sek110237 zc.zc_obj = obj; 30163444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 30173444Sek110237 &zc) == 0) { 30183444Sek110237 if (mounted) { 30193444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 30203444Sek110237 zc.zc_value); 30213444Sek110237 } else { 30223444Sek110237 (void) snprintf(pathname, len, "%s:%s", 30233444Sek110237 dsname, zc.zc_value); 30243444Sek110237 } 30253444Sek110237 } else { 30263444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 30273444Sek110237 } 30283444Sek110237 free(mntpnt); 30293444Sek110237 } 30303912Slling 30314276Staylor /* 30327042Sgw25295 * Read the EFI label from the config, if a label does not exist then 30337042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 30347042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 30357042Sgw25295 * partition. 30367042Sgw25295 */ 30377042Sgw25295 static int 30387042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 30397042Sgw25295 { 30407042Sgw25295 char *path; 30417042Sgw25295 int fd; 30427042Sgw25295 char diskname[MAXPATHLEN]; 30437042Sgw25295 int err = -1; 30447042Sgw25295 30457042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 30467042Sgw25295 return (err); 30477042Sgw25295 30487042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 30497042Sgw25295 strrchr(path, '/')); 30507042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 30517042Sgw25295 struct dk_gpt *vtoc; 30527042Sgw25295 30537042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 30547042Sgw25295 if (sb != NULL) 30557042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 30567042Sgw25295 efi_free(vtoc); 30577042Sgw25295 } 30587042Sgw25295 (void) close(fd); 30597042Sgw25295 } 30607042Sgw25295 return (err); 30617042Sgw25295 } 30627042Sgw25295 30637042Sgw25295 /* 30644276Staylor * determine where a partition starts on a disk in the current 30654276Staylor * configuration 30664276Staylor */ 30674276Staylor static diskaddr_t 30684276Staylor find_start_block(nvlist_t *config) 30694276Staylor { 30704276Staylor nvlist_t **child; 30714276Staylor uint_t c, children; 30724276Staylor diskaddr_t sb = MAXOFFSET_T; 30734276Staylor uint64_t wholedisk; 30744276Staylor 30754276Staylor if (nvlist_lookup_nvlist_array(config, 30764276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 30774276Staylor if (nvlist_lookup_uint64(config, 30784276Staylor ZPOOL_CONFIG_WHOLE_DISK, 30794276Staylor &wholedisk) != 0 || !wholedisk) { 30804276Staylor return (MAXOFFSET_T); 30814276Staylor } 30827042Sgw25295 if (read_efi_label(config, &sb) < 0) 30837042Sgw25295 sb = MAXOFFSET_T; 30844276Staylor return (sb); 30854276Staylor } 30864276Staylor 30874276Staylor for (c = 0; c < children; c++) { 30884276Staylor sb = find_start_block(child[c]); 30894276Staylor if (sb != MAXOFFSET_T) { 30904276Staylor return (sb); 30914276Staylor } 30924276Staylor } 30934276Staylor return (MAXOFFSET_T); 30944276Staylor } 30954276Staylor 30964276Staylor /* 30974276Staylor * Label an individual disk. The name provided is the short name, 30984276Staylor * stripped of any leading /dev path. 30994276Staylor */ 31004276Staylor int 31014276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 31024276Staylor { 31034276Staylor char path[MAXPATHLEN]; 31044276Staylor struct dk_gpt *vtoc; 31054276Staylor int fd; 31064276Staylor size_t resv = EFI_MIN_RESV_SIZE; 31074276Staylor uint64_t slice_size; 31084276Staylor diskaddr_t start_block; 31094276Staylor char errbuf[1024]; 31104276Staylor 31116289Smmusante /* prepare an error message just in case */ 31126289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 31136289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 31146289Smmusante 31154276Staylor if (zhp) { 31164276Staylor nvlist_t *nvroot; 31174276Staylor 31187965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 31197965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31207965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 31217965SGeorge.Wilson@Sun.COM "pools.")); 31227965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 31237965SGeorge.Wilson@Sun.COM } 31247965SGeorge.Wilson@Sun.COM 31254276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 31264276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 31274276Staylor 31284276Staylor if (zhp->zpool_start_block == 0) 31294276Staylor start_block = find_start_block(nvroot); 31304276Staylor else 31314276Staylor start_block = zhp->zpool_start_block; 31324276Staylor zhp->zpool_start_block = start_block; 31334276Staylor } else { 31344276Staylor /* new pool */ 31354276Staylor start_block = NEW_START_BLOCK; 31364276Staylor } 31374276Staylor 31384276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 31394276Staylor BACKUP_SLICE); 31404276Staylor 31414276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 31424276Staylor /* 31434276Staylor * This shouldn't happen. We've long since verified that this 31444276Staylor * is a valid device. 31454276Staylor */ 31466289Smmusante zfs_error_aux(hdl, 31476289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 31484276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 31494276Staylor } 31504276Staylor 31514276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 31524276Staylor /* 31534276Staylor * The only way this can fail is if we run out of memory, or we 31544276Staylor * were unable to read the disk's capacity 31554276Staylor */ 31564276Staylor if (errno == ENOMEM) 31574276Staylor (void) no_memory(hdl); 31584276Staylor 31594276Staylor (void) close(fd); 31606289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31616289Smmusante "unable to read disk capacity"), name); 31624276Staylor 31634276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 31644276Staylor } 31654276Staylor 31664276Staylor slice_size = vtoc->efi_last_u_lba + 1; 31674276Staylor slice_size -= EFI_MIN_RESV_SIZE; 31684276Staylor if (start_block == MAXOFFSET_T) 31694276Staylor start_block = NEW_START_BLOCK; 31704276Staylor slice_size -= start_block; 31714276Staylor 31724276Staylor vtoc->efi_parts[0].p_start = start_block; 31734276Staylor vtoc->efi_parts[0].p_size = slice_size; 31744276Staylor 31754276Staylor /* 31764276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 31774276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 31784276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 31794276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 31804276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 31814276Staylor * can get, in the absence of V_OTHER. 31824276Staylor */ 31834276Staylor vtoc->efi_parts[0].p_tag = V_USR; 31844276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 31854276Staylor 31864276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 31874276Staylor vtoc->efi_parts[8].p_size = resv; 31884276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 31894276Staylor 31904276Staylor if (efi_write(fd, vtoc) != 0) { 31914276Staylor /* 31924276Staylor * Some block drivers (like pcata) may not support EFI 31934276Staylor * GPT labels. Print out a helpful error message dir- 31944276Staylor * ecting the user to manually label the disk and give 31954276Staylor * a specific slice. 31964276Staylor */ 31974276Staylor (void) close(fd); 31984276Staylor efi_free(vtoc); 31994276Staylor 32004276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32016289Smmusante "try using fdisk(1M) and then provide a specific slice")); 32024276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 32034276Staylor } 32044276Staylor 32054276Staylor (void) close(fd); 32064276Staylor efi_free(vtoc); 32074276Staylor return (0); 32084276Staylor } 32096423Sgw25295 32106423Sgw25295 static boolean_t 32116423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 32126423Sgw25295 { 32136423Sgw25295 char *type; 32146423Sgw25295 nvlist_t **child; 32156423Sgw25295 uint_t children, c; 32166423Sgw25295 32176423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 32186423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 32196423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 32206423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 32216423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 32226423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32236423Sgw25295 "vdev type '%s' is not supported"), type); 32246423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 32256423Sgw25295 return (B_FALSE); 32266423Sgw25295 } 32276423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 32286423Sgw25295 &child, &children) == 0) { 32296423Sgw25295 for (c = 0; c < children; c++) { 32306423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 32316423Sgw25295 return (B_FALSE); 32326423Sgw25295 } 32336423Sgw25295 } 32346423Sgw25295 return (B_TRUE); 32356423Sgw25295 } 32366423Sgw25295 32376423Sgw25295 /* 32386423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 32396423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 32406423Sgw25295 */ 32416423Sgw25295 int 32426423Sgw25295 zvol_check_dump_config(char *arg) 32436423Sgw25295 { 32446423Sgw25295 zpool_handle_t *zhp = NULL; 32456423Sgw25295 nvlist_t *config, *nvroot; 32466423Sgw25295 char *p, *volname; 32476423Sgw25295 nvlist_t **top; 32486423Sgw25295 uint_t toplevels; 32496423Sgw25295 libzfs_handle_t *hdl; 32506423Sgw25295 char errbuf[1024]; 32516423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 32526423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 32536423Sgw25295 int ret = 1; 32546423Sgw25295 32556423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 32566423Sgw25295 return (-1); 32576423Sgw25295 } 32586423Sgw25295 32596423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 32606423Sgw25295 "dump is not supported on device '%s'"), arg); 32616423Sgw25295 32626423Sgw25295 if ((hdl = libzfs_init()) == NULL) 32636423Sgw25295 return (1); 32646423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 32656423Sgw25295 32666423Sgw25295 volname = arg + pathlen; 32676423Sgw25295 32686423Sgw25295 /* check the configuration of the pool */ 32696423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 32706423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32716423Sgw25295 "malformed dataset name")); 32726423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 32736423Sgw25295 return (1); 32746423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 32756423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32766423Sgw25295 "dataset name is too long")); 32776423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 32786423Sgw25295 return (1); 32796423Sgw25295 } else { 32806423Sgw25295 (void) strncpy(poolname, volname, p - volname); 32816423Sgw25295 poolname[p - volname] = '\0'; 32826423Sgw25295 } 32836423Sgw25295 32846423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 32856423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32866423Sgw25295 "could not open pool '%s'"), poolname); 32876423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 32886423Sgw25295 goto out; 32896423Sgw25295 } 32906423Sgw25295 config = zpool_get_config(zhp, NULL); 32916423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 32926423Sgw25295 &nvroot) != 0) { 32936423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32946423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 32956423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 32966423Sgw25295 goto out; 32976423Sgw25295 } 32986423Sgw25295 32996423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 33006423Sgw25295 &top, &toplevels) == 0); 33016423Sgw25295 if (toplevels != 1) { 33026423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33036423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 33046423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 33056423Sgw25295 goto out; 33066423Sgw25295 } 33076423Sgw25295 33086423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 33096423Sgw25295 goto out; 33106423Sgw25295 } 33116423Sgw25295 ret = 0; 33126423Sgw25295 33136423Sgw25295 out: 33146423Sgw25295 if (zhp) 33156423Sgw25295 zpool_close(zhp); 33166423Sgw25295 libzfs_fini(hdl); 33176423Sgw25295 return (ret); 33186423Sgw25295 } 3319