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 /* 23*11422SMark.Musante@Sun.COM * Copyright 2010 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" 4410921STim.Haley@Sun.COM #include "zfs_comutil.h" 45789Sahrens 4610685SGeorge.Wilson@Sun.COM const char *hist_event_table[LOG_END] = { 4710685SGeorge.Wilson@Sun.COM "invalid event", 4810685SGeorge.Wilson@Sun.COM "pool create", 4910685SGeorge.Wilson@Sun.COM "vdev add", 5010685SGeorge.Wilson@Sun.COM "pool remove", 5110685SGeorge.Wilson@Sun.COM "pool destroy", 5210685SGeorge.Wilson@Sun.COM "pool export", 5310685SGeorge.Wilson@Sun.COM "pool import", 5410685SGeorge.Wilson@Sun.COM "vdev attach", 5510685SGeorge.Wilson@Sun.COM "vdev replace", 5610685SGeorge.Wilson@Sun.COM "vdev detach", 5710685SGeorge.Wilson@Sun.COM "vdev online", 5810685SGeorge.Wilson@Sun.COM "vdev offline", 5910685SGeorge.Wilson@Sun.COM "vdev upgrade", 6010685SGeorge.Wilson@Sun.COM "pool clear", 6110685SGeorge.Wilson@Sun.COM "pool scrub", 6210685SGeorge.Wilson@Sun.COM "pool property set", 6310685SGeorge.Wilson@Sun.COM "create", 6410685SGeorge.Wilson@Sun.COM "clone", 6510685SGeorge.Wilson@Sun.COM "destroy", 6610685SGeorge.Wilson@Sun.COM "destroy_begin_sync", 6710685SGeorge.Wilson@Sun.COM "inherit", 6810685SGeorge.Wilson@Sun.COM "property set", 6910685SGeorge.Wilson@Sun.COM "quota set", 7010685SGeorge.Wilson@Sun.COM "permission update", 7110685SGeorge.Wilson@Sun.COM "permission remove", 7210685SGeorge.Wilson@Sun.COM "permission who remove", 7310685SGeorge.Wilson@Sun.COM "promote", 7410685SGeorge.Wilson@Sun.COM "receive", 7510685SGeorge.Wilson@Sun.COM "rename", 7610685SGeorge.Wilson@Sun.COM "reservation set", 7710685SGeorge.Wilson@Sun.COM "replay_inc_sync", 7810685SGeorge.Wilson@Sun.COM "replay_full_sync", 7910685SGeorge.Wilson@Sun.COM "rollback", 8010685SGeorge.Wilson@Sun.COM "snapshot", 8110685SGeorge.Wilson@Sun.COM "filesystem version upgrade", 8210685SGeorge.Wilson@Sun.COM "refquota set", 8310685SGeorge.Wilson@Sun.COM "refreservation set", 8410685SGeorge.Wilson@Sun.COM "pool scrub done", 8510685SGeorge.Wilson@Sun.COM "user hold", 8610685SGeorge.Wilson@Sun.COM "user release", 87*11422SMark.Musante@Sun.COM "pool split", 8810685SGeorge.Wilson@Sun.COM }; 8910685SGeorge.Wilson@Sun.COM 907042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 915094Slling 927965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 937965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 947965SGeorge.Wilson@Sun.COM #else 957965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 967965SGeorge.Wilson@Sun.COM #endif 977965SGeorge.Wilson@Sun.COM 989816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 999816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 1009816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 1019816SGeorge.Wilson@Sun.COM 1025094Slling /* 1035094Slling * ==================================================================== 1045094Slling * zpool property functions 1055094Slling * ==================================================================== 1065094Slling */ 1075094Slling 1085094Slling static int 1095094Slling zpool_get_all_props(zpool_handle_t *zhp) 1105094Slling { 1115094Slling zfs_cmd_t zc = { 0 }; 1125094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 1135094Slling 1145094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1155094Slling 1165094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 1175094Slling return (-1); 1185094Slling 1195094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 1205094Slling if (errno == ENOMEM) { 1215094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 1225094Slling zcmd_free_nvlists(&zc); 1235094Slling return (-1); 1245094Slling } 1255094Slling } else { 1265094Slling zcmd_free_nvlists(&zc); 1275094Slling return (-1); 1285094Slling } 1295094Slling } 1305094Slling 1315094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 1325094Slling zcmd_free_nvlists(&zc); 1335094Slling return (-1); 1345094Slling } 1355094Slling 1365094Slling zcmd_free_nvlists(&zc); 1375094Slling 1385094Slling return (0); 1395094Slling } 1405094Slling 1415094Slling static int 1425094Slling zpool_props_refresh(zpool_handle_t *zhp) 1435094Slling { 1445094Slling nvlist_t *old_props; 1455094Slling 1465094Slling old_props = zhp->zpool_props; 1475094Slling 1485094Slling if (zpool_get_all_props(zhp) != 0) 1495094Slling return (-1); 1505094Slling 1515094Slling nvlist_free(old_props); 1525094Slling return (0); 1535094Slling } 1545094Slling 1555094Slling static char * 1565094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1575094Slling zprop_source_t *src) 1585094Slling { 1595094Slling nvlist_t *nv, *nvl; 1605094Slling uint64_t ival; 1615094Slling char *value; 1625094Slling zprop_source_t source; 1635094Slling 1645094Slling nvl = zhp->zpool_props; 1655094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1665094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1675094Slling source = ival; 1685094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1695094Slling } else { 1705094Slling source = ZPROP_SRC_DEFAULT; 1715094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1725094Slling value = "-"; 1735094Slling } 1745094Slling 1755094Slling if (src) 1765094Slling *src = source; 1775094Slling 1785094Slling return (value); 1795094Slling } 1805094Slling 1815094Slling uint64_t 1825094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1835094Slling { 1845094Slling nvlist_t *nv, *nvl; 1855094Slling uint64_t value; 1865094Slling zprop_source_t source; 1875094Slling 1887294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1897294Sperrin /* 1907294Sperrin * zpool_get_all_props() has most likely failed because 1917294Sperrin * the pool is faulted, but if all we need is the top level 1927294Sperrin * vdev's guid then get it from the zhp config nvlist. 1937294Sperrin */ 1947294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1957294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1967294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1977294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1987294Sperrin == 0)) { 1997294Sperrin return (value); 2007294Sperrin } 2015094Slling return (zpool_prop_default_numeric(prop)); 2027294Sperrin } 2035094Slling 2045094Slling nvl = zhp->zpool_props; 2055094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 2065094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 2075094Slling source = value; 2085094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 2095094Slling } else { 2105094Slling source = ZPROP_SRC_DEFAULT; 2115094Slling value = zpool_prop_default_numeric(prop); 2125094Slling } 2135094Slling 2145094Slling if (src) 2155094Slling *src = source; 2165094Slling 2175094Slling return (value); 2185094Slling } 2195094Slling 2205094Slling /* 2215094Slling * Map VDEV STATE to printed strings. 2225094Slling */ 2235094Slling char * 2245094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 2255094Slling { 2265094Slling switch (state) { 2275094Slling case VDEV_STATE_CLOSED: 2285094Slling case VDEV_STATE_OFFLINE: 2295094Slling return (gettext("OFFLINE")); 2305094Slling case VDEV_STATE_REMOVED: 2315094Slling return (gettext("REMOVED")); 2325094Slling case VDEV_STATE_CANT_OPEN: 2337294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 2345094Slling return (gettext("FAULTED")); 235*11422SMark.Musante@Sun.COM else if (aux == VDEV_AUX_SPLIT_POOL) 236*11422SMark.Musante@Sun.COM return (gettext("SPLIT")); 2375094Slling else 2385094Slling return (gettext("UNAVAIL")); 2395094Slling case VDEV_STATE_FAULTED: 2405094Slling return (gettext("FAULTED")); 2415094Slling case VDEV_STATE_DEGRADED: 2425094Slling return (gettext("DEGRADED")); 2435094Slling case VDEV_STATE_HEALTHY: 2445094Slling return (gettext("ONLINE")); 2455094Slling } 2465094Slling 2475094Slling return (gettext("UNKNOWN")); 2485094Slling } 2495094Slling 2505094Slling /* 2515094Slling * Get a zpool property value for 'prop' and return the value in 2525094Slling * a pre-allocated buffer. 2535094Slling */ 2545094Slling int 2555094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2565094Slling zprop_source_t *srctype) 2575094Slling { 2585094Slling uint64_t intval; 2595094Slling const char *strval; 2605094Slling zprop_source_t src = ZPROP_SRC_NONE; 2615094Slling nvlist_t *nvroot; 2625094Slling vdev_stat_t *vs; 2635094Slling uint_t vsc; 2645094Slling 2655094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2668525SEric.Schrock@Sun.COM switch (prop) { 2678525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2685094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2698525SEric.Schrock@Sun.COM break; 2708525SEric.Schrock@Sun.COM 2718525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2725094Slling (void) strlcpy(buf, "FAULTED", len); 2738525SEric.Schrock@Sun.COM break; 2748525SEric.Schrock@Sun.COM 2758525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2768525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2778525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2788525SEric.Schrock@Sun.COM break; 2798525SEric.Schrock@Sun.COM 2808525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2818525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2828525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2838525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2848525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2858525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2868525SEric.Schrock@Sun.COM len); 2878525SEric.Schrock@Sun.COM if (srctype != NULL) 2888525SEric.Schrock@Sun.COM *srctype = src; 2898525SEric.Schrock@Sun.COM return (0); 2908525SEric.Schrock@Sun.COM } 2918525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2928525SEric.Schrock@Sun.COM default: 2935094Slling (void) strlcpy(buf, "-", len); 2948525SEric.Schrock@Sun.COM break; 2958525SEric.Schrock@Sun.COM } 2968525SEric.Schrock@Sun.COM 2978525SEric.Schrock@Sun.COM if (srctype != NULL) 2988525SEric.Schrock@Sun.COM *srctype = src; 2995094Slling return (0); 3005094Slling } 3015094Slling 3025094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 3035094Slling prop != ZPOOL_PROP_NAME) 3045094Slling return (-1); 3055094Slling 3065094Slling switch (zpool_prop_get_type(prop)) { 3075094Slling case PROP_TYPE_STRING: 3085094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 3095094Slling len); 3105094Slling break; 3115094Slling 3125094Slling case PROP_TYPE_NUMBER: 3135094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3145094Slling 3155094Slling switch (prop) { 3165094Slling case ZPOOL_PROP_SIZE: 31710956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_ALLOCATED: 31810956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_FREE: 3195094Slling (void) zfs_nicenum(intval, buf, len); 3205094Slling break; 3215094Slling 3225094Slling case ZPOOL_PROP_CAPACITY: 3235094Slling (void) snprintf(buf, len, "%llu%%", 3245094Slling (u_longlong_t)intval); 3255094Slling break; 3265094Slling 32710922SJeff.Bonwick@Sun.COM case ZPOOL_PROP_DEDUPRATIO: 32810922SJeff.Bonwick@Sun.COM (void) snprintf(buf, len, "%llu.%02llux", 32910922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval / 100), 33010922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval % 100)); 33110922SJeff.Bonwick@Sun.COM break; 33210922SJeff.Bonwick@Sun.COM 3335094Slling case ZPOOL_PROP_HEALTH: 3345094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 3355094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 3365094Slling verify(nvlist_lookup_uint64_array(nvroot, 3375094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 3385094Slling 3395094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 3405094Slling vs->vs_aux), len); 3415094Slling break; 3425094Slling default: 3435094Slling (void) snprintf(buf, len, "%llu", intval); 3445094Slling } 3455094Slling break; 3465094Slling 3475094Slling case PROP_TYPE_INDEX: 3485094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3495094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3505094Slling != 0) 3515094Slling return (-1); 3525094Slling (void) strlcpy(buf, strval, len); 3535094Slling break; 3545094Slling 3555094Slling default: 3565094Slling abort(); 3575094Slling } 3585094Slling 3595094Slling if (srctype) 3605094Slling *srctype = src; 3615094Slling 3625094Slling return (0); 3635094Slling } 3645094Slling 3655094Slling /* 3665094Slling * Check if the bootfs name has the same pool name as it is set to. 3675094Slling * Assuming bootfs is a valid dataset name. 3685094Slling */ 3695094Slling static boolean_t 3705094Slling bootfs_name_valid(const char *pool, char *bootfs) 3715094Slling { 3725094Slling int len = strlen(pool); 3735094Slling 3747300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3755094Slling return (B_FALSE); 3765094Slling 3775094Slling if (strncmp(pool, bootfs, len) == 0 && 3785094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3795094Slling return (B_TRUE); 3805094Slling 3815094Slling return (B_FALSE); 3825094Slling } 3835094Slling 3845094Slling /* 3857042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3867042Sgw25295 * an EFI label. 3877042Sgw25295 */ 3887042Sgw25295 static boolean_t 3897042Sgw25295 pool_uses_efi(nvlist_t *config) 3907042Sgw25295 { 3917042Sgw25295 nvlist_t **child; 3927042Sgw25295 uint_t c, children; 3937042Sgw25295 3947042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3957042Sgw25295 &child, &children) != 0) 3967042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3977042Sgw25295 3987042Sgw25295 for (c = 0; c < children; c++) { 3997042Sgw25295 if (pool_uses_efi(child[c])) 4007042Sgw25295 return (B_TRUE); 4017042Sgw25295 } 4027042Sgw25295 return (B_FALSE); 4037042Sgw25295 } 4047042Sgw25295 4057965SGeorge.Wilson@Sun.COM static boolean_t 4067965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 4077965SGeorge.Wilson@Sun.COM { 4087965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 4097965SGeorge.Wilson@Sun.COM 4107965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 4117965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 4127965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 4137965SGeorge.Wilson@Sun.COM } 4147965SGeorge.Wilson@Sun.COM 4157965SGeorge.Wilson@Sun.COM 4167042Sgw25295 /* 4175094Slling * Given an nvlist of zpool properties to be set, validate that they are 4185094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 4195094Slling * specified as strings. 4205094Slling */ 4215094Slling static nvlist_t * 4227184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 4235094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 4245094Slling { 4255094Slling nvpair_t *elem; 4265094Slling nvlist_t *retprops; 4275094Slling zpool_prop_t prop; 4285094Slling char *strval; 4295094Slling uint64_t intval; 4305363Seschrock char *slash; 4315363Seschrock struct stat64 statbuf; 4327042Sgw25295 zpool_handle_t *zhp; 4337042Sgw25295 nvlist_t *nvroot; 4345094Slling 4355094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 4365094Slling (void) no_memory(hdl); 4375094Slling return (NULL); 4385094Slling } 4395094Slling 4405094Slling elem = NULL; 4415094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 4425094Slling const char *propname = nvpair_name(elem); 4435094Slling 4445094Slling /* 4455094Slling * Make sure this property is valid and applies to this type. 4465094Slling */ 4475094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4485094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4495094Slling "invalid property '%s'"), propname); 4505094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4515094Slling goto error; 4525094Slling } 4535094Slling 4545094Slling if (zpool_prop_readonly(prop)) { 4555094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4565094Slling "is readonly"), propname); 4575094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4585094Slling goto error; 4595094Slling } 4605094Slling 4615094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4625094Slling &strval, &intval, errbuf) != 0) 4635094Slling goto error; 4645094Slling 4655094Slling /* 4665094Slling * Perform additional checking for specific properties. 4675094Slling */ 4685094Slling switch (prop) { 4695094Slling case ZPOOL_PROP_VERSION: 4705094Slling if (intval < version || intval > SPA_VERSION) { 4715094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4725094Slling "property '%s' number %d is invalid."), 4735094Slling propname, intval); 4745094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4755094Slling goto error; 4765094Slling } 4775094Slling break; 4785094Slling 4795094Slling case ZPOOL_PROP_BOOTFS: 4805094Slling if (create_or_import) { 4815094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4825094Slling "property '%s' cannot be set at creation " 4835094Slling "or import time"), propname); 4845094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4855094Slling goto error; 4865094Slling } 4875094Slling 4885094Slling if (version < SPA_VERSION_BOOTFS) { 4895094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4905094Slling "pool must be upgraded to support " 4915094Slling "'%s' property"), propname); 4925094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4935094Slling goto error; 4945094Slling } 4955094Slling 4965094Slling /* 4975094Slling * bootfs property value has to be a dataset name and 4985094Slling * the dataset has to be in the same pool as it sets to. 4995094Slling */ 5005094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 5015094Slling strval)) { 5025094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 5035094Slling "is an invalid name"), strval); 5045094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 5055094Slling goto error; 5065094Slling } 5077042Sgw25295 5087042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 5097042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5107042Sgw25295 "could not open pool '%s'"), poolname); 5117042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 5127042Sgw25295 goto error; 5137042Sgw25295 } 5147042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 5157042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 5167042Sgw25295 5177042Sgw25295 /* 5187042Sgw25295 * bootfs property cannot be set on a disk which has 5197042Sgw25295 * been EFI labeled. 5207042Sgw25295 */ 5217042Sgw25295 if (pool_uses_efi(nvroot)) { 5227042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5237042Sgw25295 "property '%s' not supported on " 5247042Sgw25295 "EFI labeled devices"), propname); 5257042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 5267042Sgw25295 zpool_close(zhp); 5277042Sgw25295 goto error; 5287042Sgw25295 } 5297042Sgw25295 zpool_close(zhp); 5305094Slling break; 5315094Slling 5325094Slling case ZPOOL_PROP_ALTROOT: 5335094Slling if (!create_or_import) { 5345094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5355094Slling "property '%s' can only be set during pool " 5365094Slling "creation or import"), propname); 5375094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 5385094Slling goto error; 5395094Slling } 5405094Slling 5415094Slling if (strval[0] != '/') { 5425094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5435094Slling "bad alternate root '%s'"), strval); 5445094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5455094Slling goto error; 5465094Slling } 5475094Slling break; 5485363Seschrock 5495363Seschrock case ZPOOL_PROP_CACHEFILE: 5505363Seschrock if (strval[0] == '\0') 5515363Seschrock break; 5525363Seschrock 5535363Seschrock if (strcmp(strval, "none") == 0) 5545363Seschrock break; 5555363Seschrock 5565363Seschrock if (strval[0] != '/') { 5575363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5585363Seschrock "property '%s' must be empty, an " 5595363Seschrock "absolute path, or 'none'"), propname); 5605363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5615363Seschrock goto error; 5625363Seschrock } 5635363Seschrock 5645363Seschrock slash = strrchr(strval, '/'); 5655363Seschrock 5665363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5675363Seschrock strcmp(slash, "/..") == 0) { 5685363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5695363Seschrock "'%s' is not a valid file"), strval); 5705363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5715363Seschrock goto error; 5725363Seschrock } 5735363Seschrock 5745363Seschrock *slash = '\0'; 5755363Seschrock 5765621Seschrock if (strval[0] != '\0' && 5775621Seschrock (stat64(strval, &statbuf) != 0 || 5785621Seschrock !S_ISDIR(statbuf.st_mode))) { 5795363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5805363Seschrock "'%s' is not a valid directory"), 5815363Seschrock strval); 5825363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5835363Seschrock goto error; 5845363Seschrock } 5855363Seschrock 5865363Seschrock *slash = '/'; 5875363Seschrock break; 5885094Slling } 5895094Slling } 5905094Slling 5915094Slling return (retprops); 5925094Slling error: 5935094Slling nvlist_free(retprops); 5945094Slling return (NULL); 5955094Slling } 5965094Slling 5975094Slling /* 5985094Slling * Set zpool property : propname=propval. 5995094Slling */ 6005094Slling int 6015094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 6025094Slling { 6035094Slling zfs_cmd_t zc = { 0 }; 6045094Slling int ret = -1; 6055094Slling char errbuf[1024]; 6065094Slling nvlist_t *nvl = NULL; 6075094Slling nvlist_t *realprops; 6085094Slling uint64_t version; 6095094Slling 6105094Slling (void) snprintf(errbuf, sizeof (errbuf), 6115094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 6125094Slling zhp->zpool_name); 6135094Slling 6145094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 6155094Slling return (no_memory(zhp->zpool_hdl)); 6165094Slling 6175094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 6185094Slling nvlist_free(nvl); 6195094Slling return (no_memory(zhp->zpool_hdl)); 6205094Slling } 6215094Slling 6225094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 6237184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 6245094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 6255094Slling nvlist_free(nvl); 6265094Slling return (-1); 6275094Slling } 6285094Slling 6295094Slling nvlist_free(nvl); 6305094Slling nvl = realprops; 6315094Slling 6325094Slling /* 6335094Slling * Execute the corresponding ioctl() to set this property. 6345094Slling */ 6355094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 6365094Slling 6375094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 6385094Slling nvlist_free(nvl); 6395094Slling return (-1); 6405094Slling } 6415094Slling 6425094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 6435094Slling 6445094Slling zcmd_free_nvlists(&zc); 6455094Slling nvlist_free(nvl); 6465094Slling 6475094Slling if (ret) 6485094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6495094Slling else 6505094Slling (void) zpool_props_refresh(zhp); 6515094Slling 6525094Slling return (ret); 6535094Slling } 6545094Slling 6555094Slling int 6565094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6575094Slling { 6585094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6595094Slling zprop_list_t *entry; 6605094Slling char buf[ZFS_MAXPROPLEN]; 6615094Slling 6625094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6635094Slling return (-1); 6645094Slling 6655094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6665094Slling 6675094Slling if (entry->pl_fixed) 6685094Slling continue; 6695094Slling 6705094Slling if (entry->pl_prop != ZPROP_INVAL && 6715094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6725094Slling NULL) == 0) { 6735094Slling if (strlen(buf) > entry->pl_width) 6745094Slling entry->pl_width = strlen(buf); 6755094Slling } 6765094Slling } 6775094Slling 6785094Slling return (0); 6795094Slling } 6805094Slling 6815094Slling 682789Sahrens /* 6839816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6849816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6859816SGeorge.Wilson@Sun.COM */ 6869816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6879816SGeorge.Wilson@Sun.COM 6889816SGeorge.Wilson@Sun.COM /* 689789Sahrens * Validate the given pool name, optionally putting an extended error message in 690789Sahrens * 'buf'. 691789Sahrens */ 6926423Sgw25295 boolean_t 6932082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 694789Sahrens { 695789Sahrens namecheck_err_t why; 696789Sahrens char what; 6971773Seschrock int ret; 698789Sahrens 6991773Seschrock ret = pool_namecheck(pool, &why, &what); 7001773Seschrock 7011773Seschrock /* 7021773Seschrock * The rules for reserved pool names were extended at a later point. 7031773Seschrock * But we need to support users with existing pools that may now be 7041773Seschrock * invalid. So we only check for this expanded set of names during a 7051773Seschrock * create (or import), and only in userland. 7061773Seschrock */ 7071773Seschrock if (ret == 0 && !isopen && 7081773Seschrock (strncmp(pool, "mirror", 6) == 0 || 7091773Seschrock strncmp(pool, "raidz", 5) == 0 || 7104527Sperrin strncmp(pool, "spare", 5) == 0 || 7114527Sperrin strcmp(pool, "log") == 0)) { 7126423Sgw25295 if (hdl != NULL) 7136423Sgw25295 zfs_error_aux(hdl, 7146423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 7152082Seschrock return (B_FALSE); 7161773Seschrock } 7171773Seschrock 7181773Seschrock 7191773Seschrock if (ret != 0) { 7202082Seschrock if (hdl != NULL) { 721789Sahrens switch (why) { 7221003Slling case NAME_ERR_TOOLONG: 7232082Seschrock zfs_error_aux(hdl, 7241003Slling dgettext(TEXT_DOMAIN, "name is too long")); 7251003Slling break; 7261003Slling 727789Sahrens case NAME_ERR_INVALCHAR: 7282082Seschrock zfs_error_aux(hdl, 729789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 730789Sahrens "'%c' in pool name"), what); 731789Sahrens break; 732789Sahrens 733789Sahrens case NAME_ERR_NOLETTER: 7342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7352082Seschrock "name must begin with a letter")); 736789Sahrens break; 737789Sahrens 738789Sahrens case NAME_ERR_RESERVED: 7392082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7402082Seschrock "name is reserved")); 741789Sahrens break; 742789Sahrens 743789Sahrens case NAME_ERR_DISKLIKE: 7442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7452082Seschrock "pool name is reserved")); 746789Sahrens break; 7472856Snd150628 7482856Snd150628 case NAME_ERR_LEADING_SLASH: 7492856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7502856Snd150628 "leading slash in name")); 7512856Snd150628 break; 7522856Snd150628 7532856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7542856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7552856Snd150628 "empty component in name")); 7562856Snd150628 break; 7572856Snd150628 7582856Snd150628 case NAME_ERR_TRAILING_SLASH: 7592856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7602856Snd150628 "trailing slash in name")); 7612856Snd150628 break; 7622856Snd150628 7632856Snd150628 case NAME_ERR_MULTIPLE_AT: 7642856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7652856Snd150628 "multiple '@' delimiters in name")); 7662856Snd150628 break; 7672856Snd150628 768789Sahrens } 769789Sahrens } 7702082Seschrock return (B_FALSE); 771789Sahrens } 772789Sahrens 7732082Seschrock return (B_TRUE); 774789Sahrens } 775789Sahrens 776789Sahrens /* 777789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 778789Sahrens * state. 779789Sahrens */ 780789Sahrens zpool_handle_t * 7812082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 782789Sahrens { 783789Sahrens zpool_handle_t *zhp; 7842142Seschrock boolean_t missing; 785789Sahrens 786789Sahrens /* 787789Sahrens * Make sure the pool name is valid. 788789Sahrens */ 7892082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7903237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7912082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7922082Seschrock pool); 793789Sahrens return (NULL); 794789Sahrens } 795789Sahrens 7962082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7972082Seschrock return (NULL); 798789Sahrens 7992082Seschrock zhp->zpool_hdl = hdl; 800789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 801789Sahrens 8022142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 8032142Seschrock zpool_close(zhp); 8042142Seschrock return (NULL); 8052142Seschrock } 8062142Seschrock 8072142Seschrock if (missing) { 8085094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 8093237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 8105094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 8112142Seschrock zpool_close(zhp); 8122142Seschrock return (NULL); 813789Sahrens } 814789Sahrens 815789Sahrens return (zhp); 816789Sahrens } 817789Sahrens 818789Sahrens /* 819789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 820789Sahrens * the configuration cache may be out of date). 821789Sahrens */ 8222142Seschrock int 8232142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 824789Sahrens { 825789Sahrens zpool_handle_t *zhp; 8262142Seschrock boolean_t missing; 827789Sahrens 8282142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 8292142Seschrock return (-1); 830789Sahrens 8312082Seschrock zhp->zpool_hdl = hdl; 832789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 833789Sahrens 8342142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 8352142Seschrock zpool_close(zhp); 8362142Seschrock return (-1); 837789Sahrens } 838789Sahrens 8392142Seschrock if (missing) { 8402142Seschrock zpool_close(zhp); 8412142Seschrock *ret = NULL; 8422142Seschrock return (0); 8432142Seschrock } 8442142Seschrock 8452142Seschrock *ret = zhp; 8462142Seschrock return (0); 847789Sahrens } 848789Sahrens 849789Sahrens /* 850789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 851789Sahrens * state. 852789Sahrens */ 853789Sahrens zpool_handle_t * 8542082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 855789Sahrens { 856789Sahrens zpool_handle_t *zhp; 857789Sahrens 8582082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 859789Sahrens return (NULL); 860789Sahrens 861789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8623237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8632082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 864789Sahrens zpool_close(zhp); 865789Sahrens return (NULL); 866789Sahrens } 867789Sahrens 868789Sahrens return (zhp); 869789Sahrens } 870789Sahrens 871789Sahrens /* 872789Sahrens * Close the handle. Simply frees the memory associated with the handle. 873789Sahrens */ 874789Sahrens void 875789Sahrens zpool_close(zpool_handle_t *zhp) 876789Sahrens { 877789Sahrens if (zhp->zpool_config) 878789Sahrens nvlist_free(zhp->zpool_config); 879952Seschrock if (zhp->zpool_old_config) 880952Seschrock nvlist_free(zhp->zpool_old_config); 8813912Slling if (zhp->zpool_props) 8823912Slling nvlist_free(zhp->zpool_props); 883789Sahrens free(zhp); 884789Sahrens } 885789Sahrens 886789Sahrens /* 887789Sahrens * Return the name of the pool. 888789Sahrens */ 889789Sahrens const char * 890789Sahrens zpool_get_name(zpool_handle_t *zhp) 891789Sahrens { 892789Sahrens return (zhp->zpool_name); 893789Sahrens } 894789Sahrens 895789Sahrens 896789Sahrens /* 897789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 898789Sahrens */ 899789Sahrens int 900789Sahrens zpool_get_state(zpool_handle_t *zhp) 901789Sahrens { 902789Sahrens return (zhp->zpool_state); 903789Sahrens } 904789Sahrens 905789Sahrens /* 906789Sahrens * Create the named pool, using the provided vdev list. It is assumed 907789Sahrens * that the consumer has already validated the contents of the nvlist, so we 908789Sahrens * don't have to worry about error semantics. 909789Sahrens */ 910789Sahrens int 9112082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 9127184Stimh nvlist_t *props, nvlist_t *fsprops) 913789Sahrens { 914789Sahrens zfs_cmd_t zc = { 0 }; 9157184Stimh nvlist_t *zc_fsprops = NULL; 9167184Stimh nvlist_t *zc_props = NULL; 9172082Seschrock char msg[1024]; 9185094Slling char *altroot; 9197184Stimh int ret = -1; 9202082Seschrock 9212082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 9222082Seschrock "cannot create '%s'"), pool); 923789Sahrens 9242082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 9252082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 9262082Seschrock 9275320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 9285320Slling return (-1); 9295320Slling 9307184Stimh if (props) { 9317184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 9327184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 9337184Stimh goto create_failed; 9347184Stimh } 9355320Slling } 936789Sahrens 9377184Stimh if (fsprops) { 9387184Stimh uint64_t zoned; 9397184Stimh char *zonestr; 9407184Stimh 9417184Stimh zoned = ((nvlist_lookup_string(fsprops, 9427184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 9437184Stimh strcmp(zonestr, "on") == 0); 9447184Stimh 9457184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9467184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9477184Stimh goto create_failed; 9487184Stimh } 9497184Stimh if (!zc_props && 9507184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9517184Stimh goto create_failed; 9527184Stimh } 9537184Stimh if (nvlist_add_nvlist(zc_props, 9547184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9557184Stimh goto create_failed; 9567184Stimh } 9577184Stimh } 9587184Stimh 9597184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9607184Stimh goto create_failed; 9617184Stimh 962789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 963789Sahrens 9647184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9655320Slling 9662676Seschrock zcmd_free_nvlists(&zc); 9677184Stimh nvlist_free(zc_props); 9687184Stimh nvlist_free(zc_fsprops); 9692082Seschrock 970789Sahrens switch (errno) { 971789Sahrens case EBUSY: 972789Sahrens /* 973789Sahrens * This can happen if the user has specified the same 974789Sahrens * device multiple times. We can't reliably detect this 975789Sahrens * until we try to add it and see we already have a 976789Sahrens * label. 977789Sahrens */ 9782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9792082Seschrock "one or more vdevs refer to the same device")); 9802082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 981789Sahrens 982789Sahrens case EOVERFLOW: 983789Sahrens /* 9842082Seschrock * This occurs when one of the devices is below 985789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 986789Sahrens * device was the problem device since there's no 987789Sahrens * reliable way to determine device size from userland. 988789Sahrens */ 989789Sahrens { 990789Sahrens char buf[64]; 991789Sahrens 992789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 993789Sahrens 9942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9952082Seschrock "one or more devices is less than the " 9962082Seschrock "minimum size (%s)"), buf); 997789Sahrens } 9982082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 999789Sahrens 1000789Sahrens case ENOSPC: 10012082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10022082Seschrock "one or more devices is out of space")); 10032082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1004789Sahrens 10055450Sbrendan case ENOTBLK: 10065450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10075450Sbrendan "cache device must be a disk or disk slice")); 10085450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 10095450Sbrendan 1010789Sahrens default: 10112082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1012789Sahrens } 1013789Sahrens } 1014789Sahrens 1015789Sahrens /* 1016789Sahrens * If this is an alternate root pool, then we automatically set the 10172676Seschrock * mountpoint of the root dataset to be '/'. 1018789Sahrens */ 10195094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 10205094Slling &altroot) == 0) { 1021789Sahrens zfs_handle_t *zhp; 1022789Sahrens 10235094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 10242676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 10252676Seschrock "/") == 0); 1026789Sahrens 1027789Sahrens zfs_close(zhp); 1028789Sahrens } 1029789Sahrens 10307184Stimh create_failed: 10315320Slling zcmd_free_nvlists(&zc); 10327184Stimh nvlist_free(zc_props); 10337184Stimh nvlist_free(zc_fsprops); 10347184Stimh return (ret); 1035789Sahrens } 1036789Sahrens 1037789Sahrens /* 1038789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1039789Sahrens * datasets left in the pool. 1040789Sahrens */ 1041789Sahrens int 1042789Sahrens zpool_destroy(zpool_handle_t *zhp) 1043789Sahrens { 1044789Sahrens zfs_cmd_t zc = { 0 }; 1045789Sahrens zfs_handle_t *zfp = NULL; 10462082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10472082Seschrock char msg[1024]; 1048789Sahrens 1049789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 10502082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 10512082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1052789Sahrens return (-1); 1053789Sahrens 1054789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1055789Sahrens 10564543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10572082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10582082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1059789Sahrens 10602082Seschrock if (errno == EROFS) { 10612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10622082Seschrock "one or more devices is read only")); 10632082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10642082Seschrock } else { 10652082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1066789Sahrens } 1067789Sahrens 1068789Sahrens if (zfp) 1069789Sahrens zfs_close(zfp); 1070789Sahrens return (-1); 1071789Sahrens } 1072789Sahrens 1073789Sahrens if (zfp) { 1074789Sahrens remove_mountpoint(zfp); 1075789Sahrens zfs_close(zfp); 1076789Sahrens } 1077789Sahrens 1078789Sahrens return (0); 1079789Sahrens } 1080789Sahrens 1081789Sahrens /* 1082789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1083789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1084789Sahrens */ 1085789Sahrens int 1086789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1087789Sahrens { 10882676Seschrock zfs_cmd_t zc = { 0 }; 10892082Seschrock int ret; 10902082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10912082Seschrock char msg[1024]; 10925450Sbrendan nvlist_t **spares, **l2cache; 10935450Sbrendan uint_t nspares, nl2cache; 10942082Seschrock 10952082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10962082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10972082Seschrock 10985450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10995450Sbrendan SPA_VERSION_SPARES && 11002082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 11012082Seschrock &spares, &nspares) == 0) { 11022082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 11032082Seschrock "upgraded to add hot spares")); 11042082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 11052082Seschrock } 1106789Sahrens 11077965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 11087965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 11097965SGeorge.Wilson@Sun.COM uint64_t s; 11107965SGeorge.Wilson@Sun.COM 11117965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 11127965SGeorge.Wilson@Sun.COM char *path; 11137965SGeorge.Wilson@Sun.COM 11147965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 11157965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 11167965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11177965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 11187965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 111910594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 112010594SGeorge.Wilson@Sun.COM B_FALSE)); 11217965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 11227965SGeorge.Wilson@Sun.COM } 11237965SGeorge.Wilson@Sun.COM } 11247965SGeorge.Wilson@Sun.COM } 11257965SGeorge.Wilson@Sun.COM 11265450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 11275450Sbrendan SPA_VERSION_L2CACHE && 11285450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 11295450Sbrendan &l2cache, &nl2cache) == 0) { 11305450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 11315450Sbrendan "upgraded to add cache devices")); 11325450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 11335450Sbrendan } 11345450Sbrendan 11355094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 11362082Seschrock return (-1); 1137789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1138789Sahrens 11394543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1140789Sahrens switch (errno) { 1141789Sahrens case EBUSY: 1142789Sahrens /* 1143789Sahrens * This can happen if the user has specified the same 1144789Sahrens * device multiple times. We can't reliably detect this 1145789Sahrens * until we try to add it and see we already have a 1146789Sahrens * label. 1147789Sahrens */ 11482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11492082Seschrock "one or more vdevs refer to the same device")); 11502082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1151789Sahrens break; 1152789Sahrens 1153789Sahrens case EOVERFLOW: 1154789Sahrens /* 1155789Sahrens * This occurrs when one of the devices is below 1156789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1157789Sahrens * device was the problem device since there's no 1158789Sahrens * reliable way to determine device size from userland. 1159789Sahrens */ 1160789Sahrens { 1161789Sahrens char buf[64]; 1162789Sahrens 1163789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1164789Sahrens 11652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11662082Seschrock "device is less than the minimum " 11672082Seschrock "size (%s)"), buf); 1168789Sahrens } 11692082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11702082Seschrock break; 11712082Seschrock 11722082Seschrock case ENOTSUP: 11732082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11744527Sperrin "pool must be upgraded to add these vdevs")); 11752082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1176789Sahrens break; 1177789Sahrens 11783912Slling case EDOM: 11793912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11804527Sperrin "root pool can not have multiple vdevs" 11814527Sperrin " or separate logs")); 11823912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11833912Slling break; 11843912Slling 11855450Sbrendan case ENOTBLK: 11865450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11875450Sbrendan "cache device must be a disk or disk slice")); 11885450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11895450Sbrendan break; 11905450Sbrendan 1191789Sahrens default: 11922082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1193789Sahrens } 1194789Sahrens 11952082Seschrock ret = -1; 11962082Seschrock } else { 11972082Seschrock ret = 0; 1198789Sahrens } 1199789Sahrens 12002676Seschrock zcmd_free_nvlists(&zc); 1201789Sahrens 12022082Seschrock return (ret); 1203789Sahrens } 1204789Sahrens 1205789Sahrens /* 1206789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1207789Sahrens * mounted datasets in the pool. 1208789Sahrens */ 1209789Sahrens int 12108211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1211789Sahrens { 1212789Sahrens zfs_cmd_t zc = { 0 }; 12137214Slling char msg[1024]; 1214789Sahrens 12157214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 12167214Slling "cannot export '%s'"), zhp->zpool_name); 12177214Slling 1218789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 12197214Slling zc.zc_cookie = force; 12208211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 12217214Slling 12227214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 12237214Slling switch (errno) { 12247214Slling case EXDEV: 12257214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 12267214Slling "use '-f' to override the following errors:\n" 12277214Slling "'%s' has an active shared spare which could be" 12287214Slling " used by other pools once '%s' is exported."), 12297214Slling zhp->zpool_name, zhp->zpool_name); 12307214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 12317214Slling msg)); 12327214Slling default: 12337214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 12347214Slling msg)); 12357214Slling } 12367214Slling } 12377214Slling 1238789Sahrens return (0); 1239789Sahrens } 1240789Sahrens 12418211SGeorge.Wilson@Sun.COM int 12428211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 12438211SGeorge.Wilson@Sun.COM { 12448211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12458211SGeorge.Wilson@Sun.COM } 12468211SGeorge.Wilson@Sun.COM 12478211SGeorge.Wilson@Sun.COM int 12488211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12498211SGeorge.Wilson@Sun.COM { 12508211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12518211SGeorge.Wilson@Sun.COM } 12528211SGeorge.Wilson@Sun.COM 125310921STim.Haley@Sun.COM static void 125410921STim.Haley@Sun.COM zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 125510921STim.Haley@Sun.COM nvlist_t *rbi) 125610921STim.Haley@Sun.COM { 125710921STim.Haley@Sun.COM uint64_t rewindto; 125810921STim.Haley@Sun.COM int64_t loss = -1; 125910921STim.Haley@Sun.COM struct tm t; 126010921STim.Haley@Sun.COM char timestr[128]; 126110921STim.Haley@Sun.COM 126210921STim.Haley@Sun.COM if (!hdl->libzfs_printerr || rbi == NULL) 126310921STim.Haley@Sun.COM return; 126410921STim.Haley@Sun.COM 126510921STim.Haley@Sun.COM if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 126610921STim.Haley@Sun.COM return; 126710921STim.Haley@Sun.COM (void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss); 126810921STim.Haley@Sun.COM 126910921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 127010921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 127110921STim.Haley@Sun.COM if (dryrun) { 127210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 127310921STim.Haley@Sun.COM "Would be able to return %s " 127410921STim.Haley@Sun.COM "to its state as of %s.\n"), 127510921STim.Haley@Sun.COM name, timestr); 127610921STim.Haley@Sun.COM } else { 127710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 127810921STim.Haley@Sun.COM "Pool %s returned to its state as of %s.\n"), 127910921STim.Haley@Sun.COM name, timestr); 128010921STim.Haley@Sun.COM } 128110921STim.Haley@Sun.COM if (loss > 120) { 128210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 128310921STim.Haley@Sun.COM "%s approximately %lld "), 128410921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", 128510921STim.Haley@Sun.COM (loss + 30) / 60); 128610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 128710921STim.Haley@Sun.COM "minutes of transactions.\n")); 128810921STim.Haley@Sun.COM } else if (loss > 0) { 128910921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 129010921STim.Haley@Sun.COM "%s approximately %lld "), 129110921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", loss); 129210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 129310921STim.Haley@Sun.COM "seconds of transactions.\n")); 129410921STim.Haley@Sun.COM } 129510921STim.Haley@Sun.COM } 129610921STim.Haley@Sun.COM } 129710921STim.Haley@Sun.COM 129810921STim.Haley@Sun.COM void 129910921STim.Haley@Sun.COM zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 130010921STim.Haley@Sun.COM nvlist_t *config) 130110921STim.Haley@Sun.COM { 130210921STim.Haley@Sun.COM int64_t loss = -1; 130310921STim.Haley@Sun.COM uint64_t edata = UINT64_MAX; 130410921STim.Haley@Sun.COM uint64_t rewindto; 130510921STim.Haley@Sun.COM struct tm t; 130610921STim.Haley@Sun.COM char timestr[128]; 130710921STim.Haley@Sun.COM 130810921STim.Haley@Sun.COM if (!hdl->libzfs_printerr) 130910921STim.Haley@Sun.COM return; 131010921STim.Haley@Sun.COM 131110921STim.Haley@Sun.COM if (reason >= 0) 131210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 131310921STim.Haley@Sun.COM else 131410921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "\t")); 131510921STim.Haley@Sun.COM 131610921STim.Haley@Sun.COM /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 131710921STim.Haley@Sun.COM if (nvlist_lookup_uint64(config, 131810921STim.Haley@Sun.COM ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 131910921STim.Haley@Sun.COM goto no_info; 132010921STim.Haley@Sun.COM 132110921STim.Haley@Sun.COM (void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss); 132210921STim.Haley@Sun.COM (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 132310921STim.Haley@Sun.COM &edata); 132410921STim.Haley@Sun.COM 132510921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 132610921STim.Haley@Sun.COM "Recovery is possible, but will result in some data loss.\n")); 132710921STim.Haley@Sun.COM 132810921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 132910921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 133010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 133110921STim.Haley@Sun.COM "\tReturning the pool to its state as of %s\n" 133210921STim.Haley@Sun.COM "\tshould correct the problem. "), 133310921STim.Haley@Sun.COM timestr); 133410921STim.Haley@Sun.COM } else { 133510921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 133610921STim.Haley@Sun.COM "\tReverting the pool to an earlier state " 133710921STim.Haley@Sun.COM "should correct the problem.\n\t")); 133810921STim.Haley@Sun.COM } 133910921STim.Haley@Sun.COM 134010921STim.Haley@Sun.COM if (loss > 120) { 134110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 134210921STim.Haley@Sun.COM "Approximately %lld minutes of data\n" 134310921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 134410921STim.Haley@Sun.COM } else if (loss > 0) { 134510921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 134610921STim.Haley@Sun.COM "Approximately %lld seconds of data\n" 134710921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), loss); 134810921STim.Haley@Sun.COM } 134910921STim.Haley@Sun.COM if (edata != 0 && edata != UINT64_MAX) { 135010921STim.Haley@Sun.COM if (edata == 1) { 135110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 135210921STim.Haley@Sun.COM "After rewind, at least\n" 135310921STim.Haley@Sun.COM "\tone persistent user-data error will remain. ")); 135410921STim.Haley@Sun.COM } else { 135510921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 135610921STim.Haley@Sun.COM "After rewind, several\n" 135710921STim.Haley@Sun.COM "\tpersistent user-data errors will remain. ")); 135810921STim.Haley@Sun.COM } 135910921STim.Haley@Sun.COM } 136010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 136111026STim.Haley@Sun.COM "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "), 136211026STim.Haley@Sun.COM reason >= 0 ? "clear" : "import", name); 136310921STim.Haley@Sun.COM 136410921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 136510921STim.Haley@Sun.COM "A scrub of the pool\n" 136610921STim.Haley@Sun.COM "\tis strongly recommended after recovery.\n")); 136710921STim.Haley@Sun.COM return; 136810921STim.Haley@Sun.COM 136910921STim.Haley@Sun.COM no_info: 137010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 137110921STim.Haley@Sun.COM "Destroy and re-create the pool from\n\ta backup source.\n")); 137210921STim.Haley@Sun.COM } 137310921STim.Haley@Sun.COM 1374789Sahrens /* 13755094Slling * zpool_import() is a contracted interface. Should be kept the same 13765094Slling * if possible. 13775094Slling * 13785094Slling * Applications should use zpool_import_props() to import a pool with 13795094Slling * new properties value to be set. 1380789Sahrens */ 1381789Sahrens int 13822082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 13835094Slling char *altroot) 13845094Slling { 13855094Slling nvlist_t *props = NULL; 13865094Slling int ret; 13875094Slling 13885094Slling if (altroot != NULL) { 13895094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 13905094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13915094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13925094Slling newname)); 13935094Slling } 13945094Slling 13955094Slling if (nvlist_add_string(props, 13968084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 13978084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 13988084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 13995094Slling nvlist_free(props); 14005094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 14015094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 14025094Slling newname)); 14035094Slling } 14045094Slling } 14055094Slling 14066643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 14075094Slling if (props) 14085094Slling nvlist_free(props); 14095094Slling return (ret); 14105094Slling } 14115094Slling 14125094Slling /* 14135094Slling * Import the given pool using the known configuration and a list of 14145094Slling * properties to be set. The configuration should have come from 14155094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 14165094Slling * is imported with a different name. 14175094Slling */ 14185094Slling int 14195094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 14206643Seschrock nvlist_t *props, boolean_t importfaulted) 1421789Sahrens { 14222676Seschrock zfs_cmd_t zc = { 0 }; 142310921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 142410921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 1425789Sahrens char *thename; 1426789Sahrens char *origname; 142710921STim.Haley@Sun.COM uint64_t returned_size; 1428789Sahrens int ret; 14295094Slling char errbuf[1024]; 1430789Sahrens 1431789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1432789Sahrens &origname) == 0); 1433789Sahrens 14345094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 14355094Slling "cannot import pool '%s'"), origname); 14365094Slling 1437789Sahrens if (newname != NULL) { 14382082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 14393237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 14402082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 14412082Seschrock newname)); 1442789Sahrens thename = (char *)newname; 1443789Sahrens } else { 1444789Sahrens thename = origname; 1445789Sahrens } 1446789Sahrens 14475094Slling if (props) { 14485094Slling uint64_t version; 14495094Slling 14505094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 14515094Slling &version) == 0); 14525094Slling 14537184Stimh if ((props = zpool_valid_proplist(hdl, origname, 14545320Slling props, version, B_TRUE, errbuf)) == NULL) { 14555094Slling return (-1); 14565320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 14575320Slling nvlist_free(props); 14585094Slling return (-1); 14595320Slling } 14605094Slling } 1461789Sahrens 1462789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1463789Sahrens 1464789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 14651544Seschrock &zc.zc_guid) == 0); 1466789Sahrens 14675320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 14685320Slling nvlist_free(props); 14692082Seschrock return (-1); 14705320Slling } 147110921STim.Haley@Sun.COM returned_size = zc.zc_nvlist_conf_size + 512; 147210921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) { 147310921STim.Haley@Sun.COM nvlist_free(props); 147410921STim.Haley@Sun.COM return (-1); 147510921STim.Haley@Sun.COM } 1476789Sahrens 14776643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1478789Sahrens ret = 0; 14794543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1480789Sahrens char desc[1024]; 148110921STim.Haley@Sun.COM 148210921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 148310921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 148410921STim.Haley@Sun.COM /* 148510921STim.Haley@Sun.COM * Dry-run failed, but we print out what success 148610921STim.Haley@Sun.COM * looks like if we found a best txg 148710921STim.Haley@Sun.COM */ 148810921STim.Haley@Sun.COM if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) { 148910921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 149010921STim.Haley@Sun.COM B_TRUE, nvi); 149110921STim.Haley@Sun.COM nvlist_free(nvi); 149210921STim.Haley@Sun.COM return (-1); 149310921STim.Haley@Sun.COM } 149410921STim.Haley@Sun.COM 1495789Sahrens if (newname == NULL) 1496789Sahrens (void) snprintf(desc, sizeof (desc), 1497789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1498789Sahrens thename); 1499789Sahrens else 1500789Sahrens (void) snprintf(desc, sizeof (desc), 1501789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1502789Sahrens origname, thename); 1503789Sahrens 1504789Sahrens switch (errno) { 15051544Seschrock case ENOTSUP: 15061544Seschrock /* 15071544Seschrock * Unsupported version. 15081544Seschrock */ 15092082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 15101544Seschrock break; 15111544Seschrock 15122174Seschrock case EINVAL: 15132174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 15142174Seschrock break; 15152174Seschrock 1516789Sahrens default: 151710921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 15182082Seschrock (void) zpool_standard_error(hdl, errno, desc); 151910921STim.Haley@Sun.COM zpool_explain_recover(hdl, 152010921STim.Haley@Sun.COM newname ? origname : thename, -errno, nvi); 152110921STim.Haley@Sun.COM nvlist_free(nvi); 152210921STim.Haley@Sun.COM break; 1523789Sahrens } 1524789Sahrens 1525789Sahrens ret = -1; 1526789Sahrens } else { 1527789Sahrens zpool_handle_t *zhp; 15284543Smarks 1529789Sahrens /* 1530789Sahrens * This should never fail, but play it safe anyway. 1531789Sahrens */ 153210588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 15332142Seschrock ret = -1; 153410588SEric.Taylor@Sun.COM else if (zhp != NULL) 1535789Sahrens zpool_close(zhp); 153610921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 153710921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 153810921STim.Haley@Sun.COM if (policy.zrp_request & 153910921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 154010921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 154110921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 154210921STim.Haley@Sun.COM nvi); 154310921STim.Haley@Sun.COM } 154410921STim.Haley@Sun.COM nvlist_free(nvi); 154510921STim.Haley@Sun.COM return (0); 1546789Sahrens } 1547789Sahrens 15482676Seschrock zcmd_free_nvlists(&zc); 15495320Slling nvlist_free(props); 15505320Slling 1551789Sahrens return (ret); 1552789Sahrens } 1553789Sahrens 1554789Sahrens /* 1555789Sahrens * Scrub the pool. 1556789Sahrens */ 1557789Sahrens int 1558789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1559789Sahrens { 1560789Sahrens zfs_cmd_t zc = { 0 }; 1561789Sahrens char msg[1024]; 15622082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1563789Sahrens 1564789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1565789Sahrens zc.zc_cookie = type; 1566789Sahrens 15674543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1568789Sahrens return (0); 1569789Sahrens 1570789Sahrens (void) snprintf(msg, sizeof (msg), 1571789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1572789Sahrens 15732082Seschrock if (errno == EBUSY) 15742082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 15752082Seschrock else 15762082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1577789Sahrens } 1578789Sahrens 15792468Sek110237 /* 15809816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 15819816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 15822468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 15832468Sek110237 * spare; but FALSE if its an INUSE spare. 15842468Sek110237 */ 15852082Seschrock static nvlist_t * 15869816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 15879816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 15881544Seschrock { 15891544Seschrock uint_t c, children; 15901544Seschrock nvlist_t **child; 15912082Seschrock nvlist_t *ret; 15927326SEric.Schrock@Sun.COM uint64_t is_log; 15939816SGeorge.Wilson@Sun.COM char *srchkey; 15949816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 15959816SGeorge.Wilson@Sun.COM 15969816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 15979816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 15989816SGeorge.Wilson@Sun.COM return (NULL); 15999816SGeorge.Wilson@Sun.COM 16009816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 16019816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 16029816SGeorge.Wilson@Sun.COM 16039816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 16049816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 16059816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 16069816SGeorge.Wilson@Sun.COM 16079816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 16089816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 16099816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 16109816SGeorge.Wilson@Sun.COM &present) == 0) { 16119816SGeorge.Wilson@Sun.COM /* 16129816SGeorge.Wilson@Sun.COM * If the device has never been present since 16139816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 16149816SGeorge.Wilson@Sun.COM * vdev is by GUID. 16159816SGeorge.Wilson@Sun.COM */ 16169816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 16179816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 16189816SGeorge.Wilson@Sun.COM if (theguid == srchval) 16199816SGeorge.Wilson@Sun.COM return (nv); 16209816SGeorge.Wilson@Sun.COM } 16219816SGeorge.Wilson@Sun.COM } 16229816SGeorge.Wilson@Sun.COM break; 16239816SGeorge.Wilson@Sun.COM } 16249816SGeorge.Wilson@Sun.COM 16259816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 16269816SGeorge.Wilson@Sun.COM char *srchval, *val; 16279816SGeorge.Wilson@Sun.COM 16289816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 16299816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 16309816SGeorge.Wilson@Sun.COM break; 16319816SGeorge.Wilson@Sun.COM 16321544Seschrock /* 16339816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 163410594SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk and when 163510594SGeorge.Wilson@Sun.COM * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 163610594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 16371544Seschrock */ 16389816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 16399816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 16409816SGeorge.Wilson@Sun.COM 16419816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 16429816SGeorge.Wilson@Sun.COM &wholedisk); 16439816SGeorge.Wilson@Sun.COM if (wholedisk) { 16449816SGeorge.Wilson@Sun.COM /* 16459816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 16469816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 16479816SGeorge.Wilson@Sun.COM */ 16489816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 16499816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 16509816SGeorge.Wilson@Sun.COM return (nv); 16519816SGeorge.Wilson@Sun.COM break; 16529816SGeorge.Wilson@Sun.COM } 165310594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 165410594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 165510594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 165610594SGeorge.Wilson@Sun.COM 165710594SGeorge.Wilson@Sun.COM /* 165810594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 165910594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 166010594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 166110594SGeorge.Wilson@Sun.COM */ 166210594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 166310594SGeorge.Wilson@Sun.COM return (NULL); 166410594SGeorge.Wilson@Sun.COM 166510594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 166610594SGeorge.Wilson@Sun.COM free(type); 166710594SGeorge.Wilson@Sun.COM break; 166810594SGeorge.Wilson@Sun.COM } 166910594SGeorge.Wilson@Sun.COM idx = p + 1; 167010594SGeorge.Wilson@Sun.COM *p = '\0'; 167110594SGeorge.Wilson@Sun.COM 167210594SGeorge.Wilson@Sun.COM /* 167310594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 167410594SGeorge.Wilson@Sun.COM */ 167510594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 167610594SGeorge.Wilson@Sun.COM free(type); 167710594SGeorge.Wilson@Sun.COM break; 167810594SGeorge.Wilson@Sun.COM } 167910594SGeorge.Wilson@Sun.COM 168010594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 168110594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 168210594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 168310594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 168410594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 168510594SGeorge.Wilson@Sun.COM &id) == 0); 168610594SGeorge.Wilson@Sun.COM 168710594SGeorge.Wilson@Sun.COM errno = 0; 168810594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 168910594SGeorge.Wilson@Sun.COM 169010594SGeorge.Wilson@Sun.COM free(type); 169110594SGeorge.Wilson@Sun.COM if (errno != 0) 169210594SGeorge.Wilson@Sun.COM return (NULL); 169310594SGeorge.Wilson@Sun.COM 169410594SGeorge.Wilson@Sun.COM /* 169510594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 169610594SGeorge.Wilson@Sun.COM */ 169710594SGeorge.Wilson@Sun.COM if (vdev_id == id) 169810594SGeorge.Wilson@Sun.COM return (nv); 16999816SGeorge.Wilson@Sun.COM } 17009816SGeorge.Wilson@Sun.COM 17019816SGeorge.Wilson@Sun.COM /* 17029816SGeorge.Wilson@Sun.COM * Common case 17039816SGeorge.Wilson@Sun.COM */ 17049816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 17052082Seschrock return (nv); 17069816SGeorge.Wilson@Sun.COM break; 17079816SGeorge.Wilson@Sun.COM } 17089816SGeorge.Wilson@Sun.COM 17099816SGeorge.Wilson@Sun.COM default: 17109816SGeorge.Wilson@Sun.COM break; 17111544Seschrock } 17121544Seschrock 17131544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 17141544Seschrock &child, &children) != 0) 17152082Seschrock return (NULL); 17161544Seschrock 17177326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 17189816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17197326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17207326SEric.Schrock@Sun.COM /* 17217326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 17227326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 17237326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 17247326SEric.Schrock@Sun.COM * 'log' is non-NULL). 17257326SEric.Schrock@Sun.COM */ 17267326SEric.Schrock@Sun.COM if (log != NULL && 17277326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 17287326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 17297326SEric.Schrock@Sun.COM is_log) { 17307326SEric.Schrock@Sun.COM *log = B_TRUE; 17317326SEric.Schrock@Sun.COM } 17321544Seschrock return (ret); 17337326SEric.Schrock@Sun.COM } 17347326SEric.Schrock@Sun.COM } 17351544Seschrock 17362082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 17372082Seschrock &child, &children) == 0) { 17382082Seschrock for (c = 0; c < children; c++) { 17399816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17407326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17412468Sek110237 *avail_spare = B_TRUE; 17422082Seschrock return (ret); 17432082Seschrock } 17442082Seschrock } 17452082Seschrock } 17462082Seschrock 17475450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 17485450Sbrendan &child, &children) == 0) { 17495450Sbrendan for (c = 0; c < children; c++) { 17509816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17517326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17525450Sbrendan *l2cache = B_TRUE; 17535450Sbrendan return (ret); 17545450Sbrendan } 17555450Sbrendan } 17565450Sbrendan } 17575450Sbrendan 17582082Seschrock return (NULL); 17591544Seschrock } 17601544Seschrock 17619816SGeorge.Wilson@Sun.COM /* 17629816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 17639816SGeorge.Wilson@Sun.COM * associated vdev. 17649816SGeorge.Wilson@Sun.COM */ 17659816SGeorge.Wilson@Sun.COM nvlist_t * 17669816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 17679816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 17689816SGeorge.Wilson@Sun.COM { 17699816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 17709816SGeorge.Wilson@Sun.COM 17719816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 17729816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 17739816SGeorge.Wilson@Sun.COM 17749816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 17759816SGeorge.Wilson@Sun.COM &nvroot) == 0); 17769816SGeorge.Wilson@Sun.COM 17779816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 17789816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 17799816SGeorge.Wilson@Sun.COM nvlist_free(search); 17809816SGeorge.Wilson@Sun.COM 17819816SGeorge.Wilson@Sun.COM return (ret); 17829816SGeorge.Wilson@Sun.COM } 17839816SGeorge.Wilson@Sun.COM 178410594SGeorge.Wilson@Sun.COM /* 178510594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 178610594SGeorge.Wilson@Sun.COM */ 178710594SGeorge.Wilson@Sun.COM boolean_t 178810594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 178910594SGeorge.Wilson@Sun.COM { 179010594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 179110594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 179210594SGeorge.Wilson@Sun.COM return (B_TRUE); 179310594SGeorge.Wilson@Sun.COM return (B_FALSE); 179410594SGeorge.Wilson@Sun.COM } 179510594SGeorge.Wilson@Sun.COM 17962082Seschrock nvlist_t * 17975450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 17987326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 17991544Seschrock { 18001544Seschrock char buf[MAXPATHLEN]; 18011544Seschrock char *end; 18029816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 18031544Seschrock uint64_t guid; 18041544Seschrock 18059816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 18069816SGeorge.Wilson@Sun.COM 18071613Seschrock guid = strtoull(path, &end, 10); 18081544Seschrock if (guid != 0 && *end == '\0') { 18099816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 181010594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 181110594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 18121544Seschrock } else if (path[0] != '/') { 18131544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 18149816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 18151544Seschrock } else { 18169816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 18171544Seschrock } 18181544Seschrock 18191544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18201544Seschrock &nvroot) == 0); 18211544Seschrock 18222468Sek110237 *avail_spare = B_FALSE; 18235450Sbrendan *l2cache = B_FALSE; 18247326SEric.Schrock@Sun.COM if (log != NULL) 18257326SEric.Schrock@Sun.COM *log = B_FALSE; 18269816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 18279816SGeorge.Wilson@Sun.COM nvlist_free(search); 18289816SGeorge.Wilson@Sun.COM 18299816SGeorge.Wilson@Sun.COM return (ret); 18302468Sek110237 } 18312468Sek110237 18327656SSherry.Moore@Sun.COM static int 18337656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 18347656SSherry.Moore@Sun.COM { 18357656SSherry.Moore@Sun.COM uint64_t ival; 18367656SSherry.Moore@Sun.COM 18377656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 18387656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 18397656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 18407656SSherry.Moore@Sun.COM return (0); 18417656SSherry.Moore@Sun.COM 18427656SSherry.Moore@Sun.COM return (1); 18437656SSherry.Moore@Sun.COM } 18447656SSherry.Moore@Sun.COM 18457656SSherry.Moore@Sun.COM /* 18469790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 18477656SSherry.Moore@Sun.COM */ 18489160SSherry.Moore@Sun.COM static int 18499790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 18509160SSherry.Moore@Sun.COM size_t *bytes_written) 18517656SSherry.Moore@Sun.COM { 18529160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 18539160SSherry.Moore@Sun.COM char *tmppath; 18549160SSherry.Moore@Sun.COM const char *format; 18559160SSherry.Moore@Sun.COM 18569160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 18579160SSherry.Moore@Sun.COM &tmppath) != 0) 18589160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 18599160SSherry.Moore@Sun.COM 18609160SSherry.Moore@Sun.COM pos = *bytes_written; 18619160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 18629160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 18639160SSherry.Moore@Sun.COM 18649160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 18659160SSherry.Moore@Sun.COM *bytes_written += rsz; 18669160SSherry.Moore@Sun.COM 18679160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 18689160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 18699160SSherry.Moore@Sun.COM if (bytes_left != 0) { 18709160SSherry.Moore@Sun.COM physpath[pos] = 0; 18719160SSherry.Moore@Sun.COM } 18729160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 18739160SSherry.Moore@Sun.COM } 18749160SSherry.Moore@Sun.COM return (0); 18759160SSherry.Moore@Sun.COM } 18769160SSherry.Moore@Sun.COM 18779790SLin.Ling@Sun.COM static int 18789790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 18799790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 18809790SLin.Ling@Sun.COM { 18819790SLin.Ling@Sun.COM char *type; 18829790SLin.Ling@Sun.COM int ret; 18839790SLin.Ling@Sun.COM 18849790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 18859790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 18869790SLin.Ling@Sun.COM 18879790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 18889790SLin.Ling@Sun.COM /* 18899790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 18909790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 18919790SLin.Ling@Sun.COM * spare device. 18929790SLin.Ling@Sun.COM */ 18939790SLin.Ling@Sun.COM if (is_spare) { 18949790SLin.Ling@Sun.COM uint64_t spare = 0; 18959790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 18969790SLin.Ling@Sun.COM &spare); 18979790SLin.Ling@Sun.COM if (!spare) 18989790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 18999790SLin.Ling@Sun.COM } 19009790SLin.Ling@Sun.COM 19019790SLin.Ling@Sun.COM if (vdev_online(nv)) { 19029790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 19039790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 19049790SLin.Ling@Sun.COM return (ret); 19059790SLin.Ling@Sun.COM } 19069790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 19079790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 19089790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 19099790SLin.Ling@Sun.COM nvlist_t **child; 19109790SLin.Ling@Sun.COM uint_t count; 19119790SLin.Ling@Sun.COM int i, ret; 19129790SLin.Ling@Sun.COM 19139790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 19149790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 19159790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19169790SLin.Ling@Sun.COM 19179790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 19189790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 19199790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 19209790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 19219790SLin.Ling@Sun.COM return (ret); 19229790SLin.Ling@Sun.COM } 19239790SLin.Ling@Sun.COM } 19249790SLin.Ling@Sun.COM 19259790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 19269790SLin.Ling@Sun.COM } 19279790SLin.Ling@Sun.COM 19289160SSherry.Moore@Sun.COM /* 19299160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 19309160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 19319160SSherry.Moore@Sun.COM */ 19329160SSherry.Moore@Sun.COM static int 19339160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 19349160SSherry.Moore@Sun.COM { 19359160SSherry.Moore@Sun.COM size_t rsz; 19367656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 19377656SSherry.Moore@Sun.COM nvlist_t **child; 19387656SSherry.Moore@Sun.COM uint_t count; 19399160SSherry.Moore@Sun.COM char *type; 19409160SSherry.Moore@Sun.COM 19419160SSherry.Moore@Sun.COM rsz = 0; 19429160SSherry.Moore@Sun.COM 19439160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 19449160SSherry.Moore@Sun.COM &vdev_root) != 0) 19459160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19469160SSherry.Moore@Sun.COM 19479160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 19489160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 19499160SSherry.Moore@Sun.COM &child, &count) != 0) 19509160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19517656SSherry.Moore@Sun.COM 19527656SSherry.Moore@Sun.COM /* 19539160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 19549160SSherry.Moore@Sun.COM * a single top-level vdev. 19557656SSherry.Moore@Sun.COM */ 19569160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 19579160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 19589160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 19599160SSherry.Moore@Sun.COM 19609790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 19619790SLin.Ling@Sun.COM B_FALSE); 19627656SSherry.Moore@Sun.COM 19639160SSherry.Moore@Sun.COM /* No online devices */ 19649160SSherry.Moore@Sun.COM if (rsz == 0) 19659160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 19669160SSherry.Moore@Sun.COM 19677656SSherry.Moore@Sun.COM return (0); 19687656SSherry.Moore@Sun.COM } 19697656SSherry.Moore@Sun.COM 19702468Sek110237 /* 19719160SSherry.Moore@Sun.COM * Get phys_path for a root pool 19729160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 19739160SSherry.Moore@Sun.COM */ 19749160SSherry.Moore@Sun.COM int 19759160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 19769160SSherry.Moore@Sun.COM { 19779160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 19789160SSherry.Moore@Sun.COM phypath_size)); 19799160SSherry.Moore@Sun.COM } 19809160SSherry.Moore@Sun.COM 19819160SSherry.Moore@Sun.COM /* 19829816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 19839816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 19849816SGeorge.Wilson@Sun.COM */ 19859816SGeorge.Wilson@Sun.COM static int 19869816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 19879816SGeorge.Wilson@Sun.COM { 19889816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 19899816SGeorge.Wilson@Sun.COM char errbuf[1024]; 19909816SGeorge.Wilson@Sun.COM int fd, error; 19919816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 19929816SGeorge.Wilson@Sun.COM 19939816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 19949816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 19959816SGeorge.Wilson@Sun.COM return (-1); 19969816SGeorge.Wilson@Sun.COM 19979816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 19989816SGeorge.Wilson@Sun.COM 19999816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 20009816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 20019816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 20029816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 20039816SGeorge.Wilson@Sun.COM } 20049816SGeorge.Wilson@Sun.COM 20059816SGeorge.Wilson@Sun.COM /* 20069816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 20079816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 20089816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 20099816SGeorge.Wilson@Sun.COM */ 20109816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 20119816SGeorge.Wilson@Sun.COM (void) close(fd); 20129816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 20139816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 20149816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 20159816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 20169816SGeorge.Wilson@Sun.COM } 20179816SGeorge.Wilson@Sun.COM return (0); 20189816SGeorge.Wilson@Sun.COM } 20199816SGeorge.Wilson@Sun.COM 20209816SGeorge.Wilson@Sun.COM /* 20214451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 20224451Seschrock * ZFS_ONLINE_* flags. 2023789Sahrens */ 2024789Sahrens int 20254451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 20264451Seschrock vdev_state_t *newstate) 2027789Sahrens { 2028789Sahrens zfs_cmd_t zc = { 0 }; 2029789Sahrens char msg[1024]; 20302082Seschrock nvlist_t *tgt; 20319816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 20322082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2033789Sahrens 20349816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 20359816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20369816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 20379816SGeorge.Wilson@Sun.COM } else { 20389816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20399816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 20409816SGeorge.Wilson@Sun.COM } 2041789Sahrens 20421544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20437326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 20449816SGeorge.Wilson@Sun.COM &islog)) == NULL) 20452082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2046789Sahrens 20472468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20482468Sek110237 204910817SEric.Schrock@Sun.COM if (avail_spare) 20502082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20512082Seschrock 20529816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 20539816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 20549816SGeorge.Wilson@Sun.COM char *pathname = NULL; 20559816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 20569816SGeorge.Wilson@Sun.COM 20579816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 20589816SGeorge.Wilson@Sun.COM &wholedisk); 20599816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 20609816SGeorge.Wilson@Sun.COM &pathname) == 0); 20619816SGeorge.Wilson@Sun.COM 20629816SGeorge.Wilson@Sun.COM /* 20639816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 20649816SGeorge.Wilson@Sun.COM */ 20659816SGeorge.Wilson@Sun.COM if (l2cache) { 20669816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20679816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 20689816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 20699816SGeorge.Wilson@Sun.COM } 20709816SGeorge.Wilson@Sun.COM 20719816SGeorge.Wilson@Sun.COM if (wholedisk) { 20729816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 20739816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 20749816SGeorge.Wilson@Sun.COM } 20759816SGeorge.Wilson@Sun.COM } 20769816SGeorge.Wilson@Sun.COM 20774451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 20784451Seschrock zc.zc_obj = flags; 20794451Seschrock 2080*11422SMark.Musante@Sun.COM if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) { 2081*11422SMark.Musante@Sun.COM if (errno == EINVAL) { 2082*11422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split " 2083*11422SMark.Musante@Sun.COM "from this pool into a new one. Use '%s' " 2084*11422SMark.Musante@Sun.COM "instead"), "zpool detach"); 2085*11422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg)); 2086*11422SMark.Musante@Sun.COM } 20874451Seschrock return (zpool_standard_error(hdl, errno, msg)); 2088*11422SMark.Musante@Sun.COM } 20894451Seschrock 20904451Seschrock *newstate = zc.zc_cookie; 20914451Seschrock return (0); 2092789Sahrens } 2093789Sahrens 2094789Sahrens /* 2095789Sahrens * Take the specified vdev offline 2096789Sahrens */ 2097789Sahrens int 20984451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2099789Sahrens { 2100789Sahrens zfs_cmd_t zc = { 0 }; 2101789Sahrens char msg[1024]; 21022082Seschrock nvlist_t *tgt; 21035450Sbrendan boolean_t avail_spare, l2cache; 21042082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2105789Sahrens 21061544Seschrock (void) snprintf(msg, sizeof (msg), 21071544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 21081544Seschrock 2109789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21107326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 21117326SEric.Schrock@Sun.COM NULL)) == NULL) 21122082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 21132082Seschrock 21142468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 21152468Sek110237 211610817SEric.Schrock@Sun.COM if (avail_spare) 21172082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21182082Seschrock 21194451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 21204451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 21211485Slling 21224543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2123789Sahrens return (0); 2124789Sahrens 2125789Sahrens switch (errno) { 21262082Seschrock case EBUSY: 2127789Sahrens 2128789Sahrens /* 2129789Sahrens * There are no other replicas of this device. 2130789Sahrens */ 21312082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21322082Seschrock 21339701SGeorge.Wilson@Sun.COM case EEXIST: 21349701SGeorge.Wilson@Sun.COM /* 21359701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 21369701SGeorge.Wilson@Sun.COM */ 21379701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 21389701SGeorge.Wilson@Sun.COM 21392082Seschrock default: 21402082Seschrock return (zpool_standard_error(hdl, errno, msg)); 21412082Seschrock } 21422082Seschrock } 2143789Sahrens 21442082Seschrock /* 21454451Seschrock * Mark the given vdev faulted. 21464451Seschrock */ 21474451Seschrock int 214810817SEric.Schrock@Sun.COM zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21494451Seschrock { 21504451Seschrock zfs_cmd_t zc = { 0 }; 21514451Seschrock char msg[1024]; 21524451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21534451Seschrock 21544451Seschrock (void) snprintf(msg, sizeof (msg), 21554451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 21564451Seschrock 21574451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21584451Seschrock zc.zc_guid = guid; 21594451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 216010817SEric.Schrock@Sun.COM zc.zc_obj = aux; 21614451Seschrock 21624451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21634451Seschrock return (0); 21644451Seschrock 21654451Seschrock switch (errno) { 21664451Seschrock case EBUSY: 21674451Seschrock 21684451Seschrock /* 21694451Seschrock * There are no other replicas of this device. 21704451Seschrock */ 21714451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21724451Seschrock 21734451Seschrock default: 21744451Seschrock return (zpool_standard_error(hdl, errno, msg)); 21754451Seschrock } 21764451Seschrock 21774451Seschrock } 21784451Seschrock 21794451Seschrock /* 21804451Seschrock * Mark the given vdev degraded. 21814451Seschrock */ 21824451Seschrock int 218310817SEric.Schrock@Sun.COM zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21844451Seschrock { 21854451Seschrock zfs_cmd_t zc = { 0 }; 21864451Seschrock char msg[1024]; 21874451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21884451Seschrock 21894451Seschrock (void) snprintf(msg, sizeof (msg), 21904451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 21914451Seschrock 21924451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21934451Seschrock zc.zc_guid = guid; 21944451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 219510817SEric.Schrock@Sun.COM zc.zc_obj = aux; 21964451Seschrock 21974451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21984451Seschrock return (0); 21994451Seschrock 22004451Seschrock return (zpool_standard_error(hdl, errno, msg)); 22014451Seschrock } 22024451Seschrock 22034451Seschrock /* 22042082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 22052082Seschrock * a hot spare. 22062082Seschrock */ 22072082Seschrock static boolean_t 22082082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 22092082Seschrock { 22102082Seschrock nvlist_t **child; 22112082Seschrock uint_t c, children; 22122082Seschrock char *type; 22132082Seschrock 22142082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 22152082Seschrock &children) == 0) { 22162082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 22172082Seschrock &type) == 0); 22182082Seschrock 22192082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 22202082Seschrock children == 2 && child[which] == tgt) 22212082Seschrock return (B_TRUE); 22222082Seschrock 22232082Seschrock for (c = 0; c < children; c++) 22242082Seschrock if (is_replacing_spare(child[c], tgt, which)) 22252082Seschrock return (B_TRUE); 2226789Sahrens } 22272082Seschrock 22282082Seschrock return (B_FALSE); 2229789Sahrens } 2230789Sahrens 2231789Sahrens /* 2232789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 22334527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2234789Sahrens */ 2235789Sahrens int 2236789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2237789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2238789Sahrens { 2239789Sahrens zfs_cmd_t zc = { 0 }; 2240789Sahrens char msg[1024]; 2241789Sahrens int ret; 22422082Seschrock nvlist_t *tgt; 22437326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 22447326SEric.Schrock@Sun.COM uint64_t val; 22457041Seschrock char *path, *newname; 22462082Seschrock nvlist_t **child; 22472082Seschrock uint_t children; 22482082Seschrock nvlist_t *config_root; 22492082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22507965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2251789Sahrens 22521544Seschrock if (replacing) 22531544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 22541544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 22551544Seschrock else 22561544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 22571544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 22581544Seschrock 22597965SGeorge.Wilson@Sun.COM /* 22607965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 22617965SGeorge.Wilson@Sun.COM * EFI labeled device. 22627965SGeorge.Wilson@Sun.COM */ 22637965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 22647965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22657965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 22667965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 22677965SGeorge.Wilson@Sun.COM } 22687965SGeorge.Wilson@Sun.COM 2269789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22707326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 22717326SEric.Schrock@Sun.COM &islog)) == 0) 22722082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22732082Seschrock 22742468Sek110237 if (avail_spare) 22752082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22762082Seschrock 22775450Sbrendan if (l2cache) 22785450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 22795450Sbrendan 22802082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22812082Seschrock zc.zc_cookie = replacing; 22822082Seschrock 22832082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 22842082Seschrock &child, &children) != 0 || children != 1) { 22852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22862082Seschrock "new device must be a single disk")); 22872082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 22881544Seschrock } 22892082Seschrock 22902082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 22912082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 22922082Seschrock 229310594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 22947041Seschrock return (-1); 22957041Seschrock 22962082Seschrock /* 22972082Seschrock * If the target is a hot spare that has been swapped in, we can only 22982082Seschrock * replace it with another hot spare. 22992082Seschrock */ 23002082Seschrock if (replacing && 23012082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 23027326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 23037326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 23047326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 23052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23062082Seschrock "can only be replaced by another hot spare")); 23077041Seschrock free(newname); 23082082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 23092082Seschrock } 23102082Seschrock 23112082Seschrock /* 23122082Seschrock * If we are attempting to replace a spare, it canot be applied to an 23132082Seschrock * already spared device. 23142082Seschrock */ 23152082Seschrock if (replacing && 23162082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 23177326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 23187326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 23197326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 23202082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23212082Seschrock "device has already been replaced with a spare")); 23227041Seschrock free(newname); 23232082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 23242082Seschrock } 2325789Sahrens 23267041Seschrock free(newname); 23277041Seschrock 23285094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 23292082Seschrock return (-1); 2330789Sahrens 23314543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2332789Sahrens 23332676Seschrock zcmd_free_nvlists(&zc); 2334789Sahrens 23357965SGeorge.Wilson@Sun.COM if (ret == 0) { 23367965SGeorge.Wilson@Sun.COM if (rootpool) { 23377965SGeorge.Wilson@Sun.COM /* 23387965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 23397965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 23407965SGeorge.Wilson@Sun.COM * newly attached disk. 23417965SGeorge.Wilson@Sun.COM */ 23427965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 23437965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 23447965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 23459790SLin.Ling@Sun.COM 23469790SLin.Ling@Sun.COM /* 23479790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 23489790SLin.Ling@Sun.COM * booting up a half-baked vdev. 23499790SLin.Ling@Sun.COM */ 23509790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 23519790SLin.Ling@Sun.COM "sure to wait until resilver is done " 23529790SLin.Ling@Sun.COM "before rebooting.\n")); 23537965SGeorge.Wilson@Sun.COM } 2354789Sahrens return (0); 23557965SGeorge.Wilson@Sun.COM } 2356789Sahrens 2357789Sahrens switch (errno) { 23581544Seschrock case ENOTSUP: 2359789Sahrens /* 2360789Sahrens * Can't attach to or replace this type of vdev. 2361789Sahrens */ 23624527Sperrin if (replacing) { 23637326SEric.Schrock@Sun.COM if (islog) 23644527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23654527Sperrin "cannot replace a log with a spare")); 23664527Sperrin else 23674527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23684527Sperrin "cannot replace a replacing device")); 23694527Sperrin } else { 23702082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23712082Seschrock "can only attach to mirrors and top-level " 23722082Seschrock "disks")); 23734527Sperrin } 23742082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2375789Sahrens break; 2376789Sahrens 23771544Seschrock case EINVAL: 2378789Sahrens /* 2379789Sahrens * The new device must be a single disk. 2380789Sahrens */ 23812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23822082Seschrock "new device must be a single disk")); 23832082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2384789Sahrens break; 2385789Sahrens 23861544Seschrock case EBUSY: 23872082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 23882082Seschrock new_disk); 23892082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2390789Sahrens break; 2391789Sahrens 23921544Seschrock case EOVERFLOW: 2393789Sahrens /* 2394789Sahrens * The new device is too small. 2395789Sahrens */ 23962082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23972082Seschrock "device is too small")); 23982082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2399789Sahrens break; 2400789Sahrens 24011544Seschrock case EDOM: 2402789Sahrens /* 2403789Sahrens * The new device has a different alignment requirement. 2404789Sahrens */ 24052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24062082Seschrock "devices have different sector alignment")); 24072082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2408789Sahrens break; 2409789Sahrens 24101544Seschrock case ENAMETOOLONG: 2411789Sahrens /* 2412789Sahrens * The resulting top-level vdev spec won't fit in the label. 2413789Sahrens */ 24142082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2415789Sahrens break; 2416789Sahrens 24171544Seschrock default: 24182082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2419789Sahrens } 2420789Sahrens 24212082Seschrock return (-1); 2422789Sahrens } 2423789Sahrens 2424789Sahrens /* 2425789Sahrens * Detach the specified device. 2426789Sahrens */ 2427789Sahrens int 2428789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2429789Sahrens { 2430789Sahrens zfs_cmd_t zc = { 0 }; 2431789Sahrens char msg[1024]; 24322082Seschrock nvlist_t *tgt; 24335450Sbrendan boolean_t avail_spare, l2cache; 24342082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2435789Sahrens 24361544Seschrock (void) snprintf(msg, sizeof (msg), 24371544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 24381544Seschrock 2439789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24407326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 24417326SEric.Schrock@Sun.COM NULL)) == 0) 24422082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2443789Sahrens 24442468Sek110237 if (avail_spare) 24452082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 24462082Seschrock 24475450Sbrendan if (l2cache) 24485450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 24495450Sbrendan 24502082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 24512082Seschrock 24524543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2453789Sahrens return (0); 2454789Sahrens 2455789Sahrens switch (errno) { 2456789Sahrens 24571544Seschrock case ENOTSUP: 2458789Sahrens /* 2459789Sahrens * Can't detach from this type of vdev. 2460789Sahrens */ 24612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 24622082Seschrock "applicable to mirror and replacing vdevs")); 24632082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2464789Sahrens break; 2465789Sahrens 24661544Seschrock case EBUSY: 2467789Sahrens /* 2468789Sahrens * There are no other replicas of this device. 2469789Sahrens */ 24702082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2471789Sahrens break; 2472789Sahrens 24731544Seschrock default: 24742082Seschrock (void) zpool_standard_error(hdl, errno, msg); 24751544Seschrock } 24761544Seschrock 24772082Seschrock return (-1); 24782082Seschrock } 24792082Seschrock 24802082Seschrock /* 2481*11422SMark.Musante@Sun.COM * Find a mirror vdev in the source nvlist. 2482*11422SMark.Musante@Sun.COM * 2483*11422SMark.Musante@Sun.COM * The mchild array contains a list of disks in one of the top-level mirrors 2484*11422SMark.Musante@Sun.COM * of the source pool. The schild array contains a list of disks that the 2485*11422SMark.Musante@Sun.COM * user specified on the command line. We loop over the mchild array to 2486*11422SMark.Musante@Sun.COM * see if any entry in the schild array matches. 2487*11422SMark.Musante@Sun.COM * 2488*11422SMark.Musante@Sun.COM * If a disk in the mchild array is found in the schild array, we return 2489*11422SMark.Musante@Sun.COM * the index of that entry. Otherwise we return -1. 2490*11422SMark.Musante@Sun.COM */ 2491*11422SMark.Musante@Sun.COM static int 2492*11422SMark.Musante@Sun.COM find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren, 2493*11422SMark.Musante@Sun.COM nvlist_t **schild, uint_t schildren) 2494*11422SMark.Musante@Sun.COM { 2495*11422SMark.Musante@Sun.COM uint_t mc; 2496*11422SMark.Musante@Sun.COM 2497*11422SMark.Musante@Sun.COM for (mc = 0; mc < mchildren; mc++) { 2498*11422SMark.Musante@Sun.COM uint_t sc; 2499*11422SMark.Musante@Sun.COM char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp, 2500*11422SMark.Musante@Sun.COM mchild[mc], B_FALSE); 2501*11422SMark.Musante@Sun.COM 2502*11422SMark.Musante@Sun.COM for (sc = 0; sc < schildren; sc++) { 2503*11422SMark.Musante@Sun.COM char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp, 2504*11422SMark.Musante@Sun.COM schild[sc], B_FALSE); 2505*11422SMark.Musante@Sun.COM boolean_t result = (strcmp(mpath, spath) == 0); 2506*11422SMark.Musante@Sun.COM 2507*11422SMark.Musante@Sun.COM free(spath); 2508*11422SMark.Musante@Sun.COM if (result) { 2509*11422SMark.Musante@Sun.COM free(mpath); 2510*11422SMark.Musante@Sun.COM return (mc); 2511*11422SMark.Musante@Sun.COM } 2512*11422SMark.Musante@Sun.COM } 2513*11422SMark.Musante@Sun.COM 2514*11422SMark.Musante@Sun.COM free(mpath); 2515*11422SMark.Musante@Sun.COM } 2516*11422SMark.Musante@Sun.COM 2517*11422SMark.Musante@Sun.COM return (-1); 2518*11422SMark.Musante@Sun.COM } 2519*11422SMark.Musante@Sun.COM 2520*11422SMark.Musante@Sun.COM /* 2521*11422SMark.Musante@Sun.COM * Split a mirror pool. If newroot points to null, then a new nvlist 2522*11422SMark.Musante@Sun.COM * is generated and it is the responsibility of the caller to free it. 2523*11422SMark.Musante@Sun.COM */ 2524*11422SMark.Musante@Sun.COM int 2525*11422SMark.Musante@Sun.COM zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot, 2526*11422SMark.Musante@Sun.COM nvlist_t *props, splitflags_t flags) 2527*11422SMark.Musante@Sun.COM { 2528*11422SMark.Musante@Sun.COM zfs_cmd_t zc = { 0 }; 2529*11422SMark.Musante@Sun.COM char msg[1024]; 2530*11422SMark.Musante@Sun.COM nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL; 2531*11422SMark.Musante@Sun.COM nvlist_t **varray = NULL, *zc_props = NULL; 2532*11422SMark.Musante@Sun.COM uint_t c, children, newchildren, lastlog = 0, vcount, found = 0; 2533*11422SMark.Musante@Sun.COM libzfs_handle_t *hdl = zhp->zpool_hdl; 2534*11422SMark.Musante@Sun.COM uint64_t vers; 2535*11422SMark.Musante@Sun.COM boolean_t freelist = B_FALSE, memory_err = B_TRUE; 2536*11422SMark.Musante@Sun.COM int retval = 0; 2537*11422SMark.Musante@Sun.COM 2538*11422SMark.Musante@Sun.COM (void) snprintf(msg, sizeof (msg), 2539*11422SMark.Musante@Sun.COM dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name); 2540*11422SMark.Musante@Sun.COM 2541*11422SMark.Musante@Sun.COM if (!zpool_name_valid(hdl, B_FALSE, newname)) 2542*11422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 2543*11422SMark.Musante@Sun.COM 2544*11422SMark.Musante@Sun.COM if ((config = zpool_get_config(zhp, NULL)) == NULL) { 2545*11422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Internal error: unable to " 2546*11422SMark.Musante@Sun.COM "retrieve pool configuration\n")); 2547*11422SMark.Musante@Sun.COM return (-1); 2548*11422SMark.Musante@Sun.COM } 2549*11422SMark.Musante@Sun.COM 2550*11422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) 2551*11422SMark.Musante@Sun.COM == 0); 2552*11422SMark.Musante@Sun.COM verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0); 2553*11422SMark.Musante@Sun.COM 2554*11422SMark.Musante@Sun.COM if (props) { 2555*11422SMark.Musante@Sun.COM if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name, 2556*11422SMark.Musante@Sun.COM props, vers, B_TRUE, msg)) == NULL) 2557*11422SMark.Musante@Sun.COM return (-1); 2558*11422SMark.Musante@Sun.COM } 2559*11422SMark.Musante@Sun.COM 2560*11422SMark.Musante@Sun.COM if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, 2561*11422SMark.Musante@Sun.COM &children) != 0) { 2562*11422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2563*11422SMark.Musante@Sun.COM "Source pool is missing vdev tree")); 2564*11422SMark.Musante@Sun.COM if (zc_props) 2565*11422SMark.Musante@Sun.COM nvlist_free(zc_props); 2566*11422SMark.Musante@Sun.COM return (-1); 2567*11422SMark.Musante@Sun.COM } 2568*11422SMark.Musante@Sun.COM 2569*11422SMark.Musante@Sun.COM varray = zfs_alloc(hdl, children * sizeof (nvlist_t *)); 2570*11422SMark.Musante@Sun.COM vcount = 0; 2571*11422SMark.Musante@Sun.COM 2572*11422SMark.Musante@Sun.COM if (*newroot == NULL || 2573*11422SMark.Musante@Sun.COM nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, 2574*11422SMark.Musante@Sun.COM &newchild, &newchildren) != 0) 2575*11422SMark.Musante@Sun.COM newchildren = 0; 2576*11422SMark.Musante@Sun.COM 2577*11422SMark.Musante@Sun.COM for (c = 0; c < children; c++) { 2578*11422SMark.Musante@Sun.COM uint64_t is_log = B_FALSE, is_hole = B_FALSE; 2579*11422SMark.Musante@Sun.COM char *type; 2580*11422SMark.Musante@Sun.COM nvlist_t **mchild, *vdev; 2581*11422SMark.Musante@Sun.COM uint_t mchildren; 2582*11422SMark.Musante@Sun.COM int entry; 2583*11422SMark.Musante@Sun.COM 2584*11422SMark.Musante@Sun.COM /* 2585*11422SMark.Musante@Sun.COM * Unlike cache & spares, slogs are stored in the 2586*11422SMark.Musante@Sun.COM * ZPOOL_CONFIG_CHILDREN array. We filter them out here. 2587*11422SMark.Musante@Sun.COM */ 2588*11422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 2589*11422SMark.Musante@Sun.COM &is_log); 2590*11422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 2591*11422SMark.Musante@Sun.COM &is_hole); 2592*11422SMark.Musante@Sun.COM if (is_log || is_hole) { 2593*11422SMark.Musante@Sun.COM /* 2594*11422SMark.Musante@Sun.COM * Create a hole vdev and put it in the config. 2595*11422SMark.Musante@Sun.COM */ 2596*11422SMark.Musante@Sun.COM if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0) 2597*11422SMark.Musante@Sun.COM goto out; 2598*11422SMark.Musante@Sun.COM if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, 2599*11422SMark.Musante@Sun.COM VDEV_TYPE_HOLE) != 0) 2600*11422SMark.Musante@Sun.COM goto out; 2601*11422SMark.Musante@Sun.COM if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE, 2602*11422SMark.Musante@Sun.COM 1) != 0) 2603*11422SMark.Musante@Sun.COM goto out; 2604*11422SMark.Musante@Sun.COM if (lastlog == 0) 2605*11422SMark.Musante@Sun.COM lastlog = vcount; 2606*11422SMark.Musante@Sun.COM varray[vcount++] = vdev; 2607*11422SMark.Musante@Sun.COM continue; 2608*11422SMark.Musante@Sun.COM } 2609*11422SMark.Musante@Sun.COM lastlog = 0; 2610*11422SMark.Musante@Sun.COM verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type) 2611*11422SMark.Musante@Sun.COM == 0); 2612*11422SMark.Musante@Sun.COM if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 2613*11422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2614*11422SMark.Musante@Sun.COM "Source pool must be composed only of mirrors\n")); 2615*11422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 2616*11422SMark.Musante@Sun.COM goto out; 2617*11422SMark.Musante@Sun.COM } 2618*11422SMark.Musante@Sun.COM 2619*11422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist_array(child[c], 2620*11422SMark.Musante@Sun.COM ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0); 2621*11422SMark.Musante@Sun.COM 2622*11422SMark.Musante@Sun.COM /* find or add an entry for this top-level vdev */ 2623*11422SMark.Musante@Sun.COM if (newchildren > 0 && 2624*11422SMark.Musante@Sun.COM (entry = find_vdev_entry(zhp, mchild, mchildren, 2625*11422SMark.Musante@Sun.COM newchild, newchildren)) >= 0) { 2626*11422SMark.Musante@Sun.COM /* We found a disk that the user specified. */ 2627*11422SMark.Musante@Sun.COM vdev = mchild[entry]; 2628*11422SMark.Musante@Sun.COM ++found; 2629*11422SMark.Musante@Sun.COM } else { 2630*11422SMark.Musante@Sun.COM /* User didn't specify a disk for this vdev. */ 2631*11422SMark.Musante@Sun.COM vdev = mchild[mchildren - 1]; 2632*11422SMark.Musante@Sun.COM } 2633*11422SMark.Musante@Sun.COM 2634*11422SMark.Musante@Sun.COM if (nvlist_dup(vdev, &varray[vcount++], 0) != 0) 2635*11422SMark.Musante@Sun.COM goto out; 2636*11422SMark.Musante@Sun.COM } 2637*11422SMark.Musante@Sun.COM 2638*11422SMark.Musante@Sun.COM /* did we find every disk the user specified? */ 2639*11422SMark.Musante@Sun.COM if (found != newchildren) { 2640*11422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must " 2641*11422SMark.Musante@Sun.COM "include at most one disk from each mirror")); 2642*11422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 2643*11422SMark.Musante@Sun.COM goto out; 2644*11422SMark.Musante@Sun.COM } 2645*11422SMark.Musante@Sun.COM 2646*11422SMark.Musante@Sun.COM /* Prepare the nvlist for populating. */ 2647*11422SMark.Musante@Sun.COM if (*newroot == NULL) { 2648*11422SMark.Musante@Sun.COM if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0) 2649*11422SMark.Musante@Sun.COM goto out; 2650*11422SMark.Musante@Sun.COM freelist = B_TRUE; 2651*11422SMark.Musante@Sun.COM if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE, 2652*11422SMark.Musante@Sun.COM VDEV_TYPE_ROOT) != 0) 2653*11422SMark.Musante@Sun.COM goto out; 2654*11422SMark.Musante@Sun.COM } else { 2655*11422SMark.Musante@Sun.COM verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0); 2656*11422SMark.Musante@Sun.COM } 2657*11422SMark.Musante@Sun.COM 2658*11422SMark.Musante@Sun.COM /* Add all the children we found */ 2659*11422SMark.Musante@Sun.COM if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray, 2660*11422SMark.Musante@Sun.COM lastlog == 0 ? vcount : lastlog) != 0) 2661*11422SMark.Musante@Sun.COM goto out; 2662*11422SMark.Musante@Sun.COM 2663*11422SMark.Musante@Sun.COM /* 2664*11422SMark.Musante@Sun.COM * If we're just doing a dry run, exit now with success. 2665*11422SMark.Musante@Sun.COM */ 2666*11422SMark.Musante@Sun.COM if (flags.dryrun) { 2667*11422SMark.Musante@Sun.COM memory_err = B_FALSE; 2668*11422SMark.Musante@Sun.COM freelist = B_FALSE; 2669*11422SMark.Musante@Sun.COM goto out; 2670*11422SMark.Musante@Sun.COM } 2671*11422SMark.Musante@Sun.COM 2672*11422SMark.Musante@Sun.COM /* now build up the config list & call the ioctl */ 2673*11422SMark.Musante@Sun.COM if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0) 2674*11422SMark.Musante@Sun.COM goto out; 2675*11422SMark.Musante@Sun.COM 2676*11422SMark.Musante@Sun.COM if (nvlist_add_nvlist(newconfig, 2677*11422SMark.Musante@Sun.COM ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 || 2678*11422SMark.Musante@Sun.COM nvlist_add_string(newconfig, 2679*11422SMark.Musante@Sun.COM ZPOOL_CONFIG_POOL_NAME, newname) != 0 || 2680*11422SMark.Musante@Sun.COM nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0) 2681*11422SMark.Musante@Sun.COM goto out; 2682*11422SMark.Musante@Sun.COM 2683*11422SMark.Musante@Sun.COM /* 2684*11422SMark.Musante@Sun.COM * The new pool is automatically part of the namespace unless we 2685*11422SMark.Musante@Sun.COM * explicitly export it. 2686*11422SMark.Musante@Sun.COM */ 2687*11422SMark.Musante@Sun.COM if (!flags.import) 2688*11422SMark.Musante@Sun.COM zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT; 2689*11422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2690*11422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string)); 2691*11422SMark.Musante@Sun.COM if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0) 2692*11422SMark.Musante@Sun.COM goto out; 2693*11422SMark.Musante@Sun.COM if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 2694*11422SMark.Musante@Sun.COM goto out; 2695*11422SMark.Musante@Sun.COM 2696*11422SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) { 2697*11422SMark.Musante@Sun.COM retval = zpool_standard_error(hdl, errno, msg); 2698*11422SMark.Musante@Sun.COM goto out; 2699*11422SMark.Musante@Sun.COM } 2700*11422SMark.Musante@Sun.COM 2701*11422SMark.Musante@Sun.COM freelist = B_FALSE; 2702*11422SMark.Musante@Sun.COM memory_err = B_FALSE; 2703*11422SMark.Musante@Sun.COM 2704*11422SMark.Musante@Sun.COM out: 2705*11422SMark.Musante@Sun.COM if (varray != NULL) { 2706*11422SMark.Musante@Sun.COM int v; 2707*11422SMark.Musante@Sun.COM 2708*11422SMark.Musante@Sun.COM for (v = 0; v < vcount; v++) 2709*11422SMark.Musante@Sun.COM nvlist_free(varray[v]); 2710*11422SMark.Musante@Sun.COM free(varray); 2711*11422SMark.Musante@Sun.COM } 2712*11422SMark.Musante@Sun.COM zcmd_free_nvlists(&zc); 2713*11422SMark.Musante@Sun.COM if (zc_props) 2714*11422SMark.Musante@Sun.COM nvlist_free(zc_props); 2715*11422SMark.Musante@Sun.COM if (newconfig) 2716*11422SMark.Musante@Sun.COM nvlist_free(newconfig); 2717*11422SMark.Musante@Sun.COM if (freelist) { 2718*11422SMark.Musante@Sun.COM nvlist_free(*newroot); 2719*11422SMark.Musante@Sun.COM *newroot = NULL; 2720*11422SMark.Musante@Sun.COM } 2721*11422SMark.Musante@Sun.COM 2722*11422SMark.Musante@Sun.COM if (retval != 0) 2723*11422SMark.Musante@Sun.COM return (retval); 2724*11422SMark.Musante@Sun.COM 2725*11422SMark.Musante@Sun.COM if (memory_err) 2726*11422SMark.Musante@Sun.COM return (no_memory(hdl)); 2727*11422SMark.Musante@Sun.COM 2728*11422SMark.Musante@Sun.COM return (0); 2729*11422SMark.Musante@Sun.COM } 2730*11422SMark.Musante@Sun.COM 2731*11422SMark.Musante@Sun.COM /* 27325450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 27335450Sbrendan * and level 2 cache devices. 27342082Seschrock */ 27352082Seschrock int 27362082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 27372082Seschrock { 27382082Seschrock zfs_cmd_t zc = { 0 }; 27392082Seschrock char msg[1024]; 27402082Seschrock nvlist_t *tgt; 274110594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 27422082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 274310594SGeorge.Wilson@Sun.COM uint64_t version; 27442082Seschrock 27452082Seschrock (void) snprintf(msg, sizeof (msg), 27462082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 27472082Seschrock 27482082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 27497326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 275010594SGeorge.Wilson@Sun.COM &islog)) == 0) 27512082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 275210594SGeorge.Wilson@Sun.COM /* 275310594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 275410594SGeorge.Wilson@Sun.COM */ 275510594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 27562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 275710594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 275810594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 27592082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 27602082Seschrock } 27612082Seschrock 276210594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 276310594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 276410594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 276510594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 276610594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 276710594SGeorge.Wilson@Sun.COM } 276810594SGeorge.Wilson@Sun.COM 27692082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 27702082Seschrock 27714543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 27722082Seschrock return (0); 27732082Seschrock 27742082Seschrock return (zpool_standard_error(hdl, errno, msg)); 27751544Seschrock } 27761544Seschrock 27771544Seschrock /* 27781544Seschrock * Clear the errors for the pool, or the particular device if specified. 27791544Seschrock */ 27801544Seschrock int 278110921STim.Haley@Sun.COM zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 27821544Seschrock { 27831544Seschrock zfs_cmd_t zc = { 0 }; 27841544Seschrock char msg[1024]; 27852082Seschrock nvlist_t *tgt; 278610921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 27875450Sbrendan boolean_t avail_spare, l2cache; 27882082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 278910921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 27901544Seschrock 27911544Seschrock if (path) 27921544Seschrock (void) snprintf(msg, sizeof (msg), 27931544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 27942676Seschrock path); 27951544Seschrock else 27961544Seschrock (void) snprintf(msg, sizeof (msg), 27971544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 27981544Seschrock zhp->zpool_name); 27991544Seschrock 28001544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28012082Seschrock if (path) { 28025450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 28037326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 28042082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 28052082Seschrock 28065450Sbrendan /* 28075450Sbrendan * Don't allow error clearing for hot spares. Do allow 28085450Sbrendan * error clearing for l2cache devices. 28095450Sbrendan */ 28102468Sek110237 if (avail_spare) 28112082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 28122082Seschrock 28132082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 28142082Seschrock &zc.zc_guid) == 0); 28151544Seschrock } 28161544Seschrock 281710921STim.Haley@Sun.COM zpool_get_rewind_policy(rewindnvl, &policy); 281810921STim.Haley@Sun.COM zc.zc_cookie = policy.zrp_request; 281910921STim.Haley@Sun.COM 282010921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0) 282110921STim.Haley@Sun.COM return (-1); 282210921STim.Haley@Sun.COM 282310921STim.Haley@Sun.COM if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0) 282410921STim.Haley@Sun.COM return (-1); 282510921STim.Haley@Sun.COM 282610921STim.Haley@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 || 282710921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) && 282810921STim.Haley@Sun.COM errno != EPERM && errno != EACCES)) { 282910921STim.Haley@Sun.COM if (policy.zrp_request & 283010921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 283110921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 283210921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, zc.zc_name, 283310921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 283410921STim.Haley@Sun.COM nvi); 283510921STim.Haley@Sun.COM nvlist_free(nvi); 283610921STim.Haley@Sun.COM } 283710921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 28381544Seschrock return (0); 283910921STim.Haley@Sun.COM } 284010921STim.Haley@Sun.COM 284110921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 28422082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2843789Sahrens } 2844789Sahrens 28453126Sahl /* 28464451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 28474451Seschrock */ 28484451Seschrock int 28494451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 28504451Seschrock { 28514451Seschrock zfs_cmd_t zc = { 0 }; 28524451Seschrock char msg[1024]; 28534451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 28544451Seschrock 28554451Seschrock (void) snprintf(msg, sizeof (msg), 28564451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 28574451Seschrock guid); 28584451Seschrock 28594451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28604451Seschrock zc.zc_guid = guid; 28614451Seschrock 28624451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 28634451Seschrock return (0); 28644451Seschrock 28654451Seschrock return (zpool_standard_error(hdl, errno, msg)); 28664451Seschrock } 28674451Seschrock 28684451Seschrock /* 28691354Seschrock * Convert from a devid string to a path. 28701354Seschrock */ 28711354Seschrock static char * 28721354Seschrock devid_to_path(char *devid_str) 28731354Seschrock { 28741354Seschrock ddi_devid_t devid; 28751354Seschrock char *minor; 28761354Seschrock char *path; 28771354Seschrock devid_nmlist_t *list = NULL; 28781354Seschrock int ret; 28791354Seschrock 28801354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 28811354Seschrock return (NULL); 28821354Seschrock 28831354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 28841354Seschrock 28851354Seschrock devid_str_free(minor); 28861354Seschrock devid_free(devid); 28871354Seschrock 28881354Seschrock if (ret != 0) 28891354Seschrock return (NULL); 28901354Seschrock 28912082Seschrock if ((path = strdup(list[0].devname)) == NULL) 28922082Seschrock return (NULL); 28932082Seschrock 28941354Seschrock devid_free_nmlist(list); 28951354Seschrock 28961354Seschrock return (path); 28971354Seschrock } 28981354Seschrock 28991354Seschrock /* 29001354Seschrock * Convert from a path to a devid string. 29011354Seschrock */ 29021354Seschrock static char * 29031354Seschrock path_to_devid(const char *path) 29041354Seschrock { 29051354Seschrock int fd; 29061354Seschrock ddi_devid_t devid; 29071354Seschrock char *minor, *ret; 29081354Seschrock 29091354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 29101354Seschrock return (NULL); 29111354Seschrock 29121354Seschrock minor = NULL; 29131354Seschrock ret = NULL; 29141354Seschrock if (devid_get(fd, &devid) == 0) { 29151354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 29161354Seschrock ret = devid_str_encode(devid, minor); 29171354Seschrock if (minor != NULL) 29181354Seschrock devid_str_free(minor); 29191354Seschrock devid_free(devid); 29201354Seschrock } 29211354Seschrock (void) close(fd); 29221354Seschrock 29231354Seschrock return (ret); 29241354Seschrock } 29251354Seschrock 29261354Seschrock /* 29271354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 29281354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 29291354Seschrock * type 'zpool status', and we'll display the correct information anyway. 29301354Seschrock */ 29311354Seschrock static void 29321354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 29331354Seschrock { 29341354Seschrock zfs_cmd_t zc = { 0 }; 29351354Seschrock 29361354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29372676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 29381354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 29391544Seschrock &zc.zc_guid) == 0); 29401354Seschrock 29412082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 29421354Seschrock } 29431354Seschrock 29441354Seschrock /* 29451354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 29461354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 29471354Seschrock * We also check if this is a whole disk, in which case we strip off the 29481354Seschrock * trailing 's0' slice name. 29491354Seschrock * 29501354Seschrock * This routine is also responsible for identifying when disks have been 29511354Seschrock * reconfigured in a new location. The kernel will have opened the device by 29521354Seschrock * devid, but the path will still refer to the old location. To catch this, we 29531354Seschrock * first do a path -> devid translation (which is fast for the common case). If 29541354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 29551354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 29561354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 29571354Seschrock * of these checks. 29581354Seschrock */ 29591354Seschrock char * 296010594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 296110594SGeorge.Wilson@Sun.COM boolean_t verbose) 29621354Seschrock { 29631354Seschrock char *path, *devid; 29641544Seschrock uint64_t value; 29651544Seschrock char buf[64]; 29664451Seschrock vdev_stat_t *vs; 29674451Seschrock uint_t vsc; 29681354Seschrock 29691544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 29701544Seschrock &value) == 0) { 29711544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 29721544Seschrock &value) == 0); 29732856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 29742856Snd150628 (u_longlong_t)value); 29751544Seschrock path = buf; 29761544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 29771354Seschrock 29784451Seschrock /* 29794451Seschrock * If the device is dead (faulted, offline, etc) then don't 29804451Seschrock * bother opening it. Otherwise we may be forcing the user to 29814451Seschrock * open a misbehaving device, which can have undesirable 29824451Seschrock * effects. 29834451Seschrock */ 29844451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 29854451Seschrock (uint64_t **)&vs, &vsc) != 0 || 29864451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 29874451Seschrock zhp != NULL && 29881354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 29891354Seschrock /* 29901354Seschrock * Determine if the current path is correct. 29911354Seschrock */ 29921354Seschrock char *newdevid = path_to_devid(path); 29931354Seschrock 29941354Seschrock if (newdevid == NULL || 29951354Seschrock strcmp(devid, newdevid) != 0) { 29961354Seschrock char *newpath; 29971354Seschrock 29981354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 29991354Seschrock /* 30001354Seschrock * Update the path appropriately. 30011354Seschrock */ 30021354Seschrock set_path(zhp, nv, newpath); 30032082Seschrock if (nvlist_add_string(nv, 30042082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 30052082Seschrock verify(nvlist_lookup_string(nv, 30062082Seschrock ZPOOL_CONFIG_PATH, 30072082Seschrock &path) == 0); 30081354Seschrock free(newpath); 30091354Seschrock } 30101354Seschrock } 30111354Seschrock 30122082Seschrock if (newdevid) 30132082Seschrock devid_str_free(newdevid); 30141354Seschrock } 30151354Seschrock 30161354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 30171354Seschrock path += 9; 30181354Seschrock 30191354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 30201544Seschrock &value) == 0 && value) { 30212082Seschrock char *tmp = zfs_strdup(hdl, path); 30222082Seschrock if (tmp == NULL) 30232082Seschrock return (NULL); 30241354Seschrock tmp[strlen(path) - 2] = '\0'; 30251354Seschrock return (tmp); 30261354Seschrock } 30271354Seschrock } else { 30281354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 30292082Seschrock 30302082Seschrock /* 30312082Seschrock * If it's a raidz device, we need to stick in the parity level. 30322082Seschrock */ 30332082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 30342082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 30352082Seschrock &value) == 0); 30362082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 30372856Snd150628 (u_longlong_t)value); 30382082Seschrock path = buf; 30392082Seschrock } 304010594SGeorge.Wilson@Sun.COM 304110594SGeorge.Wilson@Sun.COM /* 304210594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 304310594SGeorge.Wilson@Sun.COM * naming convention. 304410594SGeorge.Wilson@Sun.COM */ 304510594SGeorge.Wilson@Sun.COM if (verbose) { 304610594SGeorge.Wilson@Sun.COM uint64_t id; 304710594SGeorge.Wilson@Sun.COM 304810594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 304910594SGeorge.Wilson@Sun.COM &id) == 0); 305010594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 305110594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 305210594SGeorge.Wilson@Sun.COM path = buf; 305310594SGeorge.Wilson@Sun.COM } 30541354Seschrock } 30551354Seschrock 30562082Seschrock return (zfs_strdup(hdl, path)); 30571354Seschrock } 30581544Seschrock 30591544Seschrock static int 30601544Seschrock zbookmark_compare(const void *a, const void *b) 30611544Seschrock { 30621544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 30631544Seschrock } 30641544Seschrock 30651544Seschrock /* 30661544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 30671544Seschrock * caller. 30681544Seschrock */ 30691544Seschrock int 30703444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 30711544Seschrock { 30721544Seschrock zfs_cmd_t zc = { 0 }; 30731544Seschrock uint64_t count; 30742676Seschrock zbookmark_t *zb = NULL; 30753444Sek110237 int i; 30761544Seschrock 30771544Seschrock /* 30781544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 30791544Seschrock * has increased, allocate more space and continue until we get the 30801544Seschrock * entire list. 30811544Seschrock */ 30821544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 30831544Seschrock &count) == 0); 30844820Sek110237 if (count == 0) 30854820Sek110237 return (0); 30862676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 30872856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 30882082Seschrock return (-1); 30892676Seschrock zc.zc_nvlist_dst_size = count; 30901544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 30911544Seschrock for (;;) { 30922082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 30932082Seschrock &zc) != 0) { 30942676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 30951544Seschrock if (errno == ENOMEM) { 30963823Svb160487 count = zc.zc_nvlist_dst_size; 30972676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 30983823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 30993823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 31002082Seschrock return (-1); 31011544Seschrock } else { 31021544Seschrock return (-1); 31031544Seschrock } 31041544Seschrock } else { 31051544Seschrock break; 31061544Seschrock } 31071544Seschrock } 31081544Seschrock 31091544Seschrock /* 31101544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 31111544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 31122676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 31131544Seschrock * _not_ copied as part of the process. So we point the start of our 31141544Seschrock * array appropriate and decrement the total number of elements. 31151544Seschrock */ 31162676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 31172676Seschrock zc.zc_nvlist_dst_size; 31182676Seschrock count -= zc.zc_nvlist_dst_size; 31191544Seschrock 31201544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 31211544Seschrock 31223444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 31231544Seschrock 31241544Seschrock /* 31253444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 31261544Seschrock */ 31271544Seschrock for (i = 0; i < count; i++) { 31281544Seschrock nvlist_t *nv; 31291544Seschrock 31303700Sek110237 /* ignoring zb_blkid and zb_level for now */ 31313700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 31323700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 31331544Seschrock continue; 31341544Seschrock 31353444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 31363444Sek110237 goto nomem; 31373444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 31383444Sek110237 zb[i].zb_objset) != 0) { 31393444Sek110237 nvlist_free(nv); 31402082Seschrock goto nomem; 31413444Sek110237 } 31423444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 31433444Sek110237 zb[i].zb_object) != 0) { 31443444Sek110237 nvlist_free(nv); 31453444Sek110237 goto nomem; 31461544Seschrock } 31473444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 31483444Sek110237 nvlist_free(nv); 31493444Sek110237 goto nomem; 31503444Sek110237 } 31513444Sek110237 nvlist_free(nv); 31521544Seschrock } 31531544Seschrock 31543265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 31551544Seschrock return (0); 31562082Seschrock 31572082Seschrock nomem: 31582676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 31592082Seschrock return (no_memory(zhp->zpool_hdl)); 31601544Seschrock } 31611760Seschrock 31621760Seschrock /* 31631760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 31641760Seschrock */ 31651760Seschrock int 31665094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 31671760Seschrock { 31681760Seschrock zfs_cmd_t zc = { 0 }; 31692082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 31701760Seschrock 31711760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 31725094Slling zc.zc_cookie = new_version; 31735094Slling 31744543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 31753237Slling return (zpool_standard_error_fmt(hdl, errno, 31762082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 31772082Seschrock zhp->zpool_name)); 31781760Seschrock return (0); 31791760Seschrock } 31802926Sek110237 31814988Sek110237 void 31824988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 31834988Sek110237 char *history_str) 31844988Sek110237 { 31854988Sek110237 int i; 31864988Sek110237 31874988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 31884988Sek110237 for (i = 1; i < argc; i++) { 31894988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 31904988Sek110237 HIS_MAX_RECORD_LEN) 31914988Sek110237 break; 31924988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 31934988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 31944988Sek110237 } 31954988Sek110237 } 31964988Sek110237 31972926Sek110237 /* 31984988Sek110237 * Stage command history for logging. 31992926Sek110237 */ 32004988Sek110237 int 32014988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 32022926Sek110237 { 32034988Sek110237 if (history_str == NULL) 32044988Sek110237 return (EINVAL); 32054988Sek110237 32064988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 32074988Sek110237 return (EINVAL); 32082926Sek110237 32094715Sek110237 if (hdl->libzfs_log_str != NULL) 32104543Smarks free(hdl->libzfs_log_str); 32112926Sek110237 32124988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 32134988Sek110237 return (no_memory(hdl)); 32144543Smarks 32154988Sek110237 return (0); 32162926Sek110237 } 32172926Sek110237 32182926Sek110237 /* 32192926Sek110237 * Perform ioctl to get some command history of a pool. 32202926Sek110237 * 32212926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 32222926Sek110237 * logical offset of the history buffer to start reading from. 32232926Sek110237 * 32242926Sek110237 * Upon return, 'off' is the next logical offset to read from and 32252926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 32262926Sek110237 */ 32272926Sek110237 static int 32282926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 32292926Sek110237 { 32302926Sek110237 zfs_cmd_t zc = { 0 }; 32312926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 32322926Sek110237 32332926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 32342926Sek110237 32352926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 32362926Sek110237 zc.zc_history_len = *len; 32372926Sek110237 zc.zc_history_offset = *off; 32382926Sek110237 32392926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 32402926Sek110237 switch (errno) { 32412926Sek110237 case EPERM: 32423237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 32433237Slling dgettext(TEXT_DOMAIN, 32442926Sek110237 "cannot show history for pool '%s'"), 32452926Sek110237 zhp->zpool_name)); 32462926Sek110237 case ENOENT: 32473237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 32482926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 32492926Sek110237 "'%s'"), zhp->zpool_name)); 32503863Sek110237 case ENOTSUP: 32513863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 32523863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 32533863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 32542926Sek110237 default: 32553237Slling return (zpool_standard_error_fmt(hdl, errno, 32562926Sek110237 dgettext(TEXT_DOMAIN, 32572926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 32582926Sek110237 } 32592926Sek110237 } 32602926Sek110237 32612926Sek110237 *len = zc.zc_history_len; 32622926Sek110237 *off = zc.zc_history_offset; 32632926Sek110237 32642926Sek110237 return (0); 32652926Sek110237 } 32662926Sek110237 32672926Sek110237 /* 32682926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 32692926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 32702926Sek110237 * processed as there wasn't a complete record. 32712926Sek110237 */ 327210685SGeorge.Wilson@Sun.COM int 32732926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 32742926Sek110237 nvlist_t ***records, uint_t *numrecords) 32752926Sek110237 { 32762926Sek110237 uint64_t reclen; 32772926Sek110237 nvlist_t *nv; 32782926Sek110237 int i; 32792926Sek110237 32802926Sek110237 while (bytes_read > sizeof (reclen)) { 32812926Sek110237 32822926Sek110237 /* get length of packed record (stored as little endian) */ 32832926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 32842926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 32852926Sek110237 32862926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 32872926Sek110237 break; 32882926Sek110237 32892926Sek110237 /* unpack record */ 32902926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 32912926Sek110237 return (ENOMEM); 32922926Sek110237 bytes_read -= sizeof (reclen) + reclen; 32932926Sek110237 buf += sizeof (reclen) + reclen; 32942926Sek110237 32952926Sek110237 /* add record to nvlist array */ 32962926Sek110237 (*numrecords)++; 32972926Sek110237 if (ISP2(*numrecords + 1)) { 32982926Sek110237 *records = realloc(*records, 32992926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 33002926Sek110237 } 33012926Sek110237 (*records)[*numrecords - 1] = nv; 33022926Sek110237 } 33032926Sek110237 33042926Sek110237 *leftover = bytes_read; 33052926Sek110237 return (0); 33062926Sek110237 } 33072926Sek110237 33082926Sek110237 #define HIS_BUF_LEN (128*1024) 33092926Sek110237 33102926Sek110237 /* 33112926Sek110237 * Retrieve the command history of a pool. 33122926Sek110237 */ 33132926Sek110237 int 33142926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 33152926Sek110237 { 33162926Sek110237 char buf[HIS_BUF_LEN]; 33172926Sek110237 uint64_t off = 0; 33182926Sek110237 nvlist_t **records = NULL; 33192926Sek110237 uint_t numrecords = 0; 33202926Sek110237 int err, i; 33212926Sek110237 33222926Sek110237 do { 33232926Sek110237 uint64_t bytes_read = sizeof (buf); 33242926Sek110237 uint64_t leftover; 33252926Sek110237 33262926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 33272926Sek110237 break; 33282926Sek110237 33292926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 33302926Sek110237 if (!bytes_read) 33312926Sek110237 break; 33322926Sek110237 33332926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 33342926Sek110237 &leftover, &records, &numrecords)) != 0) 33352926Sek110237 break; 33362926Sek110237 off -= leftover; 33372926Sek110237 33382926Sek110237 /* CONSTCOND */ 33392926Sek110237 } while (1); 33402926Sek110237 33412926Sek110237 if (!err) { 33422926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 33432926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 33442926Sek110237 records, numrecords) == 0); 33452926Sek110237 } 33462926Sek110237 for (i = 0; i < numrecords; i++) 33472926Sek110237 nvlist_free(records[i]); 33482926Sek110237 free(records); 33492926Sek110237 33502926Sek110237 return (err); 33512926Sek110237 } 33523444Sek110237 33533444Sek110237 void 33543444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 33553444Sek110237 char *pathname, size_t len) 33563444Sek110237 { 33573444Sek110237 zfs_cmd_t zc = { 0 }; 33583444Sek110237 boolean_t mounted = B_FALSE; 33593444Sek110237 char *mntpnt = NULL; 33603444Sek110237 char dsname[MAXNAMELEN]; 33613444Sek110237 33623444Sek110237 if (dsobj == 0) { 33633444Sek110237 /* special case for the MOS */ 33643444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 33653444Sek110237 return; 33663444Sek110237 } 33673444Sek110237 33683444Sek110237 /* get the dataset's name */ 33693444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 33703444Sek110237 zc.zc_obj = dsobj; 33713444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 33723444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 33733444Sek110237 /* just write out a path of two object numbers */ 33743444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 33753444Sek110237 dsobj, obj); 33763444Sek110237 return; 33773444Sek110237 } 33783444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 33793444Sek110237 33803444Sek110237 /* find out if the dataset is mounted */ 33813444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 33823444Sek110237 33833444Sek110237 /* get the corrupted object's path */ 33843444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 33853444Sek110237 zc.zc_obj = obj; 33863444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 33873444Sek110237 &zc) == 0) { 33883444Sek110237 if (mounted) { 33893444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 33903444Sek110237 zc.zc_value); 33913444Sek110237 } else { 33923444Sek110237 (void) snprintf(pathname, len, "%s:%s", 33933444Sek110237 dsname, zc.zc_value); 33943444Sek110237 } 33953444Sek110237 } else { 33963444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 33973444Sek110237 } 33983444Sek110237 free(mntpnt); 33993444Sek110237 } 34003912Slling 34014276Staylor /* 34027042Sgw25295 * Read the EFI label from the config, if a label does not exist then 34037042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 34047042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 34057042Sgw25295 * partition. 34067042Sgw25295 */ 34077042Sgw25295 static int 34087042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 34097042Sgw25295 { 34107042Sgw25295 char *path; 34117042Sgw25295 int fd; 34127042Sgw25295 char diskname[MAXPATHLEN]; 34137042Sgw25295 int err = -1; 34147042Sgw25295 34157042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 34167042Sgw25295 return (err); 34177042Sgw25295 34187042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 34197042Sgw25295 strrchr(path, '/')); 34207042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 34217042Sgw25295 struct dk_gpt *vtoc; 34227042Sgw25295 34237042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 34247042Sgw25295 if (sb != NULL) 34257042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 34267042Sgw25295 efi_free(vtoc); 34277042Sgw25295 } 34287042Sgw25295 (void) close(fd); 34297042Sgw25295 } 34307042Sgw25295 return (err); 34317042Sgw25295 } 34327042Sgw25295 34337042Sgw25295 /* 34344276Staylor * determine where a partition starts on a disk in the current 34354276Staylor * configuration 34364276Staylor */ 34374276Staylor static diskaddr_t 34384276Staylor find_start_block(nvlist_t *config) 34394276Staylor { 34404276Staylor nvlist_t **child; 34414276Staylor uint_t c, children; 34424276Staylor diskaddr_t sb = MAXOFFSET_T; 34434276Staylor uint64_t wholedisk; 34444276Staylor 34454276Staylor if (nvlist_lookup_nvlist_array(config, 34464276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 34474276Staylor if (nvlist_lookup_uint64(config, 34484276Staylor ZPOOL_CONFIG_WHOLE_DISK, 34494276Staylor &wholedisk) != 0 || !wholedisk) { 34504276Staylor return (MAXOFFSET_T); 34514276Staylor } 34527042Sgw25295 if (read_efi_label(config, &sb) < 0) 34537042Sgw25295 sb = MAXOFFSET_T; 34544276Staylor return (sb); 34554276Staylor } 34564276Staylor 34574276Staylor for (c = 0; c < children; c++) { 34584276Staylor sb = find_start_block(child[c]); 34594276Staylor if (sb != MAXOFFSET_T) { 34604276Staylor return (sb); 34614276Staylor } 34624276Staylor } 34634276Staylor return (MAXOFFSET_T); 34644276Staylor } 34654276Staylor 34664276Staylor /* 34674276Staylor * Label an individual disk. The name provided is the short name, 34684276Staylor * stripped of any leading /dev path. 34694276Staylor */ 34704276Staylor int 34714276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 34724276Staylor { 34734276Staylor char path[MAXPATHLEN]; 34744276Staylor struct dk_gpt *vtoc; 34754276Staylor int fd; 34764276Staylor size_t resv = EFI_MIN_RESV_SIZE; 34774276Staylor uint64_t slice_size; 34784276Staylor diskaddr_t start_block; 34794276Staylor char errbuf[1024]; 34804276Staylor 34816289Smmusante /* prepare an error message just in case */ 34826289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 34836289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 34846289Smmusante 34854276Staylor if (zhp) { 34864276Staylor nvlist_t *nvroot; 34874276Staylor 34887965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 34897965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34907965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 34917965SGeorge.Wilson@Sun.COM "pools.")); 34927965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 34937965SGeorge.Wilson@Sun.COM } 34947965SGeorge.Wilson@Sun.COM 34954276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 34964276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 34974276Staylor 34984276Staylor if (zhp->zpool_start_block == 0) 34994276Staylor start_block = find_start_block(nvroot); 35004276Staylor else 35014276Staylor start_block = zhp->zpool_start_block; 35024276Staylor zhp->zpool_start_block = start_block; 35034276Staylor } else { 35044276Staylor /* new pool */ 35054276Staylor start_block = NEW_START_BLOCK; 35064276Staylor } 35074276Staylor 35084276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 35094276Staylor BACKUP_SLICE); 35104276Staylor 35114276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 35124276Staylor /* 35134276Staylor * This shouldn't happen. We've long since verified that this 35144276Staylor * is a valid device. 35154276Staylor */ 35166289Smmusante zfs_error_aux(hdl, 35176289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 35184276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 35194276Staylor } 35204276Staylor 35214276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 35224276Staylor /* 35234276Staylor * The only way this can fail is if we run out of memory, or we 35244276Staylor * were unable to read the disk's capacity 35254276Staylor */ 35264276Staylor if (errno == ENOMEM) 35274276Staylor (void) no_memory(hdl); 35284276Staylor 35294276Staylor (void) close(fd); 35306289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35316289Smmusante "unable to read disk capacity"), name); 35324276Staylor 35334276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 35344276Staylor } 35354276Staylor 35364276Staylor slice_size = vtoc->efi_last_u_lba + 1; 35374276Staylor slice_size -= EFI_MIN_RESV_SIZE; 35384276Staylor if (start_block == MAXOFFSET_T) 35394276Staylor start_block = NEW_START_BLOCK; 35404276Staylor slice_size -= start_block; 35414276Staylor 35424276Staylor vtoc->efi_parts[0].p_start = start_block; 35434276Staylor vtoc->efi_parts[0].p_size = slice_size; 35444276Staylor 35454276Staylor /* 35464276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 35474276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 35484276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 35494276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 35504276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 35514276Staylor * can get, in the absence of V_OTHER. 35524276Staylor */ 35534276Staylor vtoc->efi_parts[0].p_tag = V_USR; 35544276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 35554276Staylor 35564276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 35574276Staylor vtoc->efi_parts[8].p_size = resv; 35584276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 35594276Staylor 35604276Staylor if (efi_write(fd, vtoc) != 0) { 35614276Staylor /* 35624276Staylor * Some block drivers (like pcata) may not support EFI 35634276Staylor * GPT labels. Print out a helpful error message dir- 35644276Staylor * ecting the user to manually label the disk and give 35654276Staylor * a specific slice. 35664276Staylor */ 35674276Staylor (void) close(fd); 35684276Staylor efi_free(vtoc); 35694276Staylor 35704276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35716289Smmusante "try using fdisk(1M) and then provide a specific slice")); 35724276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 35734276Staylor } 35744276Staylor 35754276Staylor (void) close(fd); 35764276Staylor efi_free(vtoc); 35774276Staylor return (0); 35784276Staylor } 35796423Sgw25295 35806423Sgw25295 static boolean_t 35816423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 35826423Sgw25295 { 35836423Sgw25295 char *type; 35846423Sgw25295 nvlist_t **child; 35856423Sgw25295 uint_t children, c; 35866423Sgw25295 35876423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 35886423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 35896423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 35906423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 359110594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 35926423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 35936423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35946423Sgw25295 "vdev type '%s' is not supported"), type); 35956423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 35966423Sgw25295 return (B_FALSE); 35976423Sgw25295 } 35986423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 35996423Sgw25295 &child, &children) == 0) { 36006423Sgw25295 for (c = 0; c < children; c++) { 36016423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 36026423Sgw25295 return (B_FALSE); 36036423Sgw25295 } 36046423Sgw25295 } 36056423Sgw25295 return (B_TRUE); 36066423Sgw25295 } 36076423Sgw25295 36086423Sgw25295 /* 36096423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 36106423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 36116423Sgw25295 */ 36126423Sgw25295 int 36136423Sgw25295 zvol_check_dump_config(char *arg) 36146423Sgw25295 { 36156423Sgw25295 zpool_handle_t *zhp = NULL; 36166423Sgw25295 nvlist_t *config, *nvroot; 36176423Sgw25295 char *p, *volname; 36186423Sgw25295 nvlist_t **top; 36196423Sgw25295 uint_t toplevels; 36206423Sgw25295 libzfs_handle_t *hdl; 36216423Sgw25295 char errbuf[1024]; 36226423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 36236423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 36246423Sgw25295 int ret = 1; 36256423Sgw25295 36266423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 36276423Sgw25295 return (-1); 36286423Sgw25295 } 36296423Sgw25295 36306423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 36316423Sgw25295 "dump is not supported on device '%s'"), arg); 36326423Sgw25295 36336423Sgw25295 if ((hdl = libzfs_init()) == NULL) 36346423Sgw25295 return (1); 36356423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 36366423Sgw25295 36376423Sgw25295 volname = arg + pathlen; 36386423Sgw25295 36396423Sgw25295 /* check the configuration of the pool */ 36406423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 36416423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36426423Sgw25295 "malformed dataset name")); 36436423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 36446423Sgw25295 return (1); 36456423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 36466423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36476423Sgw25295 "dataset name is too long")); 36486423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 36496423Sgw25295 return (1); 36506423Sgw25295 } else { 36516423Sgw25295 (void) strncpy(poolname, volname, p - volname); 36526423Sgw25295 poolname[p - volname] = '\0'; 36536423Sgw25295 } 36546423Sgw25295 36556423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 36566423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36576423Sgw25295 "could not open pool '%s'"), poolname); 36586423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 36596423Sgw25295 goto out; 36606423Sgw25295 } 36616423Sgw25295 config = zpool_get_config(zhp, NULL); 36626423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 36636423Sgw25295 &nvroot) != 0) { 36646423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36656423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 36666423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 36676423Sgw25295 goto out; 36686423Sgw25295 } 36696423Sgw25295 36706423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 36716423Sgw25295 &top, &toplevels) == 0); 36726423Sgw25295 if (toplevels != 1) { 36736423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36746423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 36756423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 36766423Sgw25295 goto out; 36776423Sgw25295 } 36786423Sgw25295 36796423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 36806423Sgw25295 goto out; 36816423Sgw25295 } 36826423Sgw25295 ret = 0; 36836423Sgw25295 36846423Sgw25295 out: 36856423Sgw25295 if (zhp) 36866423Sgw25295 zpool_close(zhp); 36876423Sgw25295 libzfs_fini(hdl); 36886423Sgw25295 return (ret); 36896423Sgw25295 } 3690