1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 238525SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #include <ctype.h> 28789Sahrens #include <errno.h> 29789Sahrens #include <devid.h> 30789Sahrens #include <fcntl.h> 31789Sahrens #include <libintl.h> 32789Sahrens #include <stdio.h> 33789Sahrens #include <stdlib.h> 343126Sahl #include <strings.h> 35789Sahrens #include <unistd.h> 364276Staylor #include <sys/efi_partition.h> 374276Staylor #include <sys/vtoc.h> 38789Sahrens #include <sys/zfs_ioctl.h> 399816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 40789Sahrens 41789Sahrens #include "zfs_namecheck.h" 423912Slling #include "zfs_prop.h" 43789Sahrens #include "libzfs_impl.h" 44789Sahrens 45*10685SGeorge.Wilson@Sun.COM const char *hist_event_table[LOG_END] = { 46*10685SGeorge.Wilson@Sun.COM "invalid event", 47*10685SGeorge.Wilson@Sun.COM "pool create", 48*10685SGeorge.Wilson@Sun.COM "vdev add", 49*10685SGeorge.Wilson@Sun.COM "pool remove", 50*10685SGeorge.Wilson@Sun.COM "pool destroy", 51*10685SGeorge.Wilson@Sun.COM "pool export", 52*10685SGeorge.Wilson@Sun.COM "pool import", 53*10685SGeorge.Wilson@Sun.COM "vdev attach", 54*10685SGeorge.Wilson@Sun.COM "vdev replace", 55*10685SGeorge.Wilson@Sun.COM "vdev detach", 56*10685SGeorge.Wilson@Sun.COM "vdev online", 57*10685SGeorge.Wilson@Sun.COM "vdev offline", 58*10685SGeorge.Wilson@Sun.COM "vdev upgrade", 59*10685SGeorge.Wilson@Sun.COM "pool clear", 60*10685SGeorge.Wilson@Sun.COM "pool scrub", 61*10685SGeorge.Wilson@Sun.COM "pool property set", 62*10685SGeorge.Wilson@Sun.COM "create", 63*10685SGeorge.Wilson@Sun.COM "clone", 64*10685SGeorge.Wilson@Sun.COM "destroy", 65*10685SGeorge.Wilson@Sun.COM "destroy_begin_sync", 66*10685SGeorge.Wilson@Sun.COM "inherit", 67*10685SGeorge.Wilson@Sun.COM "property set", 68*10685SGeorge.Wilson@Sun.COM "quota set", 69*10685SGeorge.Wilson@Sun.COM "permission update", 70*10685SGeorge.Wilson@Sun.COM "permission remove", 71*10685SGeorge.Wilson@Sun.COM "permission who remove", 72*10685SGeorge.Wilson@Sun.COM "promote", 73*10685SGeorge.Wilson@Sun.COM "receive", 74*10685SGeorge.Wilson@Sun.COM "rename", 75*10685SGeorge.Wilson@Sun.COM "reservation set", 76*10685SGeorge.Wilson@Sun.COM "replay_inc_sync", 77*10685SGeorge.Wilson@Sun.COM "replay_full_sync", 78*10685SGeorge.Wilson@Sun.COM "rollback", 79*10685SGeorge.Wilson@Sun.COM "snapshot", 80*10685SGeorge.Wilson@Sun.COM "filesystem version upgrade", 81*10685SGeorge.Wilson@Sun.COM "refquota set", 82*10685SGeorge.Wilson@Sun.COM "refreservation set", 83*10685SGeorge.Wilson@Sun.COM "pool scrub done", 84*10685SGeorge.Wilson@Sun.COM "user hold", 85*10685SGeorge.Wilson@Sun.COM "user release", 86*10685SGeorge.Wilson@Sun.COM }; 87*10685SGeorge.Wilson@Sun.COM 887042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 895094Slling 907965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 917965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 927965SGeorge.Wilson@Sun.COM #else 937965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 947965SGeorge.Wilson@Sun.COM #endif 957965SGeorge.Wilson@Sun.COM 969816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 979816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 989816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 999816SGeorge.Wilson@Sun.COM 1005094Slling /* 1015094Slling * ==================================================================== 1025094Slling * zpool property functions 1035094Slling * ==================================================================== 1045094Slling */ 1055094Slling 1065094Slling static int 1075094Slling zpool_get_all_props(zpool_handle_t *zhp) 1085094Slling { 1095094Slling zfs_cmd_t zc = { 0 }; 1105094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 1115094Slling 1125094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1135094Slling 1145094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 1155094Slling return (-1); 1165094Slling 1175094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 1185094Slling if (errno == ENOMEM) { 1195094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 1205094Slling zcmd_free_nvlists(&zc); 1215094Slling return (-1); 1225094Slling } 1235094Slling } else { 1245094Slling zcmd_free_nvlists(&zc); 1255094Slling return (-1); 1265094Slling } 1275094Slling } 1285094Slling 1295094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 1305094Slling zcmd_free_nvlists(&zc); 1315094Slling return (-1); 1325094Slling } 1335094Slling 1345094Slling zcmd_free_nvlists(&zc); 1355094Slling 1365094Slling return (0); 1375094Slling } 1385094Slling 1395094Slling static int 1405094Slling zpool_props_refresh(zpool_handle_t *zhp) 1415094Slling { 1425094Slling nvlist_t *old_props; 1435094Slling 1445094Slling old_props = zhp->zpool_props; 1455094Slling 1465094Slling if (zpool_get_all_props(zhp) != 0) 1475094Slling return (-1); 1485094Slling 1495094Slling nvlist_free(old_props); 1505094Slling return (0); 1515094Slling } 1525094Slling 1535094Slling static char * 1545094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1555094Slling zprop_source_t *src) 1565094Slling { 1575094Slling nvlist_t *nv, *nvl; 1585094Slling uint64_t ival; 1595094Slling char *value; 1605094Slling zprop_source_t source; 1615094Slling 1625094Slling nvl = zhp->zpool_props; 1635094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1645094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1655094Slling source = ival; 1665094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1675094Slling } else { 1685094Slling source = ZPROP_SRC_DEFAULT; 1695094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1705094Slling value = "-"; 1715094Slling } 1725094Slling 1735094Slling if (src) 1745094Slling *src = source; 1755094Slling 1765094Slling return (value); 1775094Slling } 1785094Slling 1795094Slling uint64_t 1805094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1815094Slling { 1825094Slling nvlist_t *nv, *nvl; 1835094Slling uint64_t value; 1845094Slling zprop_source_t source; 1855094Slling 1867294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1877294Sperrin /* 1887294Sperrin * zpool_get_all_props() has most likely failed because 1897294Sperrin * the pool is faulted, but if all we need is the top level 1907294Sperrin * vdev's guid then get it from the zhp config nvlist. 1917294Sperrin */ 1927294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1937294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1947294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1957294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1967294Sperrin == 0)) { 1977294Sperrin return (value); 1987294Sperrin } 1995094Slling return (zpool_prop_default_numeric(prop)); 2007294Sperrin } 2015094Slling 2025094Slling nvl = zhp->zpool_props; 2035094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 2045094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 2055094Slling source = value; 2065094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 2075094Slling } else { 2085094Slling source = ZPROP_SRC_DEFAULT; 2095094Slling value = zpool_prop_default_numeric(prop); 2105094Slling } 2115094Slling 2125094Slling if (src) 2135094Slling *src = source; 2145094Slling 2155094Slling return (value); 2165094Slling } 2175094Slling 2185094Slling /* 2195094Slling * Map VDEV STATE to printed strings. 2205094Slling */ 2215094Slling char * 2225094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 2235094Slling { 2245094Slling switch (state) { 2255094Slling case VDEV_STATE_CLOSED: 2265094Slling case VDEV_STATE_OFFLINE: 2275094Slling return (gettext("OFFLINE")); 2285094Slling case VDEV_STATE_REMOVED: 2295094Slling return (gettext("REMOVED")); 2305094Slling case VDEV_STATE_CANT_OPEN: 2317294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 2325094Slling return (gettext("FAULTED")); 2335094Slling else 2345094Slling return (gettext("UNAVAIL")); 2355094Slling case VDEV_STATE_FAULTED: 2365094Slling return (gettext("FAULTED")); 2375094Slling case VDEV_STATE_DEGRADED: 2385094Slling return (gettext("DEGRADED")); 2395094Slling case VDEV_STATE_HEALTHY: 2405094Slling return (gettext("ONLINE")); 2415094Slling } 2425094Slling 2435094Slling return (gettext("UNKNOWN")); 2445094Slling } 2455094Slling 2465094Slling /* 2475094Slling * Get a zpool property value for 'prop' and return the value in 2485094Slling * a pre-allocated buffer. 2495094Slling */ 2505094Slling int 2515094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2525094Slling zprop_source_t *srctype) 2535094Slling { 2545094Slling uint64_t intval; 2555094Slling const char *strval; 2565094Slling zprop_source_t src = ZPROP_SRC_NONE; 2575094Slling nvlist_t *nvroot; 2585094Slling vdev_stat_t *vs; 2595094Slling uint_t vsc; 2605094Slling 2615094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2628525SEric.Schrock@Sun.COM switch (prop) { 2638525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2645094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2658525SEric.Schrock@Sun.COM break; 2668525SEric.Schrock@Sun.COM 2678525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2685094Slling (void) strlcpy(buf, "FAULTED", len); 2698525SEric.Schrock@Sun.COM break; 2708525SEric.Schrock@Sun.COM 2718525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2728525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2738525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2748525SEric.Schrock@Sun.COM break; 2758525SEric.Schrock@Sun.COM 2768525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2778525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2788525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2798525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2808525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2818525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2828525SEric.Schrock@Sun.COM len); 2838525SEric.Schrock@Sun.COM if (srctype != NULL) 2848525SEric.Schrock@Sun.COM *srctype = src; 2858525SEric.Schrock@Sun.COM return (0); 2868525SEric.Schrock@Sun.COM } 2878525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2888525SEric.Schrock@Sun.COM default: 2895094Slling (void) strlcpy(buf, "-", len); 2908525SEric.Schrock@Sun.COM break; 2918525SEric.Schrock@Sun.COM } 2928525SEric.Schrock@Sun.COM 2938525SEric.Schrock@Sun.COM if (srctype != NULL) 2948525SEric.Schrock@Sun.COM *srctype = src; 2955094Slling return (0); 2965094Slling } 2975094Slling 2985094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2995094Slling prop != ZPOOL_PROP_NAME) 3005094Slling return (-1); 3015094Slling 3025094Slling switch (zpool_prop_get_type(prop)) { 3035094Slling case PROP_TYPE_STRING: 3045094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 3055094Slling len); 3065094Slling break; 3075094Slling 3085094Slling case PROP_TYPE_NUMBER: 3095094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3105094Slling 3115094Slling switch (prop) { 3125094Slling case ZPOOL_PROP_SIZE: 3135094Slling case ZPOOL_PROP_USED: 3145094Slling case ZPOOL_PROP_AVAILABLE: 3155094Slling (void) zfs_nicenum(intval, buf, len); 3165094Slling break; 3175094Slling 3185094Slling case ZPOOL_PROP_CAPACITY: 3195094Slling (void) snprintf(buf, len, "%llu%%", 3205094Slling (u_longlong_t)intval); 3215094Slling break; 3225094Slling 3235094Slling case ZPOOL_PROP_HEALTH: 3245094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 3255094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 3265094Slling verify(nvlist_lookup_uint64_array(nvroot, 3275094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 3285094Slling 3295094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 3305094Slling vs->vs_aux), len); 3315094Slling break; 3325094Slling default: 3335094Slling (void) snprintf(buf, len, "%llu", intval); 3345094Slling } 3355094Slling break; 3365094Slling 3375094Slling case PROP_TYPE_INDEX: 3385094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3395094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3405094Slling != 0) 3415094Slling return (-1); 3425094Slling (void) strlcpy(buf, strval, len); 3435094Slling break; 3445094Slling 3455094Slling default: 3465094Slling abort(); 3475094Slling } 3485094Slling 3495094Slling if (srctype) 3505094Slling *srctype = src; 3515094Slling 3525094Slling return (0); 3535094Slling } 3545094Slling 3555094Slling /* 3565094Slling * Check if the bootfs name has the same pool name as it is set to. 3575094Slling * Assuming bootfs is a valid dataset name. 3585094Slling */ 3595094Slling static boolean_t 3605094Slling bootfs_name_valid(const char *pool, char *bootfs) 3615094Slling { 3625094Slling int len = strlen(pool); 3635094Slling 3647300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3655094Slling return (B_FALSE); 3665094Slling 3675094Slling if (strncmp(pool, bootfs, len) == 0 && 3685094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3695094Slling return (B_TRUE); 3705094Slling 3715094Slling return (B_FALSE); 3725094Slling } 3735094Slling 3745094Slling /* 3757042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3767042Sgw25295 * an EFI label. 3777042Sgw25295 */ 3787042Sgw25295 static boolean_t 3797042Sgw25295 pool_uses_efi(nvlist_t *config) 3807042Sgw25295 { 3817042Sgw25295 nvlist_t **child; 3827042Sgw25295 uint_t c, children; 3837042Sgw25295 3847042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3857042Sgw25295 &child, &children) != 0) 3867042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3877042Sgw25295 3887042Sgw25295 for (c = 0; c < children; c++) { 3897042Sgw25295 if (pool_uses_efi(child[c])) 3907042Sgw25295 return (B_TRUE); 3917042Sgw25295 } 3927042Sgw25295 return (B_FALSE); 3937042Sgw25295 } 3947042Sgw25295 3957965SGeorge.Wilson@Sun.COM static boolean_t 3967965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3977965SGeorge.Wilson@Sun.COM { 3987965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3997965SGeorge.Wilson@Sun.COM 4007965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 4017965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 4027965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 4037965SGeorge.Wilson@Sun.COM } 4047965SGeorge.Wilson@Sun.COM 4057965SGeorge.Wilson@Sun.COM 4067042Sgw25295 /* 4075094Slling * Given an nvlist of zpool properties to be set, validate that they are 4085094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 4095094Slling * specified as strings. 4105094Slling */ 4115094Slling static nvlist_t * 4127184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 4135094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 4145094Slling { 4155094Slling nvpair_t *elem; 4165094Slling nvlist_t *retprops; 4175094Slling zpool_prop_t prop; 4185094Slling char *strval; 4195094Slling uint64_t intval; 4205363Seschrock char *slash; 4215363Seschrock struct stat64 statbuf; 4227042Sgw25295 zpool_handle_t *zhp; 4237042Sgw25295 nvlist_t *nvroot; 4245094Slling 4255094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 4265094Slling (void) no_memory(hdl); 4275094Slling return (NULL); 4285094Slling } 4295094Slling 4305094Slling elem = NULL; 4315094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 4325094Slling const char *propname = nvpair_name(elem); 4335094Slling 4345094Slling /* 4355094Slling * Make sure this property is valid and applies to this type. 4365094Slling */ 4375094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4385094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4395094Slling "invalid property '%s'"), propname); 4405094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4415094Slling goto error; 4425094Slling } 4435094Slling 4445094Slling if (zpool_prop_readonly(prop)) { 4455094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4465094Slling "is readonly"), propname); 4475094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4485094Slling goto error; 4495094Slling } 4505094Slling 4515094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4525094Slling &strval, &intval, errbuf) != 0) 4535094Slling goto error; 4545094Slling 4555094Slling /* 4565094Slling * Perform additional checking for specific properties. 4575094Slling */ 4585094Slling switch (prop) { 4595094Slling case ZPOOL_PROP_VERSION: 4605094Slling if (intval < version || intval > SPA_VERSION) { 4615094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4625094Slling "property '%s' number %d is invalid."), 4635094Slling propname, intval); 4645094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4655094Slling goto error; 4665094Slling } 4675094Slling break; 4685094Slling 4695094Slling case ZPOOL_PROP_BOOTFS: 4705094Slling if (create_or_import) { 4715094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4725094Slling "property '%s' cannot be set at creation " 4735094Slling "or import time"), propname); 4745094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4755094Slling goto error; 4765094Slling } 4775094Slling 4785094Slling if (version < SPA_VERSION_BOOTFS) { 4795094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4805094Slling "pool must be upgraded to support " 4815094Slling "'%s' property"), propname); 4825094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4835094Slling goto error; 4845094Slling } 4855094Slling 4865094Slling /* 4875094Slling * bootfs property value has to be a dataset name and 4885094Slling * the dataset has to be in the same pool as it sets to. 4895094Slling */ 4905094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4915094Slling strval)) { 4925094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4935094Slling "is an invalid name"), strval); 4945094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4955094Slling goto error; 4965094Slling } 4977042Sgw25295 4987042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4997042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5007042Sgw25295 "could not open pool '%s'"), poolname); 5017042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 5027042Sgw25295 goto error; 5037042Sgw25295 } 5047042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 5057042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 5067042Sgw25295 5077042Sgw25295 /* 5087042Sgw25295 * bootfs property cannot be set on a disk which has 5097042Sgw25295 * been EFI labeled. 5107042Sgw25295 */ 5117042Sgw25295 if (pool_uses_efi(nvroot)) { 5127042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5137042Sgw25295 "property '%s' not supported on " 5147042Sgw25295 "EFI labeled devices"), propname); 5157042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 5167042Sgw25295 zpool_close(zhp); 5177042Sgw25295 goto error; 5187042Sgw25295 } 5197042Sgw25295 zpool_close(zhp); 5205094Slling break; 5215094Slling 5225094Slling case ZPOOL_PROP_ALTROOT: 5235094Slling if (!create_or_import) { 5245094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5255094Slling "property '%s' can only be set during pool " 5265094Slling "creation or import"), propname); 5275094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 5285094Slling goto error; 5295094Slling } 5305094Slling 5315094Slling if (strval[0] != '/') { 5325094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5335094Slling "bad alternate root '%s'"), strval); 5345094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5355094Slling goto error; 5365094Slling } 5375094Slling break; 5385363Seschrock 5395363Seschrock case ZPOOL_PROP_CACHEFILE: 5405363Seschrock if (strval[0] == '\0') 5415363Seschrock break; 5425363Seschrock 5435363Seschrock if (strcmp(strval, "none") == 0) 5445363Seschrock break; 5455363Seschrock 5465363Seschrock if (strval[0] != '/') { 5475363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5485363Seschrock "property '%s' must be empty, an " 5495363Seschrock "absolute path, or 'none'"), propname); 5505363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5515363Seschrock goto error; 5525363Seschrock } 5535363Seschrock 5545363Seschrock slash = strrchr(strval, '/'); 5555363Seschrock 5565363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5575363Seschrock strcmp(slash, "/..") == 0) { 5585363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5595363Seschrock "'%s' is not a valid file"), strval); 5605363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5615363Seschrock goto error; 5625363Seschrock } 5635363Seschrock 5645363Seschrock *slash = '\0'; 5655363Seschrock 5665621Seschrock if (strval[0] != '\0' && 5675621Seschrock (stat64(strval, &statbuf) != 0 || 5685621Seschrock !S_ISDIR(statbuf.st_mode))) { 5695363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5705363Seschrock "'%s' is not a valid directory"), 5715363Seschrock strval); 5725363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5735363Seschrock goto error; 5745363Seschrock } 5755363Seschrock 5765363Seschrock *slash = '/'; 5775363Seschrock break; 5785094Slling } 5795094Slling } 5805094Slling 5815094Slling return (retprops); 5825094Slling error: 5835094Slling nvlist_free(retprops); 5845094Slling return (NULL); 5855094Slling } 5865094Slling 5875094Slling /* 5885094Slling * Set zpool property : propname=propval. 5895094Slling */ 5905094Slling int 5915094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5925094Slling { 5935094Slling zfs_cmd_t zc = { 0 }; 5945094Slling int ret = -1; 5955094Slling char errbuf[1024]; 5965094Slling nvlist_t *nvl = NULL; 5975094Slling nvlist_t *realprops; 5985094Slling uint64_t version; 5995094Slling 6005094Slling (void) snprintf(errbuf, sizeof (errbuf), 6015094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 6025094Slling zhp->zpool_name); 6035094Slling 6045094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 6055094Slling return (no_memory(zhp->zpool_hdl)); 6065094Slling 6075094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 6085094Slling nvlist_free(nvl); 6095094Slling return (no_memory(zhp->zpool_hdl)); 6105094Slling } 6115094Slling 6125094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 6137184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 6145094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 6155094Slling nvlist_free(nvl); 6165094Slling return (-1); 6175094Slling } 6185094Slling 6195094Slling nvlist_free(nvl); 6205094Slling nvl = realprops; 6215094Slling 6225094Slling /* 6235094Slling * Execute the corresponding ioctl() to set this property. 6245094Slling */ 6255094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 6265094Slling 6275094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 6285094Slling nvlist_free(nvl); 6295094Slling return (-1); 6305094Slling } 6315094Slling 6325094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 6335094Slling 6345094Slling zcmd_free_nvlists(&zc); 6355094Slling nvlist_free(nvl); 6365094Slling 6375094Slling if (ret) 6385094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6395094Slling else 6405094Slling (void) zpool_props_refresh(zhp); 6415094Slling 6425094Slling return (ret); 6435094Slling } 6445094Slling 6455094Slling int 6465094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6475094Slling { 6485094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6495094Slling zprop_list_t *entry; 6505094Slling char buf[ZFS_MAXPROPLEN]; 6515094Slling 6525094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6535094Slling return (-1); 6545094Slling 6555094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6565094Slling 6575094Slling if (entry->pl_fixed) 6585094Slling continue; 6595094Slling 6605094Slling if (entry->pl_prop != ZPROP_INVAL && 6615094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6625094Slling NULL) == 0) { 6635094Slling if (strlen(buf) > entry->pl_width) 6645094Slling entry->pl_width = strlen(buf); 6655094Slling } 6665094Slling } 6675094Slling 6685094Slling return (0); 6695094Slling } 6705094Slling 6715094Slling 672789Sahrens /* 6739816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6749816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6759816SGeorge.Wilson@Sun.COM */ 6769816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6779816SGeorge.Wilson@Sun.COM 6789816SGeorge.Wilson@Sun.COM /* 679789Sahrens * Validate the given pool name, optionally putting an extended error message in 680789Sahrens * 'buf'. 681789Sahrens */ 6826423Sgw25295 boolean_t 6832082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 684789Sahrens { 685789Sahrens namecheck_err_t why; 686789Sahrens char what; 6871773Seschrock int ret; 688789Sahrens 6891773Seschrock ret = pool_namecheck(pool, &why, &what); 6901773Seschrock 6911773Seschrock /* 6921773Seschrock * The rules for reserved pool names were extended at a later point. 6931773Seschrock * But we need to support users with existing pools that may now be 6941773Seschrock * invalid. So we only check for this expanded set of names during a 6951773Seschrock * create (or import), and only in userland. 6961773Seschrock */ 6971773Seschrock if (ret == 0 && !isopen && 6981773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6991773Seschrock strncmp(pool, "raidz", 5) == 0 || 7004527Sperrin strncmp(pool, "spare", 5) == 0 || 7014527Sperrin strcmp(pool, "log") == 0)) { 7026423Sgw25295 if (hdl != NULL) 7036423Sgw25295 zfs_error_aux(hdl, 7046423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 7052082Seschrock return (B_FALSE); 7061773Seschrock } 7071773Seschrock 7081773Seschrock 7091773Seschrock if (ret != 0) { 7102082Seschrock if (hdl != NULL) { 711789Sahrens switch (why) { 7121003Slling case NAME_ERR_TOOLONG: 7132082Seschrock zfs_error_aux(hdl, 7141003Slling dgettext(TEXT_DOMAIN, "name is too long")); 7151003Slling break; 7161003Slling 717789Sahrens case NAME_ERR_INVALCHAR: 7182082Seschrock zfs_error_aux(hdl, 719789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 720789Sahrens "'%c' in pool name"), what); 721789Sahrens break; 722789Sahrens 723789Sahrens case NAME_ERR_NOLETTER: 7242082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7252082Seschrock "name must begin with a letter")); 726789Sahrens break; 727789Sahrens 728789Sahrens case NAME_ERR_RESERVED: 7292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7302082Seschrock "name is reserved")); 731789Sahrens break; 732789Sahrens 733789Sahrens case NAME_ERR_DISKLIKE: 7342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7352082Seschrock "pool name is reserved")); 736789Sahrens break; 7372856Snd150628 7382856Snd150628 case NAME_ERR_LEADING_SLASH: 7392856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7402856Snd150628 "leading slash in name")); 7412856Snd150628 break; 7422856Snd150628 7432856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7442856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7452856Snd150628 "empty component in name")); 7462856Snd150628 break; 7472856Snd150628 7482856Snd150628 case NAME_ERR_TRAILING_SLASH: 7492856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7502856Snd150628 "trailing slash in name")); 7512856Snd150628 break; 7522856Snd150628 7532856Snd150628 case NAME_ERR_MULTIPLE_AT: 7542856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7552856Snd150628 "multiple '@' delimiters in name")); 7562856Snd150628 break; 7572856Snd150628 758789Sahrens } 759789Sahrens } 7602082Seschrock return (B_FALSE); 761789Sahrens } 762789Sahrens 7632082Seschrock return (B_TRUE); 764789Sahrens } 765789Sahrens 766789Sahrens /* 767789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 768789Sahrens * state. 769789Sahrens */ 770789Sahrens zpool_handle_t * 7712082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 772789Sahrens { 773789Sahrens zpool_handle_t *zhp; 7742142Seschrock boolean_t missing; 775789Sahrens 776789Sahrens /* 777789Sahrens * Make sure the pool name is valid. 778789Sahrens */ 7792082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7803237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7812082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7822082Seschrock pool); 783789Sahrens return (NULL); 784789Sahrens } 785789Sahrens 7862082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7872082Seschrock return (NULL); 788789Sahrens 7892082Seschrock zhp->zpool_hdl = hdl; 790789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 791789Sahrens 7922142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7932142Seschrock zpool_close(zhp); 7942142Seschrock return (NULL); 7952142Seschrock } 7962142Seschrock 7972142Seschrock if (missing) { 7985094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7993237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 8005094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 8012142Seschrock zpool_close(zhp); 8022142Seschrock return (NULL); 803789Sahrens } 804789Sahrens 805789Sahrens return (zhp); 806789Sahrens } 807789Sahrens 808789Sahrens /* 809789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 810789Sahrens * the configuration cache may be out of date). 811789Sahrens */ 8122142Seschrock int 8132142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 814789Sahrens { 815789Sahrens zpool_handle_t *zhp; 8162142Seschrock boolean_t missing; 817789Sahrens 8182142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 8192142Seschrock return (-1); 820789Sahrens 8212082Seschrock zhp->zpool_hdl = hdl; 822789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 823789Sahrens 8242142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 8252142Seschrock zpool_close(zhp); 8262142Seschrock return (-1); 827789Sahrens } 828789Sahrens 8292142Seschrock if (missing) { 8302142Seschrock zpool_close(zhp); 8312142Seschrock *ret = NULL; 8322142Seschrock return (0); 8332142Seschrock } 8342142Seschrock 8352142Seschrock *ret = zhp; 8362142Seschrock return (0); 837789Sahrens } 838789Sahrens 839789Sahrens /* 840789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 841789Sahrens * state. 842789Sahrens */ 843789Sahrens zpool_handle_t * 8442082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 845789Sahrens { 846789Sahrens zpool_handle_t *zhp; 847789Sahrens 8482082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 849789Sahrens return (NULL); 850789Sahrens 851789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8523237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8532082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 854789Sahrens zpool_close(zhp); 855789Sahrens return (NULL); 856789Sahrens } 857789Sahrens 858789Sahrens return (zhp); 859789Sahrens } 860789Sahrens 861789Sahrens /* 862789Sahrens * Close the handle. Simply frees the memory associated with the handle. 863789Sahrens */ 864789Sahrens void 865789Sahrens zpool_close(zpool_handle_t *zhp) 866789Sahrens { 867789Sahrens if (zhp->zpool_config) 868789Sahrens nvlist_free(zhp->zpool_config); 869952Seschrock if (zhp->zpool_old_config) 870952Seschrock nvlist_free(zhp->zpool_old_config); 8713912Slling if (zhp->zpool_props) 8723912Slling nvlist_free(zhp->zpool_props); 873789Sahrens free(zhp); 874789Sahrens } 875789Sahrens 876789Sahrens /* 877789Sahrens * Return the name of the pool. 878789Sahrens */ 879789Sahrens const char * 880789Sahrens zpool_get_name(zpool_handle_t *zhp) 881789Sahrens { 882789Sahrens return (zhp->zpool_name); 883789Sahrens } 884789Sahrens 885789Sahrens 886789Sahrens /* 887789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 888789Sahrens */ 889789Sahrens int 890789Sahrens zpool_get_state(zpool_handle_t *zhp) 891789Sahrens { 892789Sahrens return (zhp->zpool_state); 893789Sahrens } 894789Sahrens 895789Sahrens /* 896789Sahrens * Create the named pool, using the provided vdev list. It is assumed 897789Sahrens * that the consumer has already validated the contents of the nvlist, so we 898789Sahrens * don't have to worry about error semantics. 899789Sahrens */ 900789Sahrens int 9012082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 9027184Stimh nvlist_t *props, nvlist_t *fsprops) 903789Sahrens { 904789Sahrens zfs_cmd_t zc = { 0 }; 9057184Stimh nvlist_t *zc_fsprops = NULL; 9067184Stimh nvlist_t *zc_props = NULL; 9072082Seschrock char msg[1024]; 9085094Slling char *altroot; 9097184Stimh int ret = -1; 9102082Seschrock 9112082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 9122082Seschrock "cannot create '%s'"), pool); 913789Sahrens 9142082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 9152082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 9162082Seschrock 9175320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 9185320Slling return (-1); 9195320Slling 9207184Stimh if (props) { 9217184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 9227184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 9237184Stimh goto create_failed; 9247184Stimh } 9255320Slling } 926789Sahrens 9277184Stimh if (fsprops) { 9287184Stimh uint64_t zoned; 9297184Stimh char *zonestr; 9307184Stimh 9317184Stimh zoned = ((nvlist_lookup_string(fsprops, 9327184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 9337184Stimh strcmp(zonestr, "on") == 0); 9347184Stimh 9357184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9367184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9377184Stimh goto create_failed; 9387184Stimh } 9397184Stimh if (!zc_props && 9407184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9417184Stimh goto create_failed; 9427184Stimh } 9437184Stimh if (nvlist_add_nvlist(zc_props, 9447184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9457184Stimh goto create_failed; 9467184Stimh } 9477184Stimh } 9487184Stimh 9497184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9507184Stimh goto create_failed; 9517184Stimh 952789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 953789Sahrens 9547184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9555320Slling 9562676Seschrock zcmd_free_nvlists(&zc); 9577184Stimh nvlist_free(zc_props); 9587184Stimh nvlist_free(zc_fsprops); 9592082Seschrock 960789Sahrens switch (errno) { 961789Sahrens case EBUSY: 962789Sahrens /* 963789Sahrens * This can happen if the user has specified the same 964789Sahrens * device multiple times. We can't reliably detect this 965789Sahrens * until we try to add it and see we already have a 966789Sahrens * label. 967789Sahrens */ 9682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9692082Seschrock "one or more vdevs refer to the same device")); 9702082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 971789Sahrens 972789Sahrens case EOVERFLOW: 973789Sahrens /* 9742082Seschrock * This occurs when one of the devices is below 975789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 976789Sahrens * device was the problem device since there's no 977789Sahrens * reliable way to determine device size from userland. 978789Sahrens */ 979789Sahrens { 980789Sahrens char buf[64]; 981789Sahrens 982789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 983789Sahrens 9842082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9852082Seschrock "one or more devices is less than the " 9862082Seschrock "minimum size (%s)"), buf); 987789Sahrens } 9882082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 989789Sahrens 990789Sahrens case ENOSPC: 9912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9922082Seschrock "one or more devices is out of space")); 9932082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 994789Sahrens 9955450Sbrendan case ENOTBLK: 9965450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9975450Sbrendan "cache device must be a disk or disk slice")); 9985450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9995450Sbrendan 1000789Sahrens default: 10012082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1002789Sahrens } 1003789Sahrens } 1004789Sahrens 1005789Sahrens /* 1006789Sahrens * If this is an alternate root pool, then we automatically set the 10072676Seschrock * mountpoint of the root dataset to be '/'. 1008789Sahrens */ 10095094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 10105094Slling &altroot) == 0) { 1011789Sahrens zfs_handle_t *zhp; 1012789Sahrens 10135094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 10142676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 10152676Seschrock "/") == 0); 1016789Sahrens 1017789Sahrens zfs_close(zhp); 1018789Sahrens } 1019789Sahrens 10207184Stimh create_failed: 10215320Slling zcmd_free_nvlists(&zc); 10227184Stimh nvlist_free(zc_props); 10237184Stimh nvlist_free(zc_fsprops); 10247184Stimh return (ret); 1025789Sahrens } 1026789Sahrens 1027789Sahrens /* 1028789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1029789Sahrens * datasets left in the pool. 1030789Sahrens */ 1031789Sahrens int 1032789Sahrens zpool_destroy(zpool_handle_t *zhp) 1033789Sahrens { 1034789Sahrens zfs_cmd_t zc = { 0 }; 1035789Sahrens zfs_handle_t *zfp = NULL; 10362082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10372082Seschrock char msg[1024]; 1038789Sahrens 1039789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 10402082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 10412082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1042789Sahrens return (-1); 1043789Sahrens 1044789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1045789Sahrens 10464543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10472082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10482082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1049789Sahrens 10502082Seschrock if (errno == EROFS) { 10512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10522082Seschrock "one or more devices is read only")); 10532082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10542082Seschrock } else { 10552082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1056789Sahrens } 1057789Sahrens 1058789Sahrens if (zfp) 1059789Sahrens zfs_close(zfp); 1060789Sahrens return (-1); 1061789Sahrens } 1062789Sahrens 1063789Sahrens if (zfp) { 1064789Sahrens remove_mountpoint(zfp); 1065789Sahrens zfs_close(zfp); 1066789Sahrens } 1067789Sahrens 1068789Sahrens return (0); 1069789Sahrens } 1070789Sahrens 1071789Sahrens /* 1072789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1073789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1074789Sahrens */ 1075789Sahrens int 1076789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1077789Sahrens { 10782676Seschrock zfs_cmd_t zc = { 0 }; 10792082Seschrock int ret; 10802082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10812082Seschrock char msg[1024]; 10825450Sbrendan nvlist_t **spares, **l2cache; 10835450Sbrendan uint_t nspares, nl2cache; 10842082Seschrock 10852082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10862082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10872082Seschrock 10885450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10895450Sbrendan SPA_VERSION_SPARES && 10902082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10912082Seschrock &spares, &nspares) == 0) { 10922082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10932082Seschrock "upgraded to add hot spares")); 10942082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10952082Seschrock } 1096789Sahrens 10977965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10987965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10997965SGeorge.Wilson@Sun.COM uint64_t s; 11007965SGeorge.Wilson@Sun.COM 11017965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 11027965SGeorge.Wilson@Sun.COM char *path; 11037965SGeorge.Wilson@Sun.COM 11047965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 11057965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 11067965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11077965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 11087965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 110910594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 111010594SGeorge.Wilson@Sun.COM B_FALSE)); 11117965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 11127965SGeorge.Wilson@Sun.COM } 11137965SGeorge.Wilson@Sun.COM } 11147965SGeorge.Wilson@Sun.COM } 11157965SGeorge.Wilson@Sun.COM 11165450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 11175450Sbrendan SPA_VERSION_L2CACHE && 11185450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 11195450Sbrendan &l2cache, &nl2cache) == 0) { 11205450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 11215450Sbrendan "upgraded to add cache devices")); 11225450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 11235450Sbrendan } 11245450Sbrendan 11255094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 11262082Seschrock return (-1); 1127789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1128789Sahrens 11294543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1130789Sahrens switch (errno) { 1131789Sahrens case EBUSY: 1132789Sahrens /* 1133789Sahrens * This can happen if the user has specified the same 1134789Sahrens * device multiple times. We can't reliably detect this 1135789Sahrens * until we try to add it and see we already have a 1136789Sahrens * label. 1137789Sahrens */ 11382082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11392082Seschrock "one or more vdevs refer to the same device")); 11402082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1141789Sahrens break; 1142789Sahrens 1143789Sahrens case EOVERFLOW: 1144789Sahrens /* 1145789Sahrens * This occurrs when one of the devices is below 1146789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1147789Sahrens * device was the problem device since there's no 1148789Sahrens * reliable way to determine device size from userland. 1149789Sahrens */ 1150789Sahrens { 1151789Sahrens char buf[64]; 1152789Sahrens 1153789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1154789Sahrens 11552082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11562082Seschrock "device is less than the minimum " 11572082Seschrock "size (%s)"), buf); 1158789Sahrens } 11592082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11602082Seschrock break; 11612082Seschrock 11622082Seschrock case ENOTSUP: 11632082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11644527Sperrin "pool must be upgraded to add these vdevs")); 11652082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1166789Sahrens break; 1167789Sahrens 11683912Slling case EDOM: 11693912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11704527Sperrin "root pool can not have multiple vdevs" 11714527Sperrin " or separate logs")); 11723912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11733912Slling break; 11743912Slling 11755450Sbrendan case ENOTBLK: 11765450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11775450Sbrendan "cache device must be a disk or disk slice")); 11785450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11795450Sbrendan break; 11805450Sbrendan 1181789Sahrens default: 11822082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1183789Sahrens } 1184789Sahrens 11852082Seschrock ret = -1; 11862082Seschrock } else { 11872082Seschrock ret = 0; 1188789Sahrens } 1189789Sahrens 11902676Seschrock zcmd_free_nvlists(&zc); 1191789Sahrens 11922082Seschrock return (ret); 1193789Sahrens } 1194789Sahrens 1195789Sahrens /* 1196789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1197789Sahrens * mounted datasets in the pool. 1198789Sahrens */ 1199789Sahrens int 12008211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1201789Sahrens { 1202789Sahrens zfs_cmd_t zc = { 0 }; 12037214Slling char msg[1024]; 1204789Sahrens 12057214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 12067214Slling "cannot export '%s'"), zhp->zpool_name); 12077214Slling 1208789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 12097214Slling zc.zc_cookie = force; 12108211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 12117214Slling 12127214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 12137214Slling switch (errno) { 12147214Slling case EXDEV: 12157214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 12167214Slling "use '-f' to override the following errors:\n" 12177214Slling "'%s' has an active shared spare which could be" 12187214Slling " used by other pools once '%s' is exported."), 12197214Slling zhp->zpool_name, zhp->zpool_name); 12207214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 12217214Slling msg)); 12227214Slling default: 12237214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 12247214Slling msg)); 12257214Slling } 12267214Slling } 12277214Slling 1228789Sahrens return (0); 1229789Sahrens } 1230789Sahrens 12318211SGeorge.Wilson@Sun.COM int 12328211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 12338211SGeorge.Wilson@Sun.COM { 12348211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12358211SGeorge.Wilson@Sun.COM } 12368211SGeorge.Wilson@Sun.COM 12378211SGeorge.Wilson@Sun.COM int 12388211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12398211SGeorge.Wilson@Sun.COM { 12408211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12418211SGeorge.Wilson@Sun.COM } 12428211SGeorge.Wilson@Sun.COM 1243789Sahrens /* 12445094Slling * zpool_import() is a contracted interface. Should be kept the same 12455094Slling * if possible. 12465094Slling * 12475094Slling * Applications should use zpool_import_props() to import a pool with 12485094Slling * new properties value to be set. 1249789Sahrens */ 1250789Sahrens int 12512082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12525094Slling char *altroot) 12535094Slling { 12545094Slling nvlist_t *props = NULL; 12555094Slling int ret; 12565094Slling 12575094Slling if (altroot != NULL) { 12585094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 12595094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12605094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12615094Slling newname)); 12625094Slling } 12635094Slling 12645094Slling if (nvlist_add_string(props, 12658084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 12668084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 12678084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 12685094Slling nvlist_free(props); 12695094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12705094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12715094Slling newname)); 12725094Slling } 12735094Slling } 12745094Slling 12756643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 12765094Slling if (props) 12775094Slling nvlist_free(props); 12785094Slling return (ret); 12795094Slling } 12805094Slling 12815094Slling /* 12825094Slling * Import the given pool using the known configuration and a list of 12835094Slling * properties to be set. The configuration should have come from 12845094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 12855094Slling * is imported with a different name. 12865094Slling */ 12875094Slling int 12885094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12896643Seschrock nvlist_t *props, boolean_t importfaulted) 1290789Sahrens { 12912676Seschrock zfs_cmd_t zc = { 0 }; 1292789Sahrens char *thename; 1293789Sahrens char *origname; 1294789Sahrens int ret; 12955094Slling char errbuf[1024]; 1296789Sahrens 1297789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1298789Sahrens &origname) == 0); 1299789Sahrens 13005094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 13015094Slling "cannot import pool '%s'"), origname); 13025094Slling 1303789Sahrens if (newname != NULL) { 13042082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 13053237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 13062082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13072082Seschrock newname)); 1308789Sahrens thename = (char *)newname; 1309789Sahrens } else { 1310789Sahrens thename = origname; 1311789Sahrens } 1312789Sahrens 13135094Slling if (props) { 13145094Slling uint64_t version; 13155094Slling 13165094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 13175094Slling &version) == 0); 13185094Slling 13197184Stimh if ((props = zpool_valid_proplist(hdl, origname, 13205320Slling props, version, B_TRUE, errbuf)) == NULL) { 13215094Slling return (-1); 13225320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 13235320Slling nvlist_free(props); 13245094Slling return (-1); 13255320Slling } 13265094Slling } 1327789Sahrens 1328789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1329789Sahrens 1330789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 13311544Seschrock &zc.zc_guid) == 0); 1332789Sahrens 13335320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 13345320Slling nvlist_free(props); 13352082Seschrock return (-1); 13365320Slling } 1337789Sahrens 13386643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1339789Sahrens ret = 0; 13404543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1341789Sahrens char desc[1024]; 1342789Sahrens if (newname == NULL) 1343789Sahrens (void) snprintf(desc, sizeof (desc), 1344789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1345789Sahrens thename); 1346789Sahrens else 1347789Sahrens (void) snprintf(desc, sizeof (desc), 1348789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1349789Sahrens origname, thename); 1350789Sahrens 1351789Sahrens switch (errno) { 13521544Seschrock case ENOTSUP: 13531544Seschrock /* 13541544Seschrock * Unsupported version. 13551544Seschrock */ 13562082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 13571544Seschrock break; 13581544Seschrock 13592174Seschrock case EINVAL: 13602174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 13612174Seschrock break; 13622174Seschrock 1363789Sahrens default: 13642082Seschrock (void) zpool_standard_error(hdl, errno, desc); 1365789Sahrens } 1366789Sahrens 1367789Sahrens ret = -1; 1368789Sahrens } else { 1369789Sahrens zpool_handle_t *zhp; 13704543Smarks 1371789Sahrens /* 1372789Sahrens * This should never fail, but play it safe anyway. 1373789Sahrens */ 137410588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 13752142Seschrock ret = -1; 137610588SEric.Taylor@Sun.COM else if (zhp != NULL) 1377789Sahrens zpool_close(zhp); 1378789Sahrens } 1379789Sahrens 13802676Seschrock zcmd_free_nvlists(&zc); 13815320Slling nvlist_free(props); 13825320Slling 1383789Sahrens return (ret); 1384789Sahrens } 1385789Sahrens 1386789Sahrens /* 1387789Sahrens * Scrub the pool. 1388789Sahrens */ 1389789Sahrens int 1390789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1391789Sahrens { 1392789Sahrens zfs_cmd_t zc = { 0 }; 1393789Sahrens char msg[1024]; 13942082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1395789Sahrens 1396789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1397789Sahrens zc.zc_cookie = type; 1398789Sahrens 13994543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1400789Sahrens return (0); 1401789Sahrens 1402789Sahrens (void) snprintf(msg, sizeof (msg), 1403789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1404789Sahrens 14052082Seschrock if (errno == EBUSY) 14062082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 14072082Seschrock else 14082082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1409789Sahrens } 1410789Sahrens 14112468Sek110237 /* 14129816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 14139816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 14142468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 14152468Sek110237 * spare; but FALSE if its an INUSE spare. 14162468Sek110237 */ 14172082Seschrock static nvlist_t * 14189816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 14199816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 14201544Seschrock { 14211544Seschrock uint_t c, children; 14221544Seschrock nvlist_t **child; 14232082Seschrock nvlist_t *ret; 14247326SEric.Schrock@Sun.COM uint64_t is_log; 14259816SGeorge.Wilson@Sun.COM char *srchkey; 14269816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 14279816SGeorge.Wilson@Sun.COM 14289816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 14299816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 14309816SGeorge.Wilson@Sun.COM return (NULL); 14319816SGeorge.Wilson@Sun.COM 14329816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 14339816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 14349816SGeorge.Wilson@Sun.COM 14359816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 14369816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 14379816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 14389816SGeorge.Wilson@Sun.COM 14399816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 14409816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 14419816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 14429816SGeorge.Wilson@Sun.COM &present) == 0) { 14439816SGeorge.Wilson@Sun.COM /* 14449816SGeorge.Wilson@Sun.COM * If the device has never been present since 14459816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 14469816SGeorge.Wilson@Sun.COM * vdev is by GUID. 14479816SGeorge.Wilson@Sun.COM */ 14489816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 14499816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 14509816SGeorge.Wilson@Sun.COM if (theguid == srchval) 14519816SGeorge.Wilson@Sun.COM return (nv); 14529816SGeorge.Wilson@Sun.COM } 14539816SGeorge.Wilson@Sun.COM } 14549816SGeorge.Wilson@Sun.COM break; 14559816SGeorge.Wilson@Sun.COM } 14569816SGeorge.Wilson@Sun.COM 14579816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 14589816SGeorge.Wilson@Sun.COM char *srchval, *val; 14599816SGeorge.Wilson@Sun.COM 14609816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 14619816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 14629816SGeorge.Wilson@Sun.COM break; 14639816SGeorge.Wilson@Sun.COM 14641544Seschrock /* 14659816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 146610594SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk and when 146710594SGeorge.Wilson@Sun.COM * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 146810594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 14691544Seschrock */ 14709816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 14719816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 14729816SGeorge.Wilson@Sun.COM 14739816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 14749816SGeorge.Wilson@Sun.COM &wholedisk); 14759816SGeorge.Wilson@Sun.COM if (wholedisk) { 14769816SGeorge.Wilson@Sun.COM /* 14779816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 14789816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 14799816SGeorge.Wilson@Sun.COM */ 14809816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 14819816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 14829816SGeorge.Wilson@Sun.COM return (nv); 14839816SGeorge.Wilson@Sun.COM break; 14849816SGeorge.Wilson@Sun.COM } 148510594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 148610594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 148710594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 148810594SGeorge.Wilson@Sun.COM 148910594SGeorge.Wilson@Sun.COM /* 149010594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 149110594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 149210594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 149310594SGeorge.Wilson@Sun.COM */ 149410594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 149510594SGeorge.Wilson@Sun.COM return (NULL); 149610594SGeorge.Wilson@Sun.COM 149710594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 149810594SGeorge.Wilson@Sun.COM free(type); 149910594SGeorge.Wilson@Sun.COM break; 150010594SGeorge.Wilson@Sun.COM } 150110594SGeorge.Wilson@Sun.COM idx = p + 1; 150210594SGeorge.Wilson@Sun.COM *p = '\0'; 150310594SGeorge.Wilson@Sun.COM 150410594SGeorge.Wilson@Sun.COM /* 150510594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 150610594SGeorge.Wilson@Sun.COM */ 150710594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 150810594SGeorge.Wilson@Sun.COM free(type); 150910594SGeorge.Wilson@Sun.COM break; 151010594SGeorge.Wilson@Sun.COM } 151110594SGeorge.Wilson@Sun.COM 151210594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 151310594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 151410594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 151510594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 151610594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 151710594SGeorge.Wilson@Sun.COM &id) == 0); 151810594SGeorge.Wilson@Sun.COM 151910594SGeorge.Wilson@Sun.COM errno = 0; 152010594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 152110594SGeorge.Wilson@Sun.COM 152210594SGeorge.Wilson@Sun.COM free(type); 152310594SGeorge.Wilson@Sun.COM if (errno != 0) 152410594SGeorge.Wilson@Sun.COM return (NULL); 152510594SGeorge.Wilson@Sun.COM 152610594SGeorge.Wilson@Sun.COM /* 152710594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 152810594SGeorge.Wilson@Sun.COM */ 152910594SGeorge.Wilson@Sun.COM if (vdev_id == id) 153010594SGeorge.Wilson@Sun.COM return (nv); 15319816SGeorge.Wilson@Sun.COM } 15329816SGeorge.Wilson@Sun.COM 15339816SGeorge.Wilson@Sun.COM /* 15349816SGeorge.Wilson@Sun.COM * Common case 15359816SGeorge.Wilson@Sun.COM */ 15369816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 15372082Seschrock return (nv); 15389816SGeorge.Wilson@Sun.COM break; 15399816SGeorge.Wilson@Sun.COM } 15409816SGeorge.Wilson@Sun.COM 15419816SGeorge.Wilson@Sun.COM default: 15429816SGeorge.Wilson@Sun.COM break; 15431544Seschrock } 15441544Seschrock 15451544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 15461544Seschrock &child, &children) != 0) 15472082Seschrock return (NULL); 15481544Seschrock 15497326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 15509816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15517326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15527326SEric.Schrock@Sun.COM /* 15537326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 15547326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 15557326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 15567326SEric.Schrock@Sun.COM * 'log' is non-NULL). 15577326SEric.Schrock@Sun.COM */ 15587326SEric.Schrock@Sun.COM if (log != NULL && 15597326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 15607326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 15617326SEric.Schrock@Sun.COM is_log) { 15627326SEric.Schrock@Sun.COM *log = B_TRUE; 15637326SEric.Schrock@Sun.COM } 15641544Seschrock return (ret); 15657326SEric.Schrock@Sun.COM } 15667326SEric.Schrock@Sun.COM } 15671544Seschrock 15682082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 15692082Seschrock &child, &children) == 0) { 15702082Seschrock for (c = 0; c < children; c++) { 15719816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15727326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15732468Sek110237 *avail_spare = B_TRUE; 15742082Seschrock return (ret); 15752082Seschrock } 15762082Seschrock } 15772082Seschrock } 15782082Seschrock 15795450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 15805450Sbrendan &child, &children) == 0) { 15815450Sbrendan for (c = 0; c < children; c++) { 15829816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 15837326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 15845450Sbrendan *l2cache = B_TRUE; 15855450Sbrendan return (ret); 15865450Sbrendan } 15875450Sbrendan } 15885450Sbrendan } 15895450Sbrendan 15902082Seschrock return (NULL); 15911544Seschrock } 15921544Seschrock 15939816SGeorge.Wilson@Sun.COM /* 15949816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 15959816SGeorge.Wilson@Sun.COM * associated vdev. 15969816SGeorge.Wilson@Sun.COM */ 15979816SGeorge.Wilson@Sun.COM nvlist_t * 15989816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 15999816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 16009816SGeorge.Wilson@Sun.COM { 16019816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 16029816SGeorge.Wilson@Sun.COM 16039816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 16049816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 16059816SGeorge.Wilson@Sun.COM 16069816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 16079816SGeorge.Wilson@Sun.COM &nvroot) == 0); 16089816SGeorge.Wilson@Sun.COM 16099816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 16109816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 16119816SGeorge.Wilson@Sun.COM nvlist_free(search); 16129816SGeorge.Wilson@Sun.COM 16139816SGeorge.Wilson@Sun.COM return (ret); 16149816SGeorge.Wilson@Sun.COM } 16159816SGeorge.Wilson@Sun.COM 161610594SGeorge.Wilson@Sun.COM /* 161710594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 161810594SGeorge.Wilson@Sun.COM */ 161910594SGeorge.Wilson@Sun.COM boolean_t 162010594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 162110594SGeorge.Wilson@Sun.COM { 162210594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 162310594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 162410594SGeorge.Wilson@Sun.COM return (B_TRUE); 162510594SGeorge.Wilson@Sun.COM return (B_FALSE); 162610594SGeorge.Wilson@Sun.COM } 162710594SGeorge.Wilson@Sun.COM 16282082Seschrock nvlist_t * 16295450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 16307326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 16311544Seschrock { 16321544Seschrock char buf[MAXPATHLEN]; 16331544Seschrock char *end; 16349816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 16351544Seschrock uint64_t guid; 16361544Seschrock 16379816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 16389816SGeorge.Wilson@Sun.COM 16391613Seschrock guid = strtoull(path, &end, 10); 16401544Seschrock if (guid != 0 && *end == '\0') { 16419816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 164210594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 164310594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 16441544Seschrock } else if (path[0] != '/') { 16451544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 16469816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 16471544Seschrock } else { 16489816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 16491544Seschrock } 16501544Seschrock 16511544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 16521544Seschrock &nvroot) == 0); 16531544Seschrock 16542468Sek110237 *avail_spare = B_FALSE; 16555450Sbrendan *l2cache = B_FALSE; 16567326SEric.Schrock@Sun.COM if (log != NULL) 16577326SEric.Schrock@Sun.COM *log = B_FALSE; 16589816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 16599816SGeorge.Wilson@Sun.COM nvlist_free(search); 16609816SGeorge.Wilson@Sun.COM 16619816SGeorge.Wilson@Sun.COM return (ret); 16622468Sek110237 } 16632468Sek110237 16647656SSherry.Moore@Sun.COM static int 16657656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 16667656SSherry.Moore@Sun.COM { 16677656SSherry.Moore@Sun.COM uint64_t ival; 16687656SSherry.Moore@Sun.COM 16697656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 16707656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 16717656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 16727656SSherry.Moore@Sun.COM return (0); 16737656SSherry.Moore@Sun.COM 16747656SSherry.Moore@Sun.COM return (1); 16757656SSherry.Moore@Sun.COM } 16767656SSherry.Moore@Sun.COM 16777656SSherry.Moore@Sun.COM /* 16789790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 16797656SSherry.Moore@Sun.COM */ 16809160SSherry.Moore@Sun.COM static int 16819790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 16829160SSherry.Moore@Sun.COM size_t *bytes_written) 16837656SSherry.Moore@Sun.COM { 16849160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 16859160SSherry.Moore@Sun.COM char *tmppath; 16869160SSherry.Moore@Sun.COM const char *format; 16879160SSherry.Moore@Sun.COM 16889160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 16899160SSherry.Moore@Sun.COM &tmppath) != 0) 16909160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 16919160SSherry.Moore@Sun.COM 16929160SSherry.Moore@Sun.COM pos = *bytes_written; 16939160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 16949160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 16959160SSherry.Moore@Sun.COM 16969160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 16979160SSherry.Moore@Sun.COM *bytes_written += rsz; 16989160SSherry.Moore@Sun.COM 16999160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 17009160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 17019160SSherry.Moore@Sun.COM if (bytes_left != 0) { 17029160SSherry.Moore@Sun.COM physpath[pos] = 0; 17039160SSherry.Moore@Sun.COM } 17049160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 17059160SSherry.Moore@Sun.COM } 17069160SSherry.Moore@Sun.COM return (0); 17079160SSherry.Moore@Sun.COM } 17089160SSherry.Moore@Sun.COM 17099790SLin.Ling@Sun.COM static int 17109790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 17119790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 17129790SLin.Ling@Sun.COM { 17139790SLin.Ling@Sun.COM char *type; 17149790SLin.Ling@Sun.COM int ret; 17159790SLin.Ling@Sun.COM 17169790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 17179790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 17189790SLin.Ling@Sun.COM 17199790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 17209790SLin.Ling@Sun.COM /* 17219790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 17229790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 17239790SLin.Ling@Sun.COM * spare device. 17249790SLin.Ling@Sun.COM */ 17259790SLin.Ling@Sun.COM if (is_spare) { 17269790SLin.Ling@Sun.COM uint64_t spare = 0; 17279790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 17289790SLin.Ling@Sun.COM &spare); 17299790SLin.Ling@Sun.COM if (!spare) 17309790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 17319790SLin.Ling@Sun.COM } 17329790SLin.Ling@Sun.COM 17339790SLin.Ling@Sun.COM if (vdev_online(nv)) { 17349790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 17359790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 17369790SLin.Ling@Sun.COM return (ret); 17379790SLin.Ling@Sun.COM } 17389790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 17399790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 17409790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 17419790SLin.Ling@Sun.COM nvlist_t **child; 17429790SLin.Ling@Sun.COM uint_t count; 17439790SLin.Ling@Sun.COM int i, ret; 17449790SLin.Ling@Sun.COM 17459790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 17469790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 17479790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 17489790SLin.Ling@Sun.COM 17499790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 17509790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 17519790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 17529790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 17539790SLin.Ling@Sun.COM return (ret); 17549790SLin.Ling@Sun.COM } 17559790SLin.Ling@Sun.COM } 17569790SLin.Ling@Sun.COM 17579790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 17589790SLin.Ling@Sun.COM } 17599790SLin.Ling@Sun.COM 17609160SSherry.Moore@Sun.COM /* 17619160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 17629160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 17639160SSherry.Moore@Sun.COM */ 17649160SSherry.Moore@Sun.COM static int 17659160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 17669160SSherry.Moore@Sun.COM { 17679160SSherry.Moore@Sun.COM size_t rsz; 17687656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 17697656SSherry.Moore@Sun.COM nvlist_t **child; 17707656SSherry.Moore@Sun.COM uint_t count; 17719160SSherry.Moore@Sun.COM char *type; 17729160SSherry.Moore@Sun.COM 17739160SSherry.Moore@Sun.COM rsz = 0; 17749160SSherry.Moore@Sun.COM 17759160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 17769160SSherry.Moore@Sun.COM &vdev_root) != 0) 17779160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 17789160SSherry.Moore@Sun.COM 17799160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 17809160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 17819160SSherry.Moore@Sun.COM &child, &count) != 0) 17829160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 17837656SSherry.Moore@Sun.COM 17847656SSherry.Moore@Sun.COM /* 17859160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 17869160SSherry.Moore@Sun.COM * a single top-level vdev. 17877656SSherry.Moore@Sun.COM */ 17889160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 17899160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 17909160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 17919160SSherry.Moore@Sun.COM 17929790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 17939790SLin.Ling@Sun.COM B_FALSE); 17947656SSherry.Moore@Sun.COM 17959160SSherry.Moore@Sun.COM /* No online devices */ 17969160SSherry.Moore@Sun.COM if (rsz == 0) 17979160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 17989160SSherry.Moore@Sun.COM 17997656SSherry.Moore@Sun.COM return (0); 18007656SSherry.Moore@Sun.COM } 18017656SSherry.Moore@Sun.COM 18022468Sek110237 /* 18039160SSherry.Moore@Sun.COM * Get phys_path for a root pool 18049160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 18059160SSherry.Moore@Sun.COM */ 18069160SSherry.Moore@Sun.COM int 18079160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 18089160SSherry.Moore@Sun.COM { 18099160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 18109160SSherry.Moore@Sun.COM phypath_size)); 18119160SSherry.Moore@Sun.COM } 18129160SSherry.Moore@Sun.COM 18139160SSherry.Moore@Sun.COM /* 18145450Sbrendan * Returns TRUE if the given guid corresponds to the given type. 18155450Sbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 18165450Sbrendan * devices. 18172468Sek110237 */ 18182468Sek110237 static boolean_t 18195450Sbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 18202468Sek110237 { 18215450Sbrendan uint64_t target_guid; 18222468Sek110237 nvlist_t *nvroot; 18235450Sbrendan nvlist_t **list; 18245450Sbrendan uint_t count; 18252468Sek110237 int i; 18262468Sek110237 18272468Sek110237 verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18282468Sek110237 &nvroot) == 0); 18295450Sbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 18305450Sbrendan for (i = 0; i < count; i++) { 18315450Sbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 18325450Sbrendan &target_guid) == 0); 18335450Sbrendan if (guid == target_guid) 18342468Sek110237 return (B_TRUE); 18352468Sek110237 } 18362468Sek110237 } 18372468Sek110237 18382468Sek110237 return (B_FALSE); 18391544Seschrock } 18401544Seschrock 1841789Sahrens /* 18429816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 18439816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 18449816SGeorge.Wilson@Sun.COM */ 18459816SGeorge.Wilson@Sun.COM static int 18469816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 18479816SGeorge.Wilson@Sun.COM { 18489816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 18499816SGeorge.Wilson@Sun.COM char errbuf[1024]; 18509816SGeorge.Wilson@Sun.COM int fd, error; 18519816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 18529816SGeorge.Wilson@Sun.COM 18539816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 18549816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 18559816SGeorge.Wilson@Sun.COM return (-1); 18569816SGeorge.Wilson@Sun.COM 18579816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 18589816SGeorge.Wilson@Sun.COM 18599816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 18609816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 18619816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 18629816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 18639816SGeorge.Wilson@Sun.COM } 18649816SGeorge.Wilson@Sun.COM 18659816SGeorge.Wilson@Sun.COM /* 18669816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 18679816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 18689816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 18699816SGeorge.Wilson@Sun.COM */ 18709816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 18719816SGeorge.Wilson@Sun.COM (void) close(fd); 18729816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 18739816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 18749816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 18759816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 18769816SGeorge.Wilson@Sun.COM } 18779816SGeorge.Wilson@Sun.COM return (0); 18789816SGeorge.Wilson@Sun.COM } 18799816SGeorge.Wilson@Sun.COM 18809816SGeorge.Wilson@Sun.COM /* 18814451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 18824451Seschrock * ZFS_ONLINE_* flags. 1883789Sahrens */ 1884789Sahrens int 18854451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 18864451Seschrock vdev_state_t *newstate) 1887789Sahrens { 1888789Sahrens zfs_cmd_t zc = { 0 }; 1889789Sahrens char msg[1024]; 18902082Seschrock nvlist_t *tgt; 18919816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 18922082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1893789Sahrens 18949816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 18959816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 18969816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 18979816SGeorge.Wilson@Sun.COM } else { 18989816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 18999816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 19009816SGeorge.Wilson@Sun.COM } 1901789Sahrens 19021544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19037326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 19049816SGeorge.Wilson@Sun.COM &islog)) == NULL) 19052082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1906789Sahrens 19072468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 19082468Sek110237 19095450Sbrendan if (avail_spare || 19105450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 19112082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 19122082Seschrock 19139816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 19149816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 19159816SGeorge.Wilson@Sun.COM char *pathname = NULL; 19169816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 19179816SGeorge.Wilson@Sun.COM 19189816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 19199816SGeorge.Wilson@Sun.COM &wholedisk); 19209816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 19219816SGeorge.Wilson@Sun.COM &pathname) == 0); 19229816SGeorge.Wilson@Sun.COM 19239816SGeorge.Wilson@Sun.COM /* 19249816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 19259816SGeorge.Wilson@Sun.COM */ 19269816SGeorge.Wilson@Sun.COM if (l2cache) { 19279816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 19289816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 19299816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 19309816SGeorge.Wilson@Sun.COM } 19319816SGeorge.Wilson@Sun.COM 19329816SGeorge.Wilson@Sun.COM if (wholedisk) { 19339816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 19349816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 19359816SGeorge.Wilson@Sun.COM } 19369816SGeorge.Wilson@Sun.COM } 19379816SGeorge.Wilson@Sun.COM 19384451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 19394451Seschrock zc.zc_obj = flags; 19404451Seschrock 19414543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 19424451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19434451Seschrock 19444451Seschrock *newstate = zc.zc_cookie; 19454451Seschrock return (0); 1946789Sahrens } 1947789Sahrens 1948789Sahrens /* 1949789Sahrens * Take the specified vdev offline 1950789Sahrens */ 1951789Sahrens int 19524451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1953789Sahrens { 1954789Sahrens zfs_cmd_t zc = { 0 }; 1955789Sahrens char msg[1024]; 19562082Seschrock nvlist_t *tgt; 19575450Sbrendan boolean_t avail_spare, l2cache; 19582082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1959789Sahrens 19601544Seschrock (void) snprintf(msg, sizeof (msg), 19611544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 19621544Seschrock 1963789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19647326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 19657326SEric.Schrock@Sun.COM NULL)) == NULL) 19662082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 19672082Seschrock 19682468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 19692468Sek110237 19705450Sbrendan if (avail_spare || 19715450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 19722082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 19732082Seschrock 19744451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 19754451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 19761485Slling 19774543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1978789Sahrens return (0); 1979789Sahrens 1980789Sahrens switch (errno) { 19812082Seschrock case EBUSY: 1982789Sahrens 1983789Sahrens /* 1984789Sahrens * There are no other replicas of this device. 1985789Sahrens */ 19862082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 19872082Seschrock 19889701SGeorge.Wilson@Sun.COM case EEXIST: 19899701SGeorge.Wilson@Sun.COM /* 19909701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 19919701SGeorge.Wilson@Sun.COM */ 19929701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 19939701SGeorge.Wilson@Sun.COM 19942082Seschrock default: 19952082Seschrock return (zpool_standard_error(hdl, errno, msg)); 19962082Seschrock } 19972082Seschrock } 1998789Sahrens 19992082Seschrock /* 20004451Seschrock * Mark the given vdev faulted. 20014451Seschrock */ 20024451Seschrock int 20034451Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 20044451Seschrock { 20054451Seschrock zfs_cmd_t zc = { 0 }; 20064451Seschrock char msg[1024]; 20074451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 20084451Seschrock 20094451Seschrock (void) snprintf(msg, sizeof (msg), 20104451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 20114451Seschrock 20124451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20134451Seschrock zc.zc_guid = guid; 20144451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 20154451Seschrock 20164451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 20174451Seschrock return (0); 20184451Seschrock 20194451Seschrock switch (errno) { 20204451Seschrock case EBUSY: 20214451Seschrock 20224451Seschrock /* 20234451Seschrock * There are no other replicas of this device. 20244451Seschrock */ 20254451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 20264451Seschrock 20274451Seschrock default: 20284451Seschrock return (zpool_standard_error(hdl, errno, msg)); 20294451Seschrock } 20304451Seschrock 20314451Seschrock } 20324451Seschrock 20334451Seschrock /* 20344451Seschrock * Mark the given vdev degraded. 20354451Seschrock */ 20364451Seschrock int 20374451Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 20384451Seschrock { 20394451Seschrock zfs_cmd_t zc = { 0 }; 20404451Seschrock char msg[1024]; 20414451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 20424451Seschrock 20434451Seschrock (void) snprintf(msg, sizeof (msg), 20444451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 20454451Seschrock 20464451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20474451Seschrock zc.zc_guid = guid; 20484451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 20494451Seschrock 20504451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 20514451Seschrock return (0); 20524451Seschrock 20534451Seschrock return (zpool_standard_error(hdl, errno, msg)); 20544451Seschrock } 20554451Seschrock 20564451Seschrock /* 20572082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 20582082Seschrock * a hot spare. 20592082Seschrock */ 20602082Seschrock static boolean_t 20612082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 20622082Seschrock { 20632082Seschrock nvlist_t **child; 20642082Seschrock uint_t c, children; 20652082Seschrock char *type; 20662082Seschrock 20672082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 20682082Seschrock &children) == 0) { 20692082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 20702082Seschrock &type) == 0); 20712082Seschrock 20722082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 20732082Seschrock children == 2 && child[which] == tgt) 20742082Seschrock return (B_TRUE); 20752082Seschrock 20762082Seschrock for (c = 0; c < children; c++) 20772082Seschrock if (is_replacing_spare(child[c], tgt, which)) 20782082Seschrock return (B_TRUE); 2079789Sahrens } 20802082Seschrock 20812082Seschrock return (B_FALSE); 2082789Sahrens } 2083789Sahrens 2084789Sahrens /* 2085789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 20864527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2087789Sahrens */ 2088789Sahrens int 2089789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2090789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2091789Sahrens { 2092789Sahrens zfs_cmd_t zc = { 0 }; 2093789Sahrens char msg[1024]; 2094789Sahrens int ret; 20952082Seschrock nvlist_t *tgt; 20967326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 20977326SEric.Schrock@Sun.COM uint64_t val; 20987041Seschrock char *path, *newname; 20992082Seschrock nvlist_t **child; 21002082Seschrock uint_t children; 21012082Seschrock nvlist_t *config_root; 21022082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21037965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2104789Sahrens 21051544Seschrock if (replacing) 21061544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 21071544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 21081544Seschrock else 21091544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 21101544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 21111544Seschrock 21127965SGeorge.Wilson@Sun.COM /* 21137965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 21147965SGeorge.Wilson@Sun.COM * EFI labeled device. 21157965SGeorge.Wilson@Sun.COM */ 21167965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 21177965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21187965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 21197965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 21207965SGeorge.Wilson@Sun.COM } 21217965SGeorge.Wilson@Sun.COM 2122789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21237326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 21247326SEric.Schrock@Sun.COM &islog)) == 0) 21252082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 21262082Seschrock 21272468Sek110237 if (avail_spare) 21282082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21292082Seschrock 21305450Sbrendan if (l2cache) 21315450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 21325450Sbrendan 21332082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 21342082Seschrock zc.zc_cookie = replacing; 21352082Seschrock 21362082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 21372082Seschrock &child, &children) != 0 || children != 1) { 21382082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21392082Seschrock "new device must be a single disk")); 21402082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 21411544Seschrock } 21422082Seschrock 21432082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 21442082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 21452082Seschrock 214610594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 21477041Seschrock return (-1); 21487041Seschrock 21492082Seschrock /* 21502082Seschrock * If the target is a hot spare that has been swapped in, we can only 21512082Seschrock * replace it with another hot spare. 21522082Seschrock */ 21532082Seschrock if (replacing && 21542082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 21557326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 21567326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 21577326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 21582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21592082Seschrock "can only be replaced by another hot spare")); 21607041Seschrock free(newname); 21612082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 21622082Seschrock } 21632082Seschrock 21642082Seschrock /* 21652082Seschrock * If we are attempting to replace a spare, it canot be applied to an 21662082Seschrock * already spared device. 21672082Seschrock */ 21682082Seschrock if (replacing && 21692082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 21707326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 21717326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 21727326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 21732082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21742082Seschrock "device has already been replaced with a spare")); 21757041Seschrock free(newname); 21762082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 21772082Seschrock } 2178789Sahrens 21797041Seschrock free(newname); 21807041Seschrock 21815094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 21822082Seschrock return (-1); 2183789Sahrens 21844543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2185789Sahrens 21862676Seschrock zcmd_free_nvlists(&zc); 2187789Sahrens 21887965SGeorge.Wilson@Sun.COM if (ret == 0) { 21897965SGeorge.Wilson@Sun.COM if (rootpool) { 21907965SGeorge.Wilson@Sun.COM /* 21917965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 21927965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 21937965SGeorge.Wilson@Sun.COM * newly attached disk. 21947965SGeorge.Wilson@Sun.COM */ 21957965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 21967965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 21977965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 21989790SLin.Ling@Sun.COM 21999790SLin.Ling@Sun.COM /* 22009790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 22019790SLin.Ling@Sun.COM * booting up a half-baked vdev. 22029790SLin.Ling@Sun.COM */ 22039790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 22049790SLin.Ling@Sun.COM "sure to wait until resilver is done " 22059790SLin.Ling@Sun.COM "before rebooting.\n")); 22067965SGeorge.Wilson@Sun.COM } 2207789Sahrens return (0); 22087965SGeorge.Wilson@Sun.COM } 2209789Sahrens 2210789Sahrens switch (errno) { 22111544Seschrock case ENOTSUP: 2212789Sahrens /* 2213789Sahrens * Can't attach to or replace this type of vdev. 2214789Sahrens */ 22154527Sperrin if (replacing) { 22167326SEric.Schrock@Sun.COM if (islog) 22174527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22184527Sperrin "cannot replace a log with a spare")); 22194527Sperrin else 22204527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22214527Sperrin "cannot replace a replacing device")); 22224527Sperrin } else { 22232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22242082Seschrock "can only attach to mirrors and top-level " 22252082Seschrock "disks")); 22264527Sperrin } 22272082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2228789Sahrens break; 2229789Sahrens 22301544Seschrock case EINVAL: 2231789Sahrens /* 2232789Sahrens * The new device must be a single disk. 2233789Sahrens */ 22342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22352082Seschrock "new device must be a single disk")); 22362082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2237789Sahrens break; 2238789Sahrens 22391544Seschrock case EBUSY: 22402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 22412082Seschrock new_disk); 22422082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2243789Sahrens break; 2244789Sahrens 22451544Seschrock case EOVERFLOW: 2246789Sahrens /* 2247789Sahrens * The new device is too small. 2248789Sahrens */ 22492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22502082Seschrock "device is too small")); 22512082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2252789Sahrens break; 2253789Sahrens 22541544Seschrock case EDOM: 2255789Sahrens /* 2256789Sahrens * The new device has a different alignment requirement. 2257789Sahrens */ 22582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22592082Seschrock "devices have different sector alignment")); 22602082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2261789Sahrens break; 2262789Sahrens 22631544Seschrock case ENAMETOOLONG: 2264789Sahrens /* 2265789Sahrens * The resulting top-level vdev spec won't fit in the label. 2266789Sahrens */ 22672082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2268789Sahrens break; 2269789Sahrens 22701544Seschrock default: 22712082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2272789Sahrens } 2273789Sahrens 22742082Seschrock return (-1); 2275789Sahrens } 2276789Sahrens 2277789Sahrens /* 2278789Sahrens * Detach the specified device. 2279789Sahrens */ 2280789Sahrens int 2281789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2282789Sahrens { 2283789Sahrens zfs_cmd_t zc = { 0 }; 2284789Sahrens char msg[1024]; 22852082Seschrock nvlist_t *tgt; 22865450Sbrendan boolean_t avail_spare, l2cache; 22872082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2288789Sahrens 22891544Seschrock (void) snprintf(msg, sizeof (msg), 22901544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 22911544Seschrock 2292789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22937326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22947326SEric.Schrock@Sun.COM NULL)) == 0) 22952082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2296789Sahrens 22972468Sek110237 if (avail_spare) 22982082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22992082Seschrock 23005450Sbrendan if (l2cache) 23015450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 23025450Sbrendan 23032082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 23042082Seschrock 23054543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2306789Sahrens return (0); 2307789Sahrens 2308789Sahrens switch (errno) { 2309789Sahrens 23101544Seschrock case ENOTSUP: 2311789Sahrens /* 2312789Sahrens * Can't detach from this type of vdev. 2313789Sahrens */ 23142082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 23152082Seschrock "applicable to mirror and replacing vdevs")); 23162082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2317789Sahrens break; 2318789Sahrens 23191544Seschrock case EBUSY: 2320789Sahrens /* 2321789Sahrens * There are no other replicas of this device. 2322789Sahrens */ 23232082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2324789Sahrens break; 2325789Sahrens 23261544Seschrock default: 23272082Seschrock (void) zpool_standard_error(hdl, errno, msg); 23281544Seschrock } 23291544Seschrock 23302082Seschrock return (-1); 23312082Seschrock } 23322082Seschrock 23332082Seschrock /* 23345450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 23355450Sbrendan * and level 2 cache devices. 23362082Seschrock */ 23372082Seschrock int 23382082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 23392082Seschrock { 23402082Seschrock zfs_cmd_t zc = { 0 }; 23412082Seschrock char msg[1024]; 23422082Seschrock nvlist_t *tgt; 234310594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 23442082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 234510594SGeorge.Wilson@Sun.COM uint64_t version; 23462082Seschrock 23472082Seschrock (void) snprintf(msg, sizeof (msg), 23482082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 23492082Seschrock 23502082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23517326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 235210594SGeorge.Wilson@Sun.COM &islog)) == 0) 23532082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 235410594SGeorge.Wilson@Sun.COM /* 235510594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 235610594SGeorge.Wilson@Sun.COM */ 235710594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 23582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 235910594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 236010594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 23612082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23622082Seschrock } 23632082Seschrock 236410594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 236510594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 236610594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 236710594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 236810594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 236910594SGeorge.Wilson@Sun.COM } 237010594SGeorge.Wilson@Sun.COM 23712082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 23722082Seschrock 23734543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 23742082Seschrock return (0); 23752082Seschrock 23762082Seschrock return (zpool_standard_error(hdl, errno, msg)); 23771544Seschrock } 23781544Seschrock 23791544Seschrock /* 23801544Seschrock * Clear the errors for the pool, or the particular device if specified. 23811544Seschrock */ 23821544Seschrock int 23831544Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 23841544Seschrock { 23851544Seschrock zfs_cmd_t zc = { 0 }; 23861544Seschrock char msg[1024]; 23872082Seschrock nvlist_t *tgt; 23885450Sbrendan boolean_t avail_spare, l2cache; 23892082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23901544Seschrock 23911544Seschrock if (path) 23921544Seschrock (void) snprintf(msg, sizeof (msg), 23931544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 23942676Seschrock path); 23951544Seschrock else 23961544Seschrock (void) snprintf(msg, sizeof (msg), 23971544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 23981544Seschrock zhp->zpool_name); 23991544Seschrock 24001544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24012082Seschrock if (path) { 24025450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 24037326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 24042082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 24052082Seschrock 24065450Sbrendan /* 24075450Sbrendan * Don't allow error clearing for hot spares. Do allow 24085450Sbrendan * error clearing for l2cache devices. 24095450Sbrendan */ 24102468Sek110237 if (avail_spare) 24112082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 24122082Seschrock 24132082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 24142082Seschrock &zc.zc_guid) == 0); 24151544Seschrock } 24161544Seschrock 24174543Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 24181544Seschrock return (0); 24191544Seschrock 24202082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2421789Sahrens } 2422789Sahrens 24233126Sahl /* 24244451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 24254451Seschrock */ 24264451Seschrock int 24274451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 24284451Seschrock { 24294451Seschrock zfs_cmd_t zc = { 0 }; 24304451Seschrock char msg[1024]; 24314451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 24324451Seschrock 24334451Seschrock (void) snprintf(msg, sizeof (msg), 24344451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 24354451Seschrock guid); 24364451Seschrock 24374451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24384451Seschrock zc.zc_guid = guid; 24394451Seschrock 24404451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 24414451Seschrock return (0); 24424451Seschrock 24434451Seschrock return (zpool_standard_error(hdl, errno, msg)); 24444451Seschrock } 24454451Seschrock 24464451Seschrock /* 24471354Seschrock * Convert from a devid string to a path. 24481354Seschrock */ 24491354Seschrock static char * 24501354Seschrock devid_to_path(char *devid_str) 24511354Seschrock { 24521354Seschrock ddi_devid_t devid; 24531354Seschrock char *minor; 24541354Seschrock char *path; 24551354Seschrock devid_nmlist_t *list = NULL; 24561354Seschrock int ret; 24571354Seschrock 24581354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 24591354Seschrock return (NULL); 24601354Seschrock 24611354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 24621354Seschrock 24631354Seschrock devid_str_free(minor); 24641354Seschrock devid_free(devid); 24651354Seschrock 24661354Seschrock if (ret != 0) 24671354Seschrock return (NULL); 24681354Seschrock 24692082Seschrock if ((path = strdup(list[0].devname)) == NULL) 24702082Seschrock return (NULL); 24712082Seschrock 24721354Seschrock devid_free_nmlist(list); 24731354Seschrock 24741354Seschrock return (path); 24751354Seschrock } 24761354Seschrock 24771354Seschrock /* 24781354Seschrock * Convert from a path to a devid string. 24791354Seschrock */ 24801354Seschrock static char * 24811354Seschrock path_to_devid(const char *path) 24821354Seschrock { 24831354Seschrock int fd; 24841354Seschrock ddi_devid_t devid; 24851354Seschrock char *minor, *ret; 24861354Seschrock 24871354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 24881354Seschrock return (NULL); 24891354Seschrock 24901354Seschrock minor = NULL; 24911354Seschrock ret = NULL; 24921354Seschrock if (devid_get(fd, &devid) == 0) { 24931354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 24941354Seschrock ret = devid_str_encode(devid, minor); 24951354Seschrock if (minor != NULL) 24961354Seschrock devid_str_free(minor); 24971354Seschrock devid_free(devid); 24981354Seschrock } 24991354Seschrock (void) close(fd); 25001354Seschrock 25011354Seschrock return (ret); 25021354Seschrock } 25031354Seschrock 25041354Seschrock /* 25051354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 25061354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 25071354Seschrock * type 'zpool status', and we'll display the correct information anyway. 25081354Seschrock */ 25091354Seschrock static void 25101354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 25111354Seschrock { 25121354Seschrock zfs_cmd_t zc = { 0 }; 25131354Seschrock 25141354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25152676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 25161354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 25171544Seschrock &zc.zc_guid) == 0); 25181354Seschrock 25192082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 25201354Seschrock } 25211354Seschrock 25221354Seschrock /* 25231354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 25241354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 25251354Seschrock * We also check if this is a whole disk, in which case we strip off the 25261354Seschrock * trailing 's0' slice name. 25271354Seschrock * 25281354Seschrock * This routine is also responsible for identifying when disks have been 25291354Seschrock * reconfigured in a new location. The kernel will have opened the device by 25301354Seschrock * devid, but the path will still refer to the old location. To catch this, we 25311354Seschrock * first do a path -> devid translation (which is fast for the common case). If 25321354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 25331354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 25341354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 25351354Seschrock * of these checks. 25361354Seschrock */ 25371354Seschrock char * 253810594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 253910594SGeorge.Wilson@Sun.COM boolean_t verbose) 25401354Seschrock { 25411354Seschrock char *path, *devid; 25421544Seschrock uint64_t value; 25431544Seschrock char buf[64]; 25444451Seschrock vdev_stat_t *vs; 25454451Seschrock uint_t vsc; 25461354Seschrock 25471544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 25481544Seschrock &value) == 0) { 25491544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 25501544Seschrock &value) == 0); 25512856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 25522856Snd150628 (u_longlong_t)value); 25531544Seschrock path = buf; 25541544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 25551354Seschrock 25564451Seschrock /* 25574451Seschrock * If the device is dead (faulted, offline, etc) then don't 25584451Seschrock * bother opening it. Otherwise we may be forcing the user to 25594451Seschrock * open a misbehaving device, which can have undesirable 25604451Seschrock * effects. 25614451Seschrock */ 25624451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 25634451Seschrock (uint64_t **)&vs, &vsc) != 0 || 25644451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 25654451Seschrock zhp != NULL && 25661354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 25671354Seschrock /* 25681354Seschrock * Determine if the current path is correct. 25691354Seschrock */ 25701354Seschrock char *newdevid = path_to_devid(path); 25711354Seschrock 25721354Seschrock if (newdevid == NULL || 25731354Seschrock strcmp(devid, newdevid) != 0) { 25741354Seschrock char *newpath; 25751354Seschrock 25761354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 25771354Seschrock /* 25781354Seschrock * Update the path appropriately. 25791354Seschrock */ 25801354Seschrock set_path(zhp, nv, newpath); 25812082Seschrock if (nvlist_add_string(nv, 25822082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 25832082Seschrock verify(nvlist_lookup_string(nv, 25842082Seschrock ZPOOL_CONFIG_PATH, 25852082Seschrock &path) == 0); 25861354Seschrock free(newpath); 25871354Seschrock } 25881354Seschrock } 25891354Seschrock 25902082Seschrock if (newdevid) 25912082Seschrock devid_str_free(newdevid); 25921354Seschrock } 25931354Seschrock 25941354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 25951354Seschrock path += 9; 25961354Seschrock 25971354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 25981544Seschrock &value) == 0 && value) { 25992082Seschrock char *tmp = zfs_strdup(hdl, path); 26002082Seschrock if (tmp == NULL) 26012082Seschrock return (NULL); 26021354Seschrock tmp[strlen(path) - 2] = '\0'; 26031354Seschrock return (tmp); 26041354Seschrock } 26051354Seschrock } else { 26061354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 26072082Seschrock 26082082Seschrock /* 26092082Seschrock * If it's a raidz device, we need to stick in the parity level. 26102082Seschrock */ 26112082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 26122082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 26132082Seschrock &value) == 0); 26142082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 26152856Snd150628 (u_longlong_t)value); 26162082Seschrock path = buf; 26172082Seschrock } 261810594SGeorge.Wilson@Sun.COM 261910594SGeorge.Wilson@Sun.COM /* 262010594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 262110594SGeorge.Wilson@Sun.COM * naming convention. 262210594SGeorge.Wilson@Sun.COM */ 262310594SGeorge.Wilson@Sun.COM if (verbose) { 262410594SGeorge.Wilson@Sun.COM uint64_t id; 262510594SGeorge.Wilson@Sun.COM 262610594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 262710594SGeorge.Wilson@Sun.COM &id) == 0); 262810594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 262910594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 263010594SGeorge.Wilson@Sun.COM path = buf; 263110594SGeorge.Wilson@Sun.COM } 26321354Seschrock } 26331354Seschrock 26342082Seschrock return (zfs_strdup(hdl, path)); 26351354Seschrock } 26361544Seschrock 26371544Seschrock static int 26381544Seschrock zbookmark_compare(const void *a, const void *b) 26391544Seschrock { 26401544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 26411544Seschrock } 26421544Seschrock 26431544Seschrock /* 26441544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 26451544Seschrock * caller. 26461544Seschrock */ 26471544Seschrock int 26483444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 26491544Seschrock { 26501544Seschrock zfs_cmd_t zc = { 0 }; 26511544Seschrock uint64_t count; 26522676Seschrock zbookmark_t *zb = NULL; 26533444Sek110237 int i; 26541544Seschrock 26551544Seschrock /* 26561544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 26571544Seschrock * has increased, allocate more space and continue until we get the 26581544Seschrock * entire list. 26591544Seschrock */ 26601544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 26611544Seschrock &count) == 0); 26624820Sek110237 if (count == 0) 26634820Sek110237 return (0); 26642676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 26652856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 26662082Seschrock return (-1); 26672676Seschrock zc.zc_nvlist_dst_size = count; 26681544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 26691544Seschrock for (;;) { 26702082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 26712082Seschrock &zc) != 0) { 26722676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 26731544Seschrock if (errno == ENOMEM) { 26743823Svb160487 count = zc.zc_nvlist_dst_size; 26752676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 26763823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 26773823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 26782082Seschrock return (-1); 26791544Seschrock } else { 26801544Seschrock return (-1); 26811544Seschrock } 26821544Seschrock } else { 26831544Seschrock break; 26841544Seschrock } 26851544Seschrock } 26861544Seschrock 26871544Seschrock /* 26881544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 26891544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 26902676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 26911544Seschrock * _not_ copied as part of the process. So we point the start of our 26921544Seschrock * array appropriate and decrement the total number of elements. 26931544Seschrock */ 26942676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 26952676Seschrock zc.zc_nvlist_dst_size; 26962676Seschrock count -= zc.zc_nvlist_dst_size; 26971544Seschrock 26981544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 26991544Seschrock 27003444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 27011544Seschrock 27021544Seschrock /* 27033444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 27041544Seschrock */ 27051544Seschrock for (i = 0; i < count; i++) { 27061544Seschrock nvlist_t *nv; 27071544Seschrock 27083700Sek110237 /* ignoring zb_blkid and zb_level for now */ 27093700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 27103700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 27111544Seschrock continue; 27121544Seschrock 27133444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 27143444Sek110237 goto nomem; 27153444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 27163444Sek110237 zb[i].zb_objset) != 0) { 27173444Sek110237 nvlist_free(nv); 27182082Seschrock goto nomem; 27193444Sek110237 } 27203444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 27213444Sek110237 zb[i].zb_object) != 0) { 27223444Sek110237 nvlist_free(nv); 27233444Sek110237 goto nomem; 27241544Seschrock } 27253444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 27263444Sek110237 nvlist_free(nv); 27273444Sek110237 goto nomem; 27283444Sek110237 } 27293444Sek110237 nvlist_free(nv); 27301544Seschrock } 27311544Seschrock 27323265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 27331544Seschrock return (0); 27342082Seschrock 27352082Seschrock nomem: 27362676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 27372082Seschrock return (no_memory(zhp->zpool_hdl)); 27381544Seschrock } 27391760Seschrock 27401760Seschrock /* 27411760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 27421760Seschrock */ 27431760Seschrock int 27445094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 27451760Seschrock { 27461760Seschrock zfs_cmd_t zc = { 0 }; 27472082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 27481760Seschrock 27491760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 27505094Slling zc.zc_cookie = new_version; 27515094Slling 27524543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 27533237Slling return (zpool_standard_error_fmt(hdl, errno, 27542082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 27552082Seschrock zhp->zpool_name)); 27561760Seschrock return (0); 27571760Seschrock } 27582926Sek110237 27594988Sek110237 void 27604988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 27614988Sek110237 char *history_str) 27624988Sek110237 { 27634988Sek110237 int i; 27644988Sek110237 27654988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 27664988Sek110237 for (i = 1; i < argc; i++) { 27674988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 27684988Sek110237 HIS_MAX_RECORD_LEN) 27694988Sek110237 break; 27704988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 27714988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 27724988Sek110237 } 27734988Sek110237 } 27744988Sek110237 27752926Sek110237 /* 27764988Sek110237 * Stage command history for logging. 27772926Sek110237 */ 27784988Sek110237 int 27794988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 27802926Sek110237 { 27814988Sek110237 if (history_str == NULL) 27824988Sek110237 return (EINVAL); 27834988Sek110237 27844988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 27854988Sek110237 return (EINVAL); 27862926Sek110237 27874715Sek110237 if (hdl->libzfs_log_str != NULL) 27884543Smarks free(hdl->libzfs_log_str); 27892926Sek110237 27904988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 27914988Sek110237 return (no_memory(hdl)); 27924543Smarks 27934988Sek110237 return (0); 27942926Sek110237 } 27952926Sek110237 27962926Sek110237 /* 27972926Sek110237 * Perform ioctl to get some command history of a pool. 27982926Sek110237 * 27992926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 28002926Sek110237 * logical offset of the history buffer to start reading from. 28012926Sek110237 * 28022926Sek110237 * Upon return, 'off' is the next logical offset to read from and 28032926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 28042926Sek110237 */ 28052926Sek110237 static int 28062926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 28072926Sek110237 { 28082926Sek110237 zfs_cmd_t zc = { 0 }; 28092926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 28102926Sek110237 28112926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28122926Sek110237 28132926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 28142926Sek110237 zc.zc_history_len = *len; 28152926Sek110237 zc.zc_history_offset = *off; 28162926Sek110237 28172926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 28182926Sek110237 switch (errno) { 28192926Sek110237 case EPERM: 28203237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 28213237Slling dgettext(TEXT_DOMAIN, 28222926Sek110237 "cannot show history for pool '%s'"), 28232926Sek110237 zhp->zpool_name)); 28242926Sek110237 case ENOENT: 28253237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 28262926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 28272926Sek110237 "'%s'"), zhp->zpool_name)); 28283863Sek110237 case ENOTSUP: 28293863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 28303863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 28313863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 28322926Sek110237 default: 28333237Slling return (zpool_standard_error_fmt(hdl, errno, 28342926Sek110237 dgettext(TEXT_DOMAIN, 28352926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 28362926Sek110237 } 28372926Sek110237 } 28382926Sek110237 28392926Sek110237 *len = zc.zc_history_len; 28402926Sek110237 *off = zc.zc_history_offset; 28412926Sek110237 28422926Sek110237 return (0); 28432926Sek110237 } 28442926Sek110237 28452926Sek110237 /* 28462926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 28472926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 28482926Sek110237 * processed as there wasn't a complete record. 28492926Sek110237 */ 2850*10685SGeorge.Wilson@Sun.COM int 28512926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 28522926Sek110237 nvlist_t ***records, uint_t *numrecords) 28532926Sek110237 { 28542926Sek110237 uint64_t reclen; 28552926Sek110237 nvlist_t *nv; 28562926Sek110237 int i; 28572926Sek110237 28582926Sek110237 while (bytes_read > sizeof (reclen)) { 28592926Sek110237 28602926Sek110237 /* get length of packed record (stored as little endian) */ 28612926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 28622926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 28632926Sek110237 28642926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 28652926Sek110237 break; 28662926Sek110237 28672926Sek110237 /* unpack record */ 28682926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 28692926Sek110237 return (ENOMEM); 28702926Sek110237 bytes_read -= sizeof (reclen) + reclen; 28712926Sek110237 buf += sizeof (reclen) + reclen; 28722926Sek110237 28732926Sek110237 /* add record to nvlist array */ 28742926Sek110237 (*numrecords)++; 28752926Sek110237 if (ISP2(*numrecords + 1)) { 28762926Sek110237 *records = realloc(*records, 28772926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 28782926Sek110237 } 28792926Sek110237 (*records)[*numrecords - 1] = nv; 28802926Sek110237 } 28812926Sek110237 28822926Sek110237 *leftover = bytes_read; 28832926Sek110237 return (0); 28842926Sek110237 } 28852926Sek110237 28862926Sek110237 #define HIS_BUF_LEN (128*1024) 28872926Sek110237 28882926Sek110237 /* 28892926Sek110237 * Retrieve the command history of a pool. 28902926Sek110237 */ 28912926Sek110237 int 28922926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 28932926Sek110237 { 28942926Sek110237 char buf[HIS_BUF_LEN]; 28952926Sek110237 uint64_t off = 0; 28962926Sek110237 nvlist_t **records = NULL; 28972926Sek110237 uint_t numrecords = 0; 28982926Sek110237 int err, i; 28992926Sek110237 29002926Sek110237 do { 29012926Sek110237 uint64_t bytes_read = sizeof (buf); 29022926Sek110237 uint64_t leftover; 29032926Sek110237 29042926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 29052926Sek110237 break; 29062926Sek110237 29072926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 29082926Sek110237 if (!bytes_read) 29092926Sek110237 break; 29102926Sek110237 29112926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 29122926Sek110237 &leftover, &records, &numrecords)) != 0) 29132926Sek110237 break; 29142926Sek110237 off -= leftover; 29152926Sek110237 29162926Sek110237 /* CONSTCOND */ 29172926Sek110237 } while (1); 29182926Sek110237 29192926Sek110237 if (!err) { 29202926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 29212926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 29222926Sek110237 records, numrecords) == 0); 29232926Sek110237 } 29242926Sek110237 for (i = 0; i < numrecords; i++) 29252926Sek110237 nvlist_free(records[i]); 29262926Sek110237 free(records); 29272926Sek110237 29282926Sek110237 return (err); 29292926Sek110237 } 29303444Sek110237 29313444Sek110237 void 29323444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 29333444Sek110237 char *pathname, size_t len) 29343444Sek110237 { 29353444Sek110237 zfs_cmd_t zc = { 0 }; 29363444Sek110237 boolean_t mounted = B_FALSE; 29373444Sek110237 char *mntpnt = NULL; 29383444Sek110237 char dsname[MAXNAMELEN]; 29393444Sek110237 29403444Sek110237 if (dsobj == 0) { 29413444Sek110237 /* special case for the MOS */ 29423444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 29433444Sek110237 return; 29443444Sek110237 } 29453444Sek110237 29463444Sek110237 /* get the dataset's name */ 29473444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29483444Sek110237 zc.zc_obj = dsobj; 29493444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 29503444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 29513444Sek110237 /* just write out a path of two object numbers */ 29523444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 29533444Sek110237 dsobj, obj); 29543444Sek110237 return; 29553444Sek110237 } 29563444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 29573444Sek110237 29583444Sek110237 /* find out if the dataset is mounted */ 29593444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 29603444Sek110237 29613444Sek110237 /* get the corrupted object's path */ 29623444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 29633444Sek110237 zc.zc_obj = obj; 29643444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 29653444Sek110237 &zc) == 0) { 29663444Sek110237 if (mounted) { 29673444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 29683444Sek110237 zc.zc_value); 29693444Sek110237 } else { 29703444Sek110237 (void) snprintf(pathname, len, "%s:%s", 29713444Sek110237 dsname, zc.zc_value); 29723444Sek110237 } 29733444Sek110237 } else { 29743444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 29753444Sek110237 } 29763444Sek110237 free(mntpnt); 29773444Sek110237 } 29783912Slling 29794276Staylor /* 29807042Sgw25295 * Read the EFI label from the config, if a label does not exist then 29817042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 29827042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 29837042Sgw25295 * partition. 29847042Sgw25295 */ 29857042Sgw25295 static int 29867042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 29877042Sgw25295 { 29887042Sgw25295 char *path; 29897042Sgw25295 int fd; 29907042Sgw25295 char diskname[MAXPATHLEN]; 29917042Sgw25295 int err = -1; 29927042Sgw25295 29937042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 29947042Sgw25295 return (err); 29957042Sgw25295 29967042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 29977042Sgw25295 strrchr(path, '/')); 29987042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 29997042Sgw25295 struct dk_gpt *vtoc; 30007042Sgw25295 30017042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 30027042Sgw25295 if (sb != NULL) 30037042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 30047042Sgw25295 efi_free(vtoc); 30057042Sgw25295 } 30067042Sgw25295 (void) close(fd); 30077042Sgw25295 } 30087042Sgw25295 return (err); 30097042Sgw25295 } 30107042Sgw25295 30117042Sgw25295 /* 30124276Staylor * determine where a partition starts on a disk in the current 30134276Staylor * configuration 30144276Staylor */ 30154276Staylor static diskaddr_t 30164276Staylor find_start_block(nvlist_t *config) 30174276Staylor { 30184276Staylor nvlist_t **child; 30194276Staylor uint_t c, children; 30204276Staylor diskaddr_t sb = MAXOFFSET_T; 30214276Staylor uint64_t wholedisk; 30224276Staylor 30234276Staylor if (nvlist_lookup_nvlist_array(config, 30244276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 30254276Staylor if (nvlist_lookup_uint64(config, 30264276Staylor ZPOOL_CONFIG_WHOLE_DISK, 30274276Staylor &wholedisk) != 0 || !wholedisk) { 30284276Staylor return (MAXOFFSET_T); 30294276Staylor } 30307042Sgw25295 if (read_efi_label(config, &sb) < 0) 30317042Sgw25295 sb = MAXOFFSET_T; 30324276Staylor return (sb); 30334276Staylor } 30344276Staylor 30354276Staylor for (c = 0; c < children; c++) { 30364276Staylor sb = find_start_block(child[c]); 30374276Staylor if (sb != MAXOFFSET_T) { 30384276Staylor return (sb); 30394276Staylor } 30404276Staylor } 30414276Staylor return (MAXOFFSET_T); 30424276Staylor } 30434276Staylor 30444276Staylor /* 30454276Staylor * Label an individual disk. The name provided is the short name, 30464276Staylor * stripped of any leading /dev path. 30474276Staylor */ 30484276Staylor int 30494276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 30504276Staylor { 30514276Staylor char path[MAXPATHLEN]; 30524276Staylor struct dk_gpt *vtoc; 30534276Staylor int fd; 30544276Staylor size_t resv = EFI_MIN_RESV_SIZE; 30554276Staylor uint64_t slice_size; 30564276Staylor diskaddr_t start_block; 30574276Staylor char errbuf[1024]; 30584276Staylor 30596289Smmusante /* prepare an error message just in case */ 30606289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 30616289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 30626289Smmusante 30634276Staylor if (zhp) { 30644276Staylor nvlist_t *nvroot; 30654276Staylor 30667965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 30677965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30687965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 30697965SGeorge.Wilson@Sun.COM "pools.")); 30707965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 30717965SGeorge.Wilson@Sun.COM } 30727965SGeorge.Wilson@Sun.COM 30734276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 30744276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 30754276Staylor 30764276Staylor if (zhp->zpool_start_block == 0) 30774276Staylor start_block = find_start_block(nvroot); 30784276Staylor else 30794276Staylor start_block = zhp->zpool_start_block; 30804276Staylor zhp->zpool_start_block = start_block; 30814276Staylor } else { 30824276Staylor /* new pool */ 30834276Staylor start_block = NEW_START_BLOCK; 30844276Staylor } 30854276Staylor 30864276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 30874276Staylor BACKUP_SLICE); 30884276Staylor 30894276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 30904276Staylor /* 30914276Staylor * This shouldn't happen. We've long since verified that this 30924276Staylor * is a valid device. 30934276Staylor */ 30946289Smmusante zfs_error_aux(hdl, 30956289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 30964276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 30974276Staylor } 30984276Staylor 30994276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 31004276Staylor /* 31014276Staylor * The only way this can fail is if we run out of memory, or we 31024276Staylor * were unable to read the disk's capacity 31034276Staylor */ 31044276Staylor if (errno == ENOMEM) 31054276Staylor (void) no_memory(hdl); 31064276Staylor 31074276Staylor (void) close(fd); 31086289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31096289Smmusante "unable to read disk capacity"), name); 31104276Staylor 31114276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 31124276Staylor } 31134276Staylor 31144276Staylor slice_size = vtoc->efi_last_u_lba + 1; 31154276Staylor slice_size -= EFI_MIN_RESV_SIZE; 31164276Staylor if (start_block == MAXOFFSET_T) 31174276Staylor start_block = NEW_START_BLOCK; 31184276Staylor slice_size -= start_block; 31194276Staylor 31204276Staylor vtoc->efi_parts[0].p_start = start_block; 31214276Staylor vtoc->efi_parts[0].p_size = slice_size; 31224276Staylor 31234276Staylor /* 31244276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 31254276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 31264276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 31274276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 31284276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 31294276Staylor * can get, in the absence of V_OTHER. 31304276Staylor */ 31314276Staylor vtoc->efi_parts[0].p_tag = V_USR; 31324276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 31334276Staylor 31344276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 31354276Staylor vtoc->efi_parts[8].p_size = resv; 31364276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 31374276Staylor 31384276Staylor if (efi_write(fd, vtoc) != 0) { 31394276Staylor /* 31404276Staylor * Some block drivers (like pcata) may not support EFI 31414276Staylor * GPT labels. Print out a helpful error message dir- 31424276Staylor * ecting the user to manually label the disk and give 31434276Staylor * a specific slice. 31444276Staylor */ 31454276Staylor (void) close(fd); 31464276Staylor efi_free(vtoc); 31474276Staylor 31484276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31496289Smmusante "try using fdisk(1M) and then provide a specific slice")); 31504276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 31514276Staylor } 31524276Staylor 31534276Staylor (void) close(fd); 31544276Staylor efi_free(vtoc); 31554276Staylor return (0); 31564276Staylor } 31576423Sgw25295 31586423Sgw25295 static boolean_t 31596423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 31606423Sgw25295 { 31616423Sgw25295 char *type; 31626423Sgw25295 nvlist_t **child; 31636423Sgw25295 uint_t children, c; 31646423Sgw25295 31656423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 31666423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 31676423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 31686423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 316910594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 31706423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 31716423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31726423Sgw25295 "vdev type '%s' is not supported"), type); 31736423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 31746423Sgw25295 return (B_FALSE); 31756423Sgw25295 } 31766423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 31776423Sgw25295 &child, &children) == 0) { 31786423Sgw25295 for (c = 0; c < children; c++) { 31796423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 31806423Sgw25295 return (B_FALSE); 31816423Sgw25295 } 31826423Sgw25295 } 31836423Sgw25295 return (B_TRUE); 31846423Sgw25295 } 31856423Sgw25295 31866423Sgw25295 /* 31876423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 31886423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 31896423Sgw25295 */ 31906423Sgw25295 int 31916423Sgw25295 zvol_check_dump_config(char *arg) 31926423Sgw25295 { 31936423Sgw25295 zpool_handle_t *zhp = NULL; 31946423Sgw25295 nvlist_t *config, *nvroot; 31956423Sgw25295 char *p, *volname; 31966423Sgw25295 nvlist_t **top; 31976423Sgw25295 uint_t toplevels; 31986423Sgw25295 libzfs_handle_t *hdl; 31996423Sgw25295 char errbuf[1024]; 32006423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 32016423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 32026423Sgw25295 int ret = 1; 32036423Sgw25295 32046423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 32056423Sgw25295 return (-1); 32066423Sgw25295 } 32076423Sgw25295 32086423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 32096423Sgw25295 "dump is not supported on device '%s'"), arg); 32106423Sgw25295 32116423Sgw25295 if ((hdl = libzfs_init()) == NULL) 32126423Sgw25295 return (1); 32136423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 32146423Sgw25295 32156423Sgw25295 volname = arg + pathlen; 32166423Sgw25295 32176423Sgw25295 /* check the configuration of the pool */ 32186423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 32196423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32206423Sgw25295 "malformed dataset name")); 32216423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 32226423Sgw25295 return (1); 32236423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 32246423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32256423Sgw25295 "dataset name is too long")); 32266423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 32276423Sgw25295 return (1); 32286423Sgw25295 } else { 32296423Sgw25295 (void) strncpy(poolname, volname, p - volname); 32306423Sgw25295 poolname[p - volname] = '\0'; 32316423Sgw25295 } 32326423Sgw25295 32336423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 32346423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32356423Sgw25295 "could not open pool '%s'"), poolname); 32366423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 32376423Sgw25295 goto out; 32386423Sgw25295 } 32396423Sgw25295 config = zpool_get_config(zhp, NULL); 32406423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 32416423Sgw25295 &nvroot) != 0) { 32426423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32436423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 32446423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 32456423Sgw25295 goto out; 32466423Sgw25295 } 32476423Sgw25295 32486423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 32496423Sgw25295 &top, &toplevels) == 0); 32506423Sgw25295 if (toplevels != 1) { 32516423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32526423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 32536423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 32546423Sgw25295 goto out; 32556423Sgw25295 } 32566423Sgw25295 32576423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 32586423Sgw25295 goto out; 32596423Sgw25295 } 32606423Sgw25295 ret = 0; 32616423Sgw25295 32626423Sgw25295 out: 32636423Sgw25295 if (zhp) 32646423Sgw25295 zpool_close(zhp); 32656423Sgw25295 libzfs_fini(hdl); 32666423Sgw25295 return (ret); 32676423Sgw25295 } 3268