1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 238525SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #include <ctype.h> 28789Sahrens #include <errno.h> 29789Sahrens #include <devid.h> 30789Sahrens #include <fcntl.h> 31789Sahrens #include <libintl.h> 32789Sahrens #include <stdio.h> 33789Sahrens #include <stdlib.h> 343126Sahl #include <strings.h> 35789Sahrens #include <unistd.h> 364276Staylor #include <sys/efi_partition.h> 374276Staylor #include <sys/vtoc.h> 38789Sahrens #include <sys/zfs_ioctl.h> 399816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 40789Sahrens 41789Sahrens #include "zfs_namecheck.h" 423912Slling #include "zfs_prop.h" 43789Sahrens #include "libzfs_impl.h" 44*10921STim.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", 8710685SGeorge.Wilson@Sun.COM }; 8810685SGeorge.Wilson@Sun.COM 897042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 905094Slling 917965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 927965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 937965SGeorge.Wilson@Sun.COM #else 947965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 957965SGeorge.Wilson@Sun.COM #endif 967965SGeorge.Wilson@Sun.COM 979816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 989816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 999816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 1009816SGeorge.Wilson@Sun.COM 1015094Slling /* 1025094Slling * ==================================================================== 1035094Slling * zpool property functions 1045094Slling * ==================================================================== 1055094Slling */ 1065094Slling 1075094Slling static int 1085094Slling zpool_get_all_props(zpool_handle_t *zhp) 1095094Slling { 1105094Slling zfs_cmd_t zc = { 0 }; 1115094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 1125094Slling 1135094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1145094Slling 1155094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 1165094Slling return (-1); 1175094Slling 1185094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 1195094Slling if (errno == ENOMEM) { 1205094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 1215094Slling zcmd_free_nvlists(&zc); 1225094Slling return (-1); 1235094Slling } 1245094Slling } else { 1255094Slling zcmd_free_nvlists(&zc); 1265094Slling return (-1); 1275094Slling } 1285094Slling } 1295094Slling 1305094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 1315094Slling zcmd_free_nvlists(&zc); 1325094Slling return (-1); 1335094Slling } 1345094Slling 1355094Slling zcmd_free_nvlists(&zc); 1365094Slling 1375094Slling return (0); 1385094Slling } 1395094Slling 1405094Slling static int 1415094Slling zpool_props_refresh(zpool_handle_t *zhp) 1425094Slling { 1435094Slling nvlist_t *old_props; 1445094Slling 1455094Slling old_props = zhp->zpool_props; 1465094Slling 1475094Slling if (zpool_get_all_props(zhp) != 0) 1485094Slling return (-1); 1495094Slling 1505094Slling nvlist_free(old_props); 1515094Slling return (0); 1525094Slling } 1535094Slling 1545094Slling static char * 1555094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1565094Slling zprop_source_t *src) 1575094Slling { 1585094Slling nvlist_t *nv, *nvl; 1595094Slling uint64_t ival; 1605094Slling char *value; 1615094Slling zprop_source_t source; 1625094Slling 1635094Slling nvl = zhp->zpool_props; 1645094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1655094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1665094Slling source = ival; 1675094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1685094Slling } else { 1695094Slling source = ZPROP_SRC_DEFAULT; 1705094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1715094Slling value = "-"; 1725094Slling } 1735094Slling 1745094Slling if (src) 1755094Slling *src = source; 1765094Slling 1775094Slling return (value); 1785094Slling } 1795094Slling 1805094Slling uint64_t 1815094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1825094Slling { 1835094Slling nvlist_t *nv, *nvl; 1845094Slling uint64_t value; 1855094Slling zprop_source_t source; 1865094Slling 1877294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1887294Sperrin /* 1897294Sperrin * zpool_get_all_props() has most likely failed because 1907294Sperrin * the pool is faulted, but if all we need is the top level 1917294Sperrin * vdev's guid then get it from the zhp config nvlist. 1927294Sperrin */ 1937294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1947294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1957294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1967294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1977294Sperrin == 0)) { 1987294Sperrin return (value); 1997294Sperrin } 2005094Slling return (zpool_prop_default_numeric(prop)); 2017294Sperrin } 2025094Slling 2035094Slling nvl = zhp->zpool_props; 2045094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 2055094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 2065094Slling source = value; 2075094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 2085094Slling } else { 2095094Slling source = ZPROP_SRC_DEFAULT; 2105094Slling value = zpool_prop_default_numeric(prop); 2115094Slling } 2125094Slling 2135094Slling if (src) 2145094Slling *src = source; 2155094Slling 2165094Slling return (value); 2175094Slling } 2185094Slling 2195094Slling /* 2205094Slling * Map VDEV STATE to printed strings. 2215094Slling */ 2225094Slling char * 2235094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 2245094Slling { 2255094Slling switch (state) { 2265094Slling case VDEV_STATE_CLOSED: 2275094Slling case VDEV_STATE_OFFLINE: 2285094Slling return (gettext("OFFLINE")); 2295094Slling case VDEV_STATE_REMOVED: 2305094Slling return (gettext("REMOVED")); 2315094Slling case VDEV_STATE_CANT_OPEN: 2327294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 2335094Slling return (gettext("FAULTED")); 2345094Slling else 2355094Slling return (gettext("UNAVAIL")); 2365094Slling case VDEV_STATE_FAULTED: 2375094Slling return (gettext("FAULTED")); 2385094Slling case VDEV_STATE_DEGRADED: 2395094Slling return (gettext("DEGRADED")); 2405094Slling case VDEV_STATE_HEALTHY: 2415094Slling return (gettext("ONLINE")); 2425094Slling } 2435094Slling 2445094Slling return (gettext("UNKNOWN")); 2455094Slling } 2465094Slling 2475094Slling /* 2485094Slling * Get a zpool property value for 'prop' and return the value in 2495094Slling * a pre-allocated buffer. 2505094Slling */ 2515094Slling int 2525094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2535094Slling zprop_source_t *srctype) 2545094Slling { 2555094Slling uint64_t intval; 2565094Slling const char *strval; 2575094Slling zprop_source_t src = ZPROP_SRC_NONE; 2585094Slling nvlist_t *nvroot; 2595094Slling vdev_stat_t *vs; 2605094Slling uint_t vsc; 2615094Slling 2625094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2638525SEric.Schrock@Sun.COM switch (prop) { 2648525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2655094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2668525SEric.Schrock@Sun.COM break; 2678525SEric.Schrock@Sun.COM 2688525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2695094Slling (void) strlcpy(buf, "FAULTED", len); 2708525SEric.Schrock@Sun.COM break; 2718525SEric.Schrock@Sun.COM 2728525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2738525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2748525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2758525SEric.Schrock@Sun.COM break; 2768525SEric.Schrock@Sun.COM 2778525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2788525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2798525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2808525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2818525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2828525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2838525SEric.Schrock@Sun.COM len); 2848525SEric.Schrock@Sun.COM if (srctype != NULL) 2858525SEric.Schrock@Sun.COM *srctype = src; 2868525SEric.Schrock@Sun.COM return (0); 2878525SEric.Schrock@Sun.COM } 2888525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2898525SEric.Schrock@Sun.COM default: 2905094Slling (void) strlcpy(buf, "-", len); 2918525SEric.Schrock@Sun.COM break; 2928525SEric.Schrock@Sun.COM } 2938525SEric.Schrock@Sun.COM 2948525SEric.Schrock@Sun.COM if (srctype != NULL) 2958525SEric.Schrock@Sun.COM *srctype = src; 2965094Slling return (0); 2975094Slling } 2985094Slling 2995094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 3005094Slling prop != ZPOOL_PROP_NAME) 3015094Slling return (-1); 3025094Slling 3035094Slling switch (zpool_prop_get_type(prop)) { 3045094Slling case PROP_TYPE_STRING: 3055094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 3065094Slling len); 3075094Slling break; 3085094Slling 3095094Slling case PROP_TYPE_NUMBER: 3105094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3115094Slling 3125094Slling switch (prop) { 3135094Slling case ZPOOL_PROP_SIZE: 3145094Slling case ZPOOL_PROP_USED: 3155094Slling case ZPOOL_PROP_AVAILABLE: 3165094Slling (void) zfs_nicenum(intval, buf, len); 3175094Slling break; 3185094Slling 3195094Slling case ZPOOL_PROP_CAPACITY: 3205094Slling (void) snprintf(buf, len, "%llu%%", 3215094Slling (u_longlong_t)intval); 3225094Slling break; 3235094Slling 3245094Slling case ZPOOL_PROP_HEALTH: 3255094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 3265094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 3275094Slling verify(nvlist_lookup_uint64_array(nvroot, 3285094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 3295094Slling 3305094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 3315094Slling vs->vs_aux), len); 3325094Slling break; 3335094Slling default: 3345094Slling (void) snprintf(buf, len, "%llu", intval); 3355094Slling } 3365094Slling break; 3375094Slling 3385094Slling case PROP_TYPE_INDEX: 3395094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3405094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3415094Slling != 0) 3425094Slling return (-1); 3435094Slling (void) strlcpy(buf, strval, len); 3445094Slling break; 3455094Slling 3465094Slling default: 3475094Slling abort(); 3485094Slling } 3495094Slling 3505094Slling if (srctype) 3515094Slling *srctype = src; 3525094Slling 3535094Slling return (0); 3545094Slling } 3555094Slling 3565094Slling /* 3575094Slling * Check if the bootfs name has the same pool name as it is set to. 3585094Slling * Assuming bootfs is a valid dataset name. 3595094Slling */ 3605094Slling static boolean_t 3615094Slling bootfs_name_valid(const char *pool, char *bootfs) 3625094Slling { 3635094Slling int len = strlen(pool); 3645094Slling 3657300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3665094Slling return (B_FALSE); 3675094Slling 3685094Slling if (strncmp(pool, bootfs, len) == 0 && 3695094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3705094Slling return (B_TRUE); 3715094Slling 3725094Slling return (B_FALSE); 3735094Slling } 3745094Slling 3755094Slling /* 3767042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3777042Sgw25295 * an EFI label. 3787042Sgw25295 */ 3797042Sgw25295 static boolean_t 3807042Sgw25295 pool_uses_efi(nvlist_t *config) 3817042Sgw25295 { 3827042Sgw25295 nvlist_t **child; 3837042Sgw25295 uint_t c, children; 3847042Sgw25295 3857042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3867042Sgw25295 &child, &children) != 0) 3877042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3887042Sgw25295 3897042Sgw25295 for (c = 0; c < children; c++) { 3907042Sgw25295 if (pool_uses_efi(child[c])) 3917042Sgw25295 return (B_TRUE); 3927042Sgw25295 } 3937042Sgw25295 return (B_FALSE); 3947042Sgw25295 } 3957042Sgw25295 3967965SGeorge.Wilson@Sun.COM static boolean_t 3977965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3987965SGeorge.Wilson@Sun.COM { 3997965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 4007965SGeorge.Wilson@Sun.COM 4017965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 4027965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 4037965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 4047965SGeorge.Wilson@Sun.COM } 4057965SGeorge.Wilson@Sun.COM 4067965SGeorge.Wilson@Sun.COM 4077042Sgw25295 /* 4085094Slling * Given an nvlist of zpool properties to be set, validate that they are 4095094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 4105094Slling * specified as strings. 4115094Slling */ 4125094Slling static nvlist_t * 4137184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 4145094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 4155094Slling { 4165094Slling nvpair_t *elem; 4175094Slling nvlist_t *retprops; 4185094Slling zpool_prop_t prop; 4195094Slling char *strval; 4205094Slling uint64_t intval; 4215363Seschrock char *slash; 4225363Seschrock struct stat64 statbuf; 4237042Sgw25295 zpool_handle_t *zhp; 4247042Sgw25295 nvlist_t *nvroot; 4255094Slling 4265094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 4275094Slling (void) no_memory(hdl); 4285094Slling return (NULL); 4295094Slling } 4305094Slling 4315094Slling elem = NULL; 4325094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 4335094Slling const char *propname = nvpair_name(elem); 4345094Slling 4355094Slling /* 4365094Slling * Make sure this property is valid and applies to this type. 4375094Slling */ 4385094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4395094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4405094Slling "invalid property '%s'"), propname); 4415094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4425094Slling goto error; 4435094Slling } 4445094Slling 4455094Slling if (zpool_prop_readonly(prop)) { 4465094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4475094Slling "is readonly"), propname); 4485094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4495094Slling goto error; 4505094Slling } 4515094Slling 4525094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4535094Slling &strval, &intval, errbuf) != 0) 4545094Slling goto error; 4555094Slling 4565094Slling /* 4575094Slling * Perform additional checking for specific properties. 4585094Slling */ 4595094Slling switch (prop) { 4605094Slling case ZPOOL_PROP_VERSION: 4615094Slling if (intval < version || intval > SPA_VERSION) { 4625094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4635094Slling "property '%s' number %d is invalid."), 4645094Slling propname, intval); 4655094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4665094Slling goto error; 4675094Slling } 4685094Slling break; 4695094Slling 4705094Slling case ZPOOL_PROP_BOOTFS: 4715094Slling if (create_or_import) { 4725094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4735094Slling "property '%s' cannot be set at creation " 4745094Slling "or import time"), propname); 4755094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4765094Slling goto error; 4775094Slling } 4785094Slling 4795094Slling if (version < SPA_VERSION_BOOTFS) { 4805094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4815094Slling "pool must be upgraded to support " 4825094Slling "'%s' property"), propname); 4835094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4845094Slling goto error; 4855094Slling } 4865094Slling 4875094Slling /* 4885094Slling * bootfs property value has to be a dataset name and 4895094Slling * the dataset has to be in the same pool as it sets to. 4905094Slling */ 4915094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4925094Slling strval)) { 4935094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4945094Slling "is an invalid name"), strval); 4955094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4965094Slling goto error; 4975094Slling } 4987042Sgw25295 4997042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 5007042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5017042Sgw25295 "could not open pool '%s'"), poolname); 5027042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 5037042Sgw25295 goto error; 5047042Sgw25295 } 5057042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 5067042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 5077042Sgw25295 5087042Sgw25295 /* 5097042Sgw25295 * bootfs property cannot be set on a disk which has 5107042Sgw25295 * been EFI labeled. 5117042Sgw25295 */ 5127042Sgw25295 if (pool_uses_efi(nvroot)) { 5137042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5147042Sgw25295 "property '%s' not supported on " 5157042Sgw25295 "EFI labeled devices"), propname); 5167042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 5177042Sgw25295 zpool_close(zhp); 5187042Sgw25295 goto error; 5197042Sgw25295 } 5207042Sgw25295 zpool_close(zhp); 5215094Slling break; 5225094Slling 5235094Slling case ZPOOL_PROP_ALTROOT: 5245094Slling if (!create_or_import) { 5255094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5265094Slling "property '%s' can only be set during pool " 5275094Slling "creation or import"), propname); 5285094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 5295094Slling goto error; 5305094Slling } 5315094Slling 5325094Slling if (strval[0] != '/') { 5335094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5345094Slling "bad alternate root '%s'"), strval); 5355094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5365094Slling goto error; 5375094Slling } 5385094Slling break; 5395363Seschrock 5405363Seschrock case ZPOOL_PROP_CACHEFILE: 5415363Seschrock if (strval[0] == '\0') 5425363Seschrock break; 5435363Seschrock 5445363Seschrock if (strcmp(strval, "none") == 0) 5455363Seschrock break; 5465363Seschrock 5475363Seschrock if (strval[0] != '/') { 5485363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5495363Seschrock "property '%s' must be empty, an " 5505363Seschrock "absolute path, or 'none'"), propname); 5515363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5525363Seschrock goto error; 5535363Seschrock } 5545363Seschrock 5555363Seschrock slash = strrchr(strval, '/'); 5565363Seschrock 5575363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5585363Seschrock strcmp(slash, "/..") == 0) { 5595363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5605363Seschrock "'%s' is not a valid file"), strval); 5615363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5625363Seschrock goto error; 5635363Seschrock } 5645363Seschrock 5655363Seschrock *slash = '\0'; 5665363Seschrock 5675621Seschrock if (strval[0] != '\0' && 5685621Seschrock (stat64(strval, &statbuf) != 0 || 5695621Seschrock !S_ISDIR(statbuf.st_mode))) { 5705363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5715363Seschrock "'%s' is not a valid directory"), 5725363Seschrock strval); 5735363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5745363Seschrock goto error; 5755363Seschrock } 5765363Seschrock 5775363Seschrock *slash = '/'; 5785363Seschrock break; 5795094Slling } 5805094Slling } 5815094Slling 5825094Slling return (retprops); 5835094Slling error: 5845094Slling nvlist_free(retprops); 5855094Slling return (NULL); 5865094Slling } 5875094Slling 5885094Slling /* 5895094Slling * Set zpool property : propname=propval. 5905094Slling */ 5915094Slling int 5925094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5935094Slling { 5945094Slling zfs_cmd_t zc = { 0 }; 5955094Slling int ret = -1; 5965094Slling char errbuf[1024]; 5975094Slling nvlist_t *nvl = NULL; 5985094Slling nvlist_t *realprops; 5995094Slling uint64_t version; 6005094Slling 6015094Slling (void) snprintf(errbuf, sizeof (errbuf), 6025094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 6035094Slling zhp->zpool_name); 6045094Slling 6055094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 6065094Slling return (no_memory(zhp->zpool_hdl)); 6075094Slling 6085094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 6095094Slling nvlist_free(nvl); 6105094Slling return (no_memory(zhp->zpool_hdl)); 6115094Slling } 6125094Slling 6135094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 6147184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 6155094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 6165094Slling nvlist_free(nvl); 6175094Slling return (-1); 6185094Slling } 6195094Slling 6205094Slling nvlist_free(nvl); 6215094Slling nvl = realprops; 6225094Slling 6235094Slling /* 6245094Slling * Execute the corresponding ioctl() to set this property. 6255094Slling */ 6265094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 6275094Slling 6285094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 6295094Slling nvlist_free(nvl); 6305094Slling return (-1); 6315094Slling } 6325094Slling 6335094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 6345094Slling 6355094Slling zcmd_free_nvlists(&zc); 6365094Slling nvlist_free(nvl); 6375094Slling 6385094Slling if (ret) 6395094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6405094Slling else 6415094Slling (void) zpool_props_refresh(zhp); 6425094Slling 6435094Slling return (ret); 6445094Slling } 6455094Slling 6465094Slling int 6475094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6485094Slling { 6495094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6505094Slling zprop_list_t *entry; 6515094Slling char buf[ZFS_MAXPROPLEN]; 6525094Slling 6535094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6545094Slling return (-1); 6555094Slling 6565094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6575094Slling 6585094Slling if (entry->pl_fixed) 6595094Slling continue; 6605094Slling 6615094Slling if (entry->pl_prop != ZPROP_INVAL && 6625094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6635094Slling NULL) == 0) { 6645094Slling if (strlen(buf) > entry->pl_width) 6655094Slling entry->pl_width = strlen(buf); 6665094Slling } 6675094Slling } 6685094Slling 6695094Slling return (0); 6705094Slling } 6715094Slling 6725094Slling 673789Sahrens /* 6749816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6759816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6769816SGeorge.Wilson@Sun.COM */ 6779816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6789816SGeorge.Wilson@Sun.COM 6799816SGeorge.Wilson@Sun.COM /* 680789Sahrens * Validate the given pool name, optionally putting an extended error message in 681789Sahrens * 'buf'. 682789Sahrens */ 6836423Sgw25295 boolean_t 6842082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 685789Sahrens { 686789Sahrens namecheck_err_t why; 687789Sahrens char what; 6881773Seschrock int ret; 689789Sahrens 6901773Seschrock ret = pool_namecheck(pool, &why, &what); 6911773Seschrock 6921773Seschrock /* 6931773Seschrock * The rules for reserved pool names were extended at a later point. 6941773Seschrock * But we need to support users with existing pools that may now be 6951773Seschrock * invalid. So we only check for this expanded set of names during a 6961773Seschrock * create (or import), and only in userland. 6971773Seschrock */ 6981773Seschrock if (ret == 0 && !isopen && 6991773Seschrock (strncmp(pool, "mirror", 6) == 0 || 7001773Seschrock strncmp(pool, "raidz", 5) == 0 || 7014527Sperrin strncmp(pool, "spare", 5) == 0 || 7024527Sperrin strcmp(pool, "log") == 0)) { 7036423Sgw25295 if (hdl != NULL) 7046423Sgw25295 zfs_error_aux(hdl, 7056423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 7062082Seschrock return (B_FALSE); 7071773Seschrock } 7081773Seschrock 7091773Seschrock 7101773Seschrock if (ret != 0) { 7112082Seschrock if (hdl != NULL) { 712789Sahrens switch (why) { 7131003Slling case NAME_ERR_TOOLONG: 7142082Seschrock zfs_error_aux(hdl, 7151003Slling dgettext(TEXT_DOMAIN, "name is too long")); 7161003Slling break; 7171003Slling 718789Sahrens case NAME_ERR_INVALCHAR: 7192082Seschrock zfs_error_aux(hdl, 720789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 721789Sahrens "'%c' in pool name"), what); 722789Sahrens break; 723789Sahrens 724789Sahrens case NAME_ERR_NOLETTER: 7252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7262082Seschrock "name must begin with a letter")); 727789Sahrens break; 728789Sahrens 729789Sahrens case NAME_ERR_RESERVED: 7302082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7312082Seschrock "name is reserved")); 732789Sahrens break; 733789Sahrens 734789Sahrens case NAME_ERR_DISKLIKE: 7352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7362082Seschrock "pool name is reserved")); 737789Sahrens break; 7382856Snd150628 7392856Snd150628 case NAME_ERR_LEADING_SLASH: 7402856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7412856Snd150628 "leading slash in name")); 7422856Snd150628 break; 7432856Snd150628 7442856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7452856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7462856Snd150628 "empty component in name")); 7472856Snd150628 break; 7482856Snd150628 7492856Snd150628 case NAME_ERR_TRAILING_SLASH: 7502856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7512856Snd150628 "trailing slash in name")); 7522856Snd150628 break; 7532856Snd150628 7542856Snd150628 case NAME_ERR_MULTIPLE_AT: 7552856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7562856Snd150628 "multiple '@' delimiters in name")); 7572856Snd150628 break; 7582856Snd150628 759789Sahrens } 760789Sahrens } 7612082Seschrock return (B_FALSE); 762789Sahrens } 763789Sahrens 7642082Seschrock return (B_TRUE); 765789Sahrens } 766789Sahrens 767789Sahrens /* 768789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 769789Sahrens * state. 770789Sahrens */ 771789Sahrens zpool_handle_t * 7722082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 773789Sahrens { 774789Sahrens zpool_handle_t *zhp; 7752142Seschrock boolean_t missing; 776789Sahrens 777789Sahrens /* 778789Sahrens * Make sure the pool name is valid. 779789Sahrens */ 7802082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7813237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7822082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7832082Seschrock pool); 784789Sahrens return (NULL); 785789Sahrens } 786789Sahrens 7872082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7882082Seschrock return (NULL); 789789Sahrens 7902082Seschrock zhp->zpool_hdl = hdl; 791789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 792789Sahrens 7932142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7942142Seschrock zpool_close(zhp); 7952142Seschrock return (NULL); 7962142Seschrock } 7972142Seschrock 7982142Seschrock if (missing) { 7995094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 8003237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 8015094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 8022142Seschrock zpool_close(zhp); 8032142Seschrock return (NULL); 804789Sahrens } 805789Sahrens 806789Sahrens return (zhp); 807789Sahrens } 808789Sahrens 809789Sahrens /* 810789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 811789Sahrens * the configuration cache may be out of date). 812789Sahrens */ 8132142Seschrock int 8142142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 815789Sahrens { 816789Sahrens zpool_handle_t *zhp; 8172142Seschrock boolean_t missing; 818789Sahrens 8192142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 8202142Seschrock return (-1); 821789Sahrens 8222082Seschrock zhp->zpool_hdl = hdl; 823789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 824789Sahrens 8252142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 8262142Seschrock zpool_close(zhp); 8272142Seschrock return (-1); 828789Sahrens } 829789Sahrens 8302142Seschrock if (missing) { 8312142Seschrock zpool_close(zhp); 8322142Seschrock *ret = NULL; 8332142Seschrock return (0); 8342142Seschrock } 8352142Seschrock 8362142Seschrock *ret = zhp; 8372142Seschrock return (0); 838789Sahrens } 839789Sahrens 840789Sahrens /* 841789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 842789Sahrens * state. 843789Sahrens */ 844789Sahrens zpool_handle_t * 8452082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 846789Sahrens { 847789Sahrens zpool_handle_t *zhp; 848789Sahrens 8492082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 850789Sahrens return (NULL); 851789Sahrens 852789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8533237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8542082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 855789Sahrens zpool_close(zhp); 856789Sahrens return (NULL); 857789Sahrens } 858789Sahrens 859789Sahrens return (zhp); 860789Sahrens } 861789Sahrens 862789Sahrens /* 863789Sahrens * Close the handle. Simply frees the memory associated with the handle. 864789Sahrens */ 865789Sahrens void 866789Sahrens zpool_close(zpool_handle_t *zhp) 867789Sahrens { 868789Sahrens if (zhp->zpool_config) 869789Sahrens nvlist_free(zhp->zpool_config); 870952Seschrock if (zhp->zpool_old_config) 871952Seschrock nvlist_free(zhp->zpool_old_config); 8723912Slling if (zhp->zpool_props) 8733912Slling nvlist_free(zhp->zpool_props); 874789Sahrens free(zhp); 875789Sahrens } 876789Sahrens 877789Sahrens /* 878789Sahrens * Return the name of the pool. 879789Sahrens */ 880789Sahrens const char * 881789Sahrens zpool_get_name(zpool_handle_t *zhp) 882789Sahrens { 883789Sahrens return (zhp->zpool_name); 884789Sahrens } 885789Sahrens 886789Sahrens 887789Sahrens /* 888789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 889789Sahrens */ 890789Sahrens int 891789Sahrens zpool_get_state(zpool_handle_t *zhp) 892789Sahrens { 893789Sahrens return (zhp->zpool_state); 894789Sahrens } 895789Sahrens 896789Sahrens /* 897789Sahrens * Create the named pool, using the provided vdev list. It is assumed 898789Sahrens * that the consumer has already validated the contents of the nvlist, so we 899789Sahrens * don't have to worry about error semantics. 900789Sahrens */ 901789Sahrens int 9022082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 9037184Stimh nvlist_t *props, nvlist_t *fsprops) 904789Sahrens { 905789Sahrens zfs_cmd_t zc = { 0 }; 9067184Stimh nvlist_t *zc_fsprops = NULL; 9077184Stimh nvlist_t *zc_props = NULL; 9082082Seschrock char msg[1024]; 9095094Slling char *altroot; 9107184Stimh int ret = -1; 9112082Seschrock 9122082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 9132082Seschrock "cannot create '%s'"), pool); 914789Sahrens 9152082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 9162082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 9172082Seschrock 9185320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 9195320Slling return (-1); 9205320Slling 9217184Stimh if (props) { 9227184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 9237184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 9247184Stimh goto create_failed; 9257184Stimh } 9265320Slling } 927789Sahrens 9287184Stimh if (fsprops) { 9297184Stimh uint64_t zoned; 9307184Stimh char *zonestr; 9317184Stimh 9327184Stimh zoned = ((nvlist_lookup_string(fsprops, 9337184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 9347184Stimh strcmp(zonestr, "on") == 0); 9357184Stimh 9367184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9377184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9387184Stimh goto create_failed; 9397184Stimh } 9407184Stimh if (!zc_props && 9417184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9427184Stimh goto create_failed; 9437184Stimh } 9447184Stimh if (nvlist_add_nvlist(zc_props, 9457184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9467184Stimh goto create_failed; 9477184Stimh } 9487184Stimh } 9497184Stimh 9507184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9517184Stimh goto create_failed; 9527184Stimh 953789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 954789Sahrens 9557184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9565320Slling 9572676Seschrock zcmd_free_nvlists(&zc); 9587184Stimh nvlist_free(zc_props); 9597184Stimh nvlist_free(zc_fsprops); 9602082Seschrock 961789Sahrens switch (errno) { 962789Sahrens case EBUSY: 963789Sahrens /* 964789Sahrens * This can happen if the user has specified the same 965789Sahrens * device multiple times. We can't reliably detect this 966789Sahrens * until we try to add it and see we already have a 967789Sahrens * label. 968789Sahrens */ 9692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9702082Seschrock "one or more vdevs refer to the same device")); 9712082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 972789Sahrens 973789Sahrens case EOVERFLOW: 974789Sahrens /* 9752082Seschrock * This occurs when one of the devices is below 976789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 977789Sahrens * device was the problem device since there's no 978789Sahrens * reliable way to determine device size from userland. 979789Sahrens */ 980789Sahrens { 981789Sahrens char buf[64]; 982789Sahrens 983789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 984789Sahrens 9852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9862082Seschrock "one or more devices is less than the " 9872082Seschrock "minimum size (%s)"), buf); 988789Sahrens } 9892082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 990789Sahrens 991789Sahrens case ENOSPC: 9922082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9932082Seschrock "one or more devices is out of space")); 9942082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 995789Sahrens 9965450Sbrendan case ENOTBLK: 9975450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9985450Sbrendan "cache device must be a disk or disk slice")); 9995450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 10005450Sbrendan 1001789Sahrens default: 10022082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1003789Sahrens } 1004789Sahrens } 1005789Sahrens 1006789Sahrens /* 1007789Sahrens * If this is an alternate root pool, then we automatically set the 10082676Seschrock * mountpoint of the root dataset to be '/'. 1009789Sahrens */ 10105094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 10115094Slling &altroot) == 0) { 1012789Sahrens zfs_handle_t *zhp; 1013789Sahrens 10145094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 10152676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 10162676Seschrock "/") == 0); 1017789Sahrens 1018789Sahrens zfs_close(zhp); 1019789Sahrens } 1020789Sahrens 10217184Stimh create_failed: 10225320Slling zcmd_free_nvlists(&zc); 10237184Stimh nvlist_free(zc_props); 10247184Stimh nvlist_free(zc_fsprops); 10257184Stimh return (ret); 1026789Sahrens } 1027789Sahrens 1028789Sahrens /* 1029789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1030789Sahrens * datasets left in the pool. 1031789Sahrens */ 1032789Sahrens int 1033789Sahrens zpool_destroy(zpool_handle_t *zhp) 1034789Sahrens { 1035789Sahrens zfs_cmd_t zc = { 0 }; 1036789Sahrens zfs_handle_t *zfp = NULL; 10372082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10382082Seschrock char msg[1024]; 1039789Sahrens 1040789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 10412082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 10422082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1043789Sahrens return (-1); 1044789Sahrens 1045789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1046789Sahrens 10474543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10482082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10492082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1050789Sahrens 10512082Seschrock if (errno == EROFS) { 10522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10532082Seschrock "one or more devices is read only")); 10542082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10552082Seschrock } else { 10562082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1057789Sahrens } 1058789Sahrens 1059789Sahrens if (zfp) 1060789Sahrens zfs_close(zfp); 1061789Sahrens return (-1); 1062789Sahrens } 1063789Sahrens 1064789Sahrens if (zfp) { 1065789Sahrens remove_mountpoint(zfp); 1066789Sahrens zfs_close(zfp); 1067789Sahrens } 1068789Sahrens 1069789Sahrens return (0); 1070789Sahrens } 1071789Sahrens 1072789Sahrens /* 1073789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1074789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1075789Sahrens */ 1076789Sahrens int 1077789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1078789Sahrens { 10792676Seschrock zfs_cmd_t zc = { 0 }; 10802082Seschrock int ret; 10812082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10822082Seschrock char msg[1024]; 10835450Sbrendan nvlist_t **spares, **l2cache; 10845450Sbrendan uint_t nspares, nl2cache; 10852082Seschrock 10862082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10872082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10882082Seschrock 10895450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10905450Sbrendan SPA_VERSION_SPARES && 10912082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10922082Seschrock &spares, &nspares) == 0) { 10932082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10942082Seschrock "upgraded to add hot spares")); 10952082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10962082Seschrock } 1097789Sahrens 10987965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10997965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 11007965SGeorge.Wilson@Sun.COM uint64_t s; 11017965SGeorge.Wilson@Sun.COM 11027965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 11037965SGeorge.Wilson@Sun.COM char *path; 11047965SGeorge.Wilson@Sun.COM 11057965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 11067965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 11077965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11087965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 11097965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 111010594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 111110594SGeorge.Wilson@Sun.COM B_FALSE)); 11127965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 11137965SGeorge.Wilson@Sun.COM } 11147965SGeorge.Wilson@Sun.COM } 11157965SGeorge.Wilson@Sun.COM } 11167965SGeorge.Wilson@Sun.COM 11175450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 11185450Sbrendan SPA_VERSION_L2CACHE && 11195450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 11205450Sbrendan &l2cache, &nl2cache) == 0) { 11215450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 11225450Sbrendan "upgraded to add cache devices")); 11235450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 11245450Sbrendan } 11255450Sbrendan 11265094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 11272082Seschrock return (-1); 1128789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1129789Sahrens 11304543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1131789Sahrens switch (errno) { 1132789Sahrens case EBUSY: 1133789Sahrens /* 1134789Sahrens * This can happen if the user has specified the same 1135789Sahrens * device multiple times. We can't reliably detect this 1136789Sahrens * until we try to add it and see we already have a 1137789Sahrens * label. 1138789Sahrens */ 11392082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11402082Seschrock "one or more vdevs refer to the same device")); 11412082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1142789Sahrens break; 1143789Sahrens 1144789Sahrens case EOVERFLOW: 1145789Sahrens /* 1146789Sahrens * This occurrs when one of the devices is below 1147789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1148789Sahrens * device was the problem device since there's no 1149789Sahrens * reliable way to determine device size from userland. 1150789Sahrens */ 1151789Sahrens { 1152789Sahrens char buf[64]; 1153789Sahrens 1154789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1155789Sahrens 11562082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11572082Seschrock "device is less than the minimum " 11582082Seschrock "size (%s)"), buf); 1159789Sahrens } 11602082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11612082Seschrock break; 11622082Seschrock 11632082Seschrock case ENOTSUP: 11642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11654527Sperrin "pool must be upgraded to add these vdevs")); 11662082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1167789Sahrens break; 1168789Sahrens 11693912Slling case EDOM: 11703912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11714527Sperrin "root pool can not have multiple vdevs" 11724527Sperrin " or separate logs")); 11733912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11743912Slling break; 11753912Slling 11765450Sbrendan case ENOTBLK: 11775450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11785450Sbrendan "cache device must be a disk or disk slice")); 11795450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11805450Sbrendan break; 11815450Sbrendan 1182789Sahrens default: 11832082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1184789Sahrens } 1185789Sahrens 11862082Seschrock ret = -1; 11872082Seschrock } else { 11882082Seschrock ret = 0; 1189789Sahrens } 1190789Sahrens 11912676Seschrock zcmd_free_nvlists(&zc); 1192789Sahrens 11932082Seschrock return (ret); 1194789Sahrens } 1195789Sahrens 1196789Sahrens /* 1197789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1198789Sahrens * mounted datasets in the pool. 1199789Sahrens */ 1200789Sahrens int 12018211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1202789Sahrens { 1203789Sahrens zfs_cmd_t zc = { 0 }; 12047214Slling char msg[1024]; 1205789Sahrens 12067214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 12077214Slling "cannot export '%s'"), zhp->zpool_name); 12087214Slling 1209789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 12107214Slling zc.zc_cookie = force; 12118211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 12127214Slling 12137214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 12147214Slling switch (errno) { 12157214Slling case EXDEV: 12167214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 12177214Slling "use '-f' to override the following errors:\n" 12187214Slling "'%s' has an active shared spare which could be" 12197214Slling " used by other pools once '%s' is exported."), 12207214Slling zhp->zpool_name, zhp->zpool_name); 12217214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 12227214Slling msg)); 12237214Slling default: 12247214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 12257214Slling msg)); 12267214Slling } 12277214Slling } 12287214Slling 1229789Sahrens return (0); 1230789Sahrens } 1231789Sahrens 12328211SGeorge.Wilson@Sun.COM int 12338211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 12348211SGeorge.Wilson@Sun.COM { 12358211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12368211SGeorge.Wilson@Sun.COM } 12378211SGeorge.Wilson@Sun.COM 12388211SGeorge.Wilson@Sun.COM int 12398211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12408211SGeorge.Wilson@Sun.COM { 12418211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12428211SGeorge.Wilson@Sun.COM } 12438211SGeorge.Wilson@Sun.COM 1244*10921STim.Haley@Sun.COM static void 1245*10921STim.Haley@Sun.COM zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 1246*10921STim.Haley@Sun.COM nvlist_t *rbi) 1247*10921STim.Haley@Sun.COM { 1248*10921STim.Haley@Sun.COM uint64_t rewindto; 1249*10921STim.Haley@Sun.COM int64_t loss = -1; 1250*10921STim.Haley@Sun.COM struct tm t; 1251*10921STim.Haley@Sun.COM char timestr[128]; 1252*10921STim.Haley@Sun.COM 1253*10921STim.Haley@Sun.COM if (!hdl->libzfs_printerr || rbi == NULL) 1254*10921STim.Haley@Sun.COM return; 1255*10921STim.Haley@Sun.COM 1256*10921STim.Haley@Sun.COM if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1257*10921STim.Haley@Sun.COM return; 1258*10921STim.Haley@Sun.COM (void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss); 1259*10921STim.Haley@Sun.COM 1260*10921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 1261*10921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 1262*10921STim.Haley@Sun.COM if (dryrun) { 1263*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1264*10921STim.Haley@Sun.COM "Would be able to return %s " 1265*10921STim.Haley@Sun.COM "to its state as of %s.\n"), 1266*10921STim.Haley@Sun.COM name, timestr); 1267*10921STim.Haley@Sun.COM } else { 1268*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1269*10921STim.Haley@Sun.COM "Pool %s returned to its state as of %s.\n"), 1270*10921STim.Haley@Sun.COM name, timestr); 1271*10921STim.Haley@Sun.COM } 1272*10921STim.Haley@Sun.COM if (loss > 120) { 1273*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1274*10921STim.Haley@Sun.COM "%s approximately %lld "), 1275*10921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", 1276*10921STim.Haley@Sun.COM (loss + 30) / 60); 1277*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1278*10921STim.Haley@Sun.COM "minutes of transactions.\n")); 1279*10921STim.Haley@Sun.COM } else if (loss > 0) { 1280*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1281*10921STim.Haley@Sun.COM "%s approximately %lld "), 1282*10921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", loss); 1283*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1284*10921STim.Haley@Sun.COM "seconds of transactions.\n")); 1285*10921STim.Haley@Sun.COM } 1286*10921STim.Haley@Sun.COM } 1287*10921STim.Haley@Sun.COM } 1288*10921STim.Haley@Sun.COM 1289*10921STim.Haley@Sun.COM void 1290*10921STim.Haley@Sun.COM zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 1291*10921STim.Haley@Sun.COM nvlist_t *config) 1292*10921STim.Haley@Sun.COM { 1293*10921STim.Haley@Sun.COM int64_t loss = -1; 1294*10921STim.Haley@Sun.COM uint64_t edata = UINT64_MAX; 1295*10921STim.Haley@Sun.COM uint64_t rewindto; 1296*10921STim.Haley@Sun.COM struct tm t; 1297*10921STim.Haley@Sun.COM char timestr[128]; 1298*10921STim.Haley@Sun.COM 1299*10921STim.Haley@Sun.COM if (!hdl->libzfs_printerr) 1300*10921STim.Haley@Sun.COM return; 1301*10921STim.Haley@Sun.COM 1302*10921STim.Haley@Sun.COM if (reason >= 0) 1303*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 1304*10921STim.Haley@Sun.COM else 1305*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "\t")); 1306*10921STim.Haley@Sun.COM 1307*10921STim.Haley@Sun.COM /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 1308*10921STim.Haley@Sun.COM if (nvlist_lookup_uint64(config, 1309*10921STim.Haley@Sun.COM ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1310*10921STim.Haley@Sun.COM goto no_info; 1311*10921STim.Haley@Sun.COM 1312*10921STim.Haley@Sun.COM (void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss); 1313*10921STim.Haley@Sun.COM (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 1314*10921STim.Haley@Sun.COM &edata); 1315*10921STim.Haley@Sun.COM 1316*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1317*10921STim.Haley@Sun.COM "Recovery is possible, but will result in some data loss.\n")); 1318*10921STim.Haley@Sun.COM 1319*10921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 1320*10921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 1321*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1322*10921STim.Haley@Sun.COM "\tReturning the pool to its state as of %s\n" 1323*10921STim.Haley@Sun.COM "\tshould correct the problem. "), 1324*10921STim.Haley@Sun.COM timestr); 1325*10921STim.Haley@Sun.COM } else { 1326*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1327*10921STim.Haley@Sun.COM "\tReverting the pool to an earlier state " 1328*10921STim.Haley@Sun.COM "should correct the problem.\n\t")); 1329*10921STim.Haley@Sun.COM } 1330*10921STim.Haley@Sun.COM 1331*10921STim.Haley@Sun.COM if (loss > 120) { 1332*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1333*10921STim.Haley@Sun.COM "Approximately %lld minutes of data\n" 1334*10921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 1335*10921STim.Haley@Sun.COM } else if (loss > 0) { 1336*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1337*10921STim.Haley@Sun.COM "Approximately %lld seconds of data\n" 1338*10921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), loss); 1339*10921STim.Haley@Sun.COM } 1340*10921STim.Haley@Sun.COM if (edata != 0 && edata != UINT64_MAX) { 1341*10921STim.Haley@Sun.COM if (edata == 1) { 1342*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1343*10921STim.Haley@Sun.COM "After rewind, at least\n" 1344*10921STim.Haley@Sun.COM "\tone persistent user-data error will remain. ")); 1345*10921STim.Haley@Sun.COM } else { 1346*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1347*10921STim.Haley@Sun.COM "After rewind, several\n" 1348*10921STim.Haley@Sun.COM "\tpersistent user-data errors will remain. ")); 1349*10921STim.Haley@Sun.COM } 1350*10921STim.Haley@Sun.COM } 1351*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1352*10921STim.Haley@Sun.COM "Recovery can be\n\tattempted by executing " 1353*10921STim.Haley@Sun.COM "'zpool %s -F %s'. "), reason >= 0 ? "clear" : "import", name); 1354*10921STim.Haley@Sun.COM 1355*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1356*10921STim.Haley@Sun.COM "A scrub of the pool\n" 1357*10921STim.Haley@Sun.COM "\tis strongly recommended after recovery.\n")); 1358*10921STim.Haley@Sun.COM return; 1359*10921STim.Haley@Sun.COM 1360*10921STim.Haley@Sun.COM no_info: 1361*10921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 1362*10921STim.Haley@Sun.COM "Destroy and re-create the pool from\n\ta backup source.\n")); 1363*10921STim.Haley@Sun.COM } 1364*10921STim.Haley@Sun.COM 1365789Sahrens /* 13665094Slling * zpool_import() is a contracted interface. Should be kept the same 13675094Slling * if possible. 13685094Slling * 13695094Slling * Applications should use zpool_import_props() to import a pool with 13705094Slling * new properties value to be set. 1371789Sahrens */ 1372789Sahrens int 13732082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 13745094Slling char *altroot) 13755094Slling { 13765094Slling nvlist_t *props = NULL; 13775094Slling int ret; 13785094Slling 13795094Slling if (altroot != NULL) { 13805094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 13815094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13825094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13835094Slling newname)); 13845094Slling } 13855094Slling 13865094Slling if (nvlist_add_string(props, 13878084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 13888084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 13898084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 13905094Slling nvlist_free(props); 13915094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13925094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13935094Slling newname)); 13945094Slling } 13955094Slling } 13965094Slling 13976643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 13985094Slling if (props) 13995094Slling nvlist_free(props); 14005094Slling return (ret); 14015094Slling } 14025094Slling 14035094Slling /* 14045094Slling * Import the given pool using the known configuration and a list of 14055094Slling * properties to be set. The configuration should have come from 14065094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 14075094Slling * is imported with a different name. 14085094Slling */ 14095094Slling int 14105094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 14116643Seschrock nvlist_t *props, boolean_t importfaulted) 1412789Sahrens { 14132676Seschrock zfs_cmd_t zc = { 0 }; 1414*10921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 1415*10921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 1416789Sahrens char *thename; 1417789Sahrens char *origname; 1418*10921STim.Haley@Sun.COM uint64_t returned_size; 1419789Sahrens int ret; 14205094Slling char errbuf[1024]; 1421789Sahrens 1422789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1423789Sahrens &origname) == 0); 1424789Sahrens 14255094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 14265094Slling "cannot import pool '%s'"), origname); 14275094Slling 1428789Sahrens if (newname != NULL) { 14292082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 14303237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 14312082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 14322082Seschrock newname)); 1433789Sahrens thename = (char *)newname; 1434789Sahrens } else { 1435789Sahrens thename = origname; 1436789Sahrens } 1437789Sahrens 14385094Slling if (props) { 14395094Slling uint64_t version; 14405094Slling 14415094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 14425094Slling &version) == 0); 14435094Slling 14447184Stimh if ((props = zpool_valid_proplist(hdl, origname, 14455320Slling props, version, B_TRUE, errbuf)) == NULL) { 14465094Slling return (-1); 14475320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 14485320Slling nvlist_free(props); 14495094Slling return (-1); 14505320Slling } 14515094Slling } 1452789Sahrens 1453789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1454789Sahrens 1455789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 14561544Seschrock &zc.zc_guid) == 0); 1457789Sahrens 14585320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 14595320Slling nvlist_free(props); 14602082Seschrock return (-1); 14615320Slling } 1462*10921STim.Haley@Sun.COM returned_size = zc.zc_nvlist_conf_size + 512; 1463*10921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) { 1464*10921STim.Haley@Sun.COM nvlist_free(props); 1465*10921STim.Haley@Sun.COM return (-1); 1466*10921STim.Haley@Sun.COM } 1467789Sahrens 14686643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1469789Sahrens ret = 0; 14704543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1471789Sahrens char desc[1024]; 1472*10921STim.Haley@Sun.COM 1473*10921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 1474*10921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 1475*10921STim.Haley@Sun.COM /* 1476*10921STim.Haley@Sun.COM * Dry-run failed, but we print out what success 1477*10921STim.Haley@Sun.COM * looks like if we found a best txg 1478*10921STim.Haley@Sun.COM */ 1479*10921STim.Haley@Sun.COM if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) { 1480*10921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 1481*10921STim.Haley@Sun.COM B_TRUE, nvi); 1482*10921STim.Haley@Sun.COM nvlist_free(nvi); 1483*10921STim.Haley@Sun.COM return (-1); 1484*10921STim.Haley@Sun.COM } 1485*10921STim.Haley@Sun.COM 1486789Sahrens if (newname == NULL) 1487789Sahrens (void) snprintf(desc, sizeof (desc), 1488789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1489789Sahrens thename); 1490789Sahrens else 1491789Sahrens (void) snprintf(desc, sizeof (desc), 1492789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1493789Sahrens origname, thename); 1494789Sahrens 1495789Sahrens switch (errno) { 14961544Seschrock case ENOTSUP: 14971544Seschrock /* 14981544Seschrock * Unsupported version. 14991544Seschrock */ 15002082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 15011544Seschrock break; 15021544Seschrock 15032174Seschrock case EINVAL: 15042174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 15052174Seschrock break; 15062174Seschrock 1507789Sahrens default: 1508*10921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 15092082Seschrock (void) zpool_standard_error(hdl, errno, desc); 1510*10921STim.Haley@Sun.COM zpool_explain_recover(hdl, 1511*10921STim.Haley@Sun.COM newname ? origname : thename, -errno, nvi); 1512*10921STim.Haley@Sun.COM nvlist_free(nvi); 1513*10921STim.Haley@Sun.COM break; 1514789Sahrens } 1515789Sahrens 1516789Sahrens ret = -1; 1517789Sahrens } else { 1518789Sahrens zpool_handle_t *zhp; 15194543Smarks 1520789Sahrens /* 1521789Sahrens * This should never fail, but play it safe anyway. 1522789Sahrens */ 152310588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 15242142Seschrock ret = -1; 152510588SEric.Taylor@Sun.COM else if (zhp != NULL) 1526789Sahrens zpool_close(zhp); 1527*10921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 1528*10921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 1529*10921STim.Haley@Sun.COM if (policy.zrp_request & 1530*10921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 1531*10921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 1532*10921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 1533*10921STim.Haley@Sun.COM nvi); 1534*10921STim.Haley@Sun.COM } 1535*10921STim.Haley@Sun.COM nvlist_free(nvi); 1536*10921STim.Haley@Sun.COM return (0); 1537789Sahrens } 1538789Sahrens 15392676Seschrock zcmd_free_nvlists(&zc); 15405320Slling nvlist_free(props); 15415320Slling 1542789Sahrens return (ret); 1543789Sahrens } 1544789Sahrens 1545789Sahrens /* 1546789Sahrens * Scrub the pool. 1547789Sahrens */ 1548789Sahrens int 1549789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1550789Sahrens { 1551789Sahrens zfs_cmd_t zc = { 0 }; 1552789Sahrens char msg[1024]; 15532082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1554789Sahrens 1555789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1556789Sahrens zc.zc_cookie = type; 1557789Sahrens 15584543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1559789Sahrens return (0); 1560789Sahrens 1561789Sahrens (void) snprintf(msg, sizeof (msg), 1562789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1563789Sahrens 15642082Seschrock if (errno == EBUSY) 15652082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 15662082Seschrock else 15672082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1568789Sahrens } 1569789Sahrens 15702468Sek110237 /* 15719816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 15729816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 15732468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 15742468Sek110237 * spare; but FALSE if its an INUSE spare. 15752468Sek110237 */ 15762082Seschrock static nvlist_t * 15779816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 15789816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 15791544Seschrock { 15801544Seschrock uint_t c, children; 15811544Seschrock nvlist_t **child; 15822082Seschrock nvlist_t *ret; 15837326SEric.Schrock@Sun.COM uint64_t is_log; 15849816SGeorge.Wilson@Sun.COM char *srchkey; 15859816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 15869816SGeorge.Wilson@Sun.COM 15879816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 15889816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 15899816SGeorge.Wilson@Sun.COM return (NULL); 15909816SGeorge.Wilson@Sun.COM 15919816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 15929816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 15939816SGeorge.Wilson@Sun.COM 15949816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 15959816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 15969816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 15979816SGeorge.Wilson@Sun.COM 15989816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 15999816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 16009816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 16019816SGeorge.Wilson@Sun.COM &present) == 0) { 16029816SGeorge.Wilson@Sun.COM /* 16039816SGeorge.Wilson@Sun.COM * If the device has never been present since 16049816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 16059816SGeorge.Wilson@Sun.COM * vdev is by GUID. 16069816SGeorge.Wilson@Sun.COM */ 16079816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 16089816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 16099816SGeorge.Wilson@Sun.COM if (theguid == srchval) 16109816SGeorge.Wilson@Sun.COM return (nv); 16119816SGeorge.Wilson@Sun.COM } 16129816SGeorge.Wilson@Sun.COM } 16139816SGeorge.Wilson@Sun.COM break; 16149816SGeorge.Wilson@Sun.COM } 16159816SGeorge.Wilson@Sun.COM 16169816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 16179816SGeorge.Wilson@Sun.COM char *srchval, *val; 16189816SGeorge.Wilson@Sun.COM 16199816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 16209816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 16219816SGeorge.Wilson@Sun.COM break; 16229816SGeorge.Wilson@Sun.COM 16231544Seschrock /* 16249816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 162510594SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk and when 162610594SGeorge.Wilson@Sun.COM * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 162710594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 16281544Seschrock */ 16299816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 16309816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 16319816SGeorge.Wilson@Sun.COM 16329816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 16339816SGeorge.Wilson@Sun.COM &wholedisk); 16349816SGeorge.Wilson@Sun.COM if (wholedisk) { 16359816SGeorge.Wilson@Sun.COM /* 16369816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 16379816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 16389816SGeorge.Wilson@Sun.COM */ 16399816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 16409816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 16419816SGeorge.Wilson@Sun.COM return (nv); 16429816SGeorge.Wilson@Sun.COM break; 16439816SGeorge.Wilson@Sun.COM } 164410594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 164510594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 164610594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 164710594SGeorge.Wilson@Sun.COM 164810594SGeorge.Wilson@Sun.COM /* 164910594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 165010594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 165110594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 165210594SGeorge.Wilson@Sun.COM */ 165310594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 165410594SGeorge.Wilson@Sun.COM return (NULL); 165510594SGeorge.Wilson@Sun.COM 165610594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 165710594SGeorge.Wilson@Sun.COM free(type); 165810594SGeorge.Wilson@Sun.COM break; 165910594SGeorge.Wilson@Sun.COM } 166010594SGeorge.Wilson@Sun.COM idx = p + 1; 166110594SGeorge.Wilson@Sun.COM *p = '\0'; 166210594SGeorge.Wilson@Sun.COM 166310594SGeorge.Wilson@Sun.COM /* 166410594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 166510594SGeorge.Wilson@Sun.COM */ 166610594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 166710594SGeorge.Wilson@Sun.COM free(type); 166810594SGeorge.Wilson@Sun.COM break; 166910594SGeorge.Wilson@Sun.COM } 167010594SGeorge.Wilson@Sun.COM 167110594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 167210594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 167310594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 167410594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 167510594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 167610594SGeorge.Wilson@Sun.COM &id) == 0); 167710594SGeorge.Wilson@Sun.COM 167810594SGeorge.Wilson@Sun.COM errno = 0; 167910594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 168010594SGeorge.Wilson@Sun.COM 168110594SGeorge.Wilson@Sun.COM free(type); 168210594SGeorge.Wilson@Sun.COM if (errno != 0) 168310594SGeorge.Wilson@Sun.COM return (NULL); 168410594SGeorge.Wilson@Sun.COM 168510594SGeorge.Wilson@Sun.COM /* 168610594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 168710594SGeorge.Wilson@Sun.COM */ 168810594SGeorge.Wilson@Sun.COM if (vdev_id == id) 168910594SGeorge.Wilson@Sun.COM return (nv); 16909816SGeorge.Wilson@Sun.COM } 16919816SGeorge.Wilson@Sun.COM 16929816SGeorge.Wilson@Sun.COM /* 16939816SGeorge.Wilson@Sun.COM * Common case 16949816SGeorge.Wilson@Sun.COM */ 16959816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 16962082Seschrock return (nv); 16979816SGeorge.Wilson@Sun.COM break; 16989816SGeorge.Wilson@Sun.COM } 16999816SGeorge.Wilson@Sun.COM 17009816SGeorge.Wilson@Sun.COM default: 17019816SGeorge.Wilson@Sun.COM break; 17021544Seschrock } 17031544Seschrock 17041544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 17051544Seschrock &child, &children) != 0) 17062082Seschrock return (NULL); 17071544Seschrock 17087326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 17099816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17107326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17117326SEric.Schrock@Sun.COM /* 17127326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 17137326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 17147326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 17157326SEric.Schrock@Sun.COM * 'log' is non-NULL). 17167326SEric.Schrock@Sun.COM */ 17177326SEric.Schrock@Sun.COM if (log != NULL && 17187326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 17197326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 17207326SEric.Schrock@Sun.COM is_log) { 17217326SEric.Schrock@Sun.COM *log = B_TRUE; 17227326SEric.Schrock@Sun.COM } 17231544Seschrock return (ret); 17247326SEric.Schrock@Sun.COM } 17257326SEric.Schrock@Sun.COM } 17261544Seschrock 17272082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 17282082Seschrock &child, &children) == 0) { 17292082Seschrock for (c = 0; c < children; c++) { 17309816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17317326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17322468Sek110237 *avail_spare = B_TRUE; 17332082Seschrock return (ret); 17342082Seschrock } 17352082Seschrock } 17362082Seschrock } 17372082Seschrock 17385450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 17395450Sbrendan &child, &children) == 0) { 17405450Sbrendan for (c = 0; c < children; c++) { 17419816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17427326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17435450Sbrendan *l2cache = B_TRUE; 17445450Sbrendan return (ret); 17455450Sbrendan } 17465450Sbrendan } 17475450Sbrendan } 17485450Sbrendan 17492082Seschrock return (NULL); 17501544Seschrock } 17511544Seschrock 17529816SGeorge.Wilson@Sun.COM /* 17539816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 17549816SGeorge.Wilson@Sun.COM * associated vdev. 17559816SGeorge.Wilson@Sun.COM */ 17569816SGeorge.Wilson@Sun.COM nvlist_t * 17579816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 17589816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 17599816SGeorge.Wilson@Sun.COM { 17609816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 17619816SGeorge.Wilson@Sun.COM 17629816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 17639816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 17649816SGeorge.Wilson@Sun.COM 17659816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 17669816SGeorge.Wilson@Sun.COM &nvroot) == 0); 17679816SGeorge.Wilson@Sun.COM 17689816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 17699816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 17709816SGeorge.Wilson@Sun.COM nvlist_free(search); 17719816SGeorge.Wilson@Sun.COM 17729816SGeorge.Wilson@Sun.COM return (ret); 17739816SGeorge.Wilson@Sun.COM } 17749816SGeorge.Wilson@Sun.COM 177510594SGeorge.Wilson@Sun.COM /* 177610594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 177710594SGeorge.Wilson@Sun.COM */ 177810594SGeorge.Wilson@Sun.COM boolean_t 177910594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 178010594SGeorge.Wilson@Sun.COM { 178110594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 178210594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 178310594SGeorge.Wilson@Sun.COM return (B_TRUE); 178410594SGeorge.Wilson@Sun.COM return (B_FALSE); 178510594SGeorge.Wilson@Sun.COM } 178610594SGeorge.Wilson@Sun.COM 17872082Seschrock nvlist_t * 17885450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 17897326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 17901544Seschrock { 17911544Seschrock char buf[MAXPATHLEN]; 17921544Seschrock char *end; 17939816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 17941544Seschrock uint64_t guid; 17951544Seschrock 17969816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 17979816SGeorge.Wilson@Sun.COM 17981613Seschrock guid = strtoull(path, &end, 10); 17991544Seschrock if (guid != 0 && *end == '\0') { 18009816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 180110594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 180210594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 18031544Seschrock } else if (path[0] != '/') { 18041544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 18059816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 18061544Seschrock } else { 18079816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 18081544Seschrock } 18091544Seschrock 18101544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18111544Seschrock &nvroot) == 0); 18121544Seschrock 18132468Sek110237 *avail_spare = B_FALSE; 18145450Sbrendan *l2cache = B_FALSE; 18157326SEric.Schrock@Sun.COM if (log != NULL) 18167326SEric.Schrock@Sun.COM *log = B_FALSE; 18179816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 18189816SGeorge.Wilson@Sun.COM nvlist_free(search); 18199816SGeorge.Wilson@Sun.COM 18209816SGeorge.Wilson@Sun.COM return (ret); 18212468Sek110237 } 18222468Sek110237 18237656SSherry.Moore@Sun.COM static int 18247656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 18257656SSherry.Moore@Sun.COM { 18267656SSherry.Moore@Sun.COM uint64_t ival; 18277656SSherry.Moore@Sun.COM 18287656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 18297656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 18307656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 18317656SSherry.Moore@Sun.COM return (0); 18327656SSherry.Moore@Sun.COM 18337656SSherry.Moore@Sun.COM return (1); 18347656SSherry.Moore@Sun.COM } 18357656SSherry.Moore@Sun.COM 18367656SSherry.Moore@Sun.COM /* 18379790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 18387656SSherry.Moore@Sun.COM */ 18399160SSherry.Moore@Sun.COM static int 18409790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 18419160SSherry.Moore@Sun.COM size_t *bytes_written) 18427656SSherry.Moore@Sun.COM { 18439160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 18449160SSherry.Moore@Sun.COM char *tmppath; 18459160SSherry.Moore@Sun.COM const char *format; 18469160SSherry.Moore@Sun.COM 18479160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 18489160SSherry.Moore@Sun.COM &tmppath) != 0) 18499160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 18509160SSherry.Moore@Sun.COM 18519160SSherry.Moore@Sun.COM pos = *bytes_written; 18529160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 18539160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 18549160SSherry.Moore@Sun.COM 18559160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 18569160SSherry.Moore@Sun.COM *bytes_written += rsz; 18579160SSherry.Moore@Sun.COM 18589160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 18599160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 18609160SSherry.Moore@Sun.COM if (bytes_left != 0) { 18619160SSherry.Moore@Sun.COM physpath[pos] = 0; 18629160SSherry.Moore@Sun.COM } 18639160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 18649160SSherry.Moore@Sun.COM } 18659160SSherry.Moore@Sun.COM return (0); 18669160SSherry.Moore@Sun.COM } 18679160SSherry.Moore@Sun.COM 18689790SLin.Ling@Sun.COM static int 18699790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 18709790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 18719790SLin.Ling@Sun.COM { 18729790SLin.Ling@Sun.COM char *type; 18739790SLin.Ling@Sun.COM int ret; 18749790SLin.Ling@Sun.COM 18759790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 18769790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 18779790SLin.Ling@Sun.COM 18789790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 18799790SLin.Ling@Sun.COM /* 18809790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 18819790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 18829790SLin.Ling@Sun.COM * spare device. 18839790SLin.Ling@Sun.COM */ 18849790SLin.Ling@Sun.COM if (is_spare) { 18859790SLin.Ling@Sun.COM uint64_t spare = 0; 18869790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 18879790SLin.Ling@Sun.COM &spare); 18889790SLin.Ling@Sun.COM if (!spare) 18899790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 18909790SLin.Ling@Sun.COM } 18919790SLin.Ling@Sun.COM 18929790SLin.Ling@Sun.COM if (vdev_online(nv)) { 18939790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 18949790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 18959790SLin.Ling@Sun.COM return (ret); 18969790SLin.Ling@Sun.COM } 18979790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 18989790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 18999790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 19009790SLin.Ling@Sun.COM nvlist_t **child; 19019790SLin.Ling@Sun.COM uint_t count; 19029790SLin.Ling@Sun.COM int i, ret; 19039790SLin.Ling@Sun.COM 19049790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 19059790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 19069790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19079790SLin.Ling@Sun.COM 19089790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 19099790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 19109790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 19119790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 19129790SLin.Ling@Sun.COM return (ret); 19139790SLin.Ling@Sun.COM } 19149790SLin.Ling@Sun.COM } 19159790SLin.Ling@Sun.COM 19169790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 19179790SLin.Ling@Sun.COM } 19189790SLin.Ling@Sun.COM 19199160SSherry.Moore@Sun.COM /* 19209160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 19219160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 19229160SSherry.Moore@Sun.COM */ 19239160SSherry.Moore@Sun.COM static int 19249160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 19259160SSherry.Moore@Sun.COM { 19269160SSherry.Moore@Sun.COM size_t rsz; 19277656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 19287656SSherry.Moore@Sun.COM nvlist_t **child; 19297656SSherry.Moore@Sun.COM uint_t count; 19309160SSherry.Moore@Sun.COM char *type; 19319160SSherry.Moore@Sun.COM 19329160SSherry.Moore@Sun.COM rsz = 0; 19339160SSherry.Moore@Sun.COM 19349160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 19359160SSherry.Moore@Sun.COM &vdev_root) != 0) 19369160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19379160SSherry.Moore@Sun.COM 19389160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 19399160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 19409160SSherry.Moore@Sun.COM &child, &count) != 0) 19419160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19427656SSherry.Moore@Sun.COM 19437656SSherry.Moore@Sun.COM /* 19449160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 19459160SSherry.Moore@Sun.COM * a single top-level vdev. 19467656SSherry.Moore@Sun.COM */ 19479160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 19489160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 19499160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 19509160SSherry.Moore@Sun.COM 19519790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 19529790SLin.Ling@Sun.COM B_FALSE); 19537656SSherry.Moore@Sun.COM 19549160SSherry.Moore@Sun.COM /* No online devices */ 19559160SSherry.Moore@Sun.COM if (rsz == 0) 19569160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 19579160SSherry.Moore@Sun.COM 19587656SSherry.Moore@Sun.COM return (0); 19597656SSherry.Moore@Sun.COM } 19607656SSherry.Moore@Sun.COM 19612468Sek110237 /* 19629160SSherry.Moore@Sun.COM * Get phys_path for a root pool 19639160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 19649160SSherry.Moore@Sun.COM */ 19659160SSherry.Moore@Sun.COM int 19669160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 19679160SSherry.Moore@Sun.COM { 19689160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 19699160SSherry.Moore@Sun.COM phypath_size)); 19709160SSherry.Moore@Sun.COM } 19719160SSherry.Moore@Sun.COM 19729160SSherry.Moore@Sun.COM /* 19739816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 19749816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 19759816SGeorge.Wilson@Sun.COM */ 19769816SGeorge.Wilson@Sun.COM static int 19779816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 19789816SGeorge.Wilson@Sun.COM { 19799816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 19809816SGeorge.Wilson@Sun.COM char errbuf[1024]; 19819816SGeorge.Wilson@Sun.COM int fd, error; 19829816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 19839816SGeorge.Wilson@Sun.COM 19849816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 19859816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 19869816SGeorge.Wilson@Sun.COM return (-1); 19879816SGeorge.Wilson@Sun.COM 19889816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 19899816SGeorge.Wilson@Sun.COM 19909816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 19919816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 19929816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 19939816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 19949816SGeorge.Wilson@Sun.COM } 19959816SGeorge.Wilson@Sun.COM 19969816SGeorge.Wilson@Sun.COM /* 19979816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 19989816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 19999816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 20009816SGeorge.Wilson@Sun.COM */ 20019816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 20029816SGeorge.Wilson@Sun.COM (void) close(fd); 20039816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 20049816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 20059816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 20069816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 20079816SGeorge.Wilson@Sun.COM } 20089816SGeorge.Wilson@Sun.COM return (0); 20099816SGeorge.Wilson@Sun.COM } 20109816SGeorge.Wilson@Sun.COM 20119816SGeorge.Wilson@Sun.COM /* 20124451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 20134451Seschrock * ZFS_ONLINE_* flags. 2014789Sahrens */ 2015789Sahrens int 20164451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 20174451Seschrock vdev_state_t *newstate) 2018789Sahrens { 2019789Sahrens zfs_cmd_t zc = { 0 }; 2020789Sahrens char msg[1024]; 20212082Seschrock nvlist_t *tgt; 20229816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 20232082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2024789Sahrens 20259816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 20269816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20279816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 20289816SGeorge.Wilson@Sun.COM } else { 20299816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20309816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 20319816SGeorge.Wilson@Sun.COM } 2032789Sahrens 20331544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20347326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 20359816SGeorge.Wilson@Sun.COM &islog)) == NULL) 20362082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2037789Sahrens 20382468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20392468Sek110237 204010817SEric.Schrock@Sun.COM if (avail_spare) 20412082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20422082Seschrock 20439816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 20449816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 20459816SGeorge.Wilson@Sun.COM char *pathname = NULL; 20469816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 20479816SGeorge.Wilson@Sun.COM 20489816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 20499816SGeorge.Wilson@Sun.COM &wholedisk); 20509816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 20519816SGeorge.Wilson@Sun.COM &pathname) == 0); 20529816SGeorge.Wilson@Sun.COM 20539816SGeorge.Wilson@Sun.COM /* 20549816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 20559816SGeorge.Wilson@Sun.COM */ 20569816SGeorge.Wilson@Sun.COM if (l2cache) { 20579816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20589816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 20599816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 20609816SGeorge.Wilson@Sun.COM } 20619816SGeorge.Wilson@Sun.COM 20629816SGeorge.Wilson@Sun.COM if (wholedisk) { 20639816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 20649816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 20659816SGeorge.Wilson@Sun.COM } 20669816SGeorge.Wilson@Sun.COM } 20679816SGeorge.Wilson@Sun.COM 20684451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 20694451Seschrock zc.zc_obj = flags; 20704451Seschrock 20714543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 20724451Seschrock return (zpool_standard_error(hdl, errno, msg)); 20734451Seschrock 20744451Seschrock *newstate = zc.zc_cookie; 20754451Seschrock return (0); 2076789Sahrens } 2077789Sahrens 2078789Sahrens /* 2079789Sahrens * Take the specified vdev offline 2080789Sahrens */ 2081789Sahrens int 20824451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2083789Sahrens { 2084789Sahrens zfs_cmd_t zc = { 0 }; 2085789Sahrens char msg[1024]; 20862082Seschrock nvlist_t *tgt; 20875450Sbrendan boolean_t avail_spare, l2cache; 20882082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2089789Sahrens 20901544Seschrock (void) snprintf(msg, sizeof (msg), 20911544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 20921544Seschrock 2093789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20947326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 20957326SEric.Schrock@Sun.COM NULL)) == NULL) 20962082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 20972082Seschrock 20982468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20992468Sek110237 210010817SEric.Schrock@Sun.COM if (avail_spare) 21012082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21022082Seschrock 21034451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 21044451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 21051485Slling 21064543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2107789Sahrens return (0); 2108789Sahrens 2109789Sahrens switch (errno) { 21102082Seschrock case EBUSY: 2111789Sahrens 2112789Sahrens /* 2113789Sahrens * There are no other replicas of this device. 2114789Sahrens */ 21152082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21162082Seschrock 21179701SGeorge.Wilson@Sun.COM case EEXIST: 21189701SGeorge.Wilson@Sun.COM /* 21199701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 21209701SGeorge.Wilson@Sun.COM */ 21219701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 21229701SGeorge.Wilson@Sun.COM 21232082Seschrock default: 21242082Seschrock return (zpool_standard_error(hdl, errno, msg)); 21252082Seschrock } 21262082Seschrock } 2127789Sahrens 21282082Seschrock /* 21294451Seschrock * Mark the given vdev faulted. 21304451Seschrock */ 21314451Seschrock int 213210817SEric.Schrock@Sun.COM zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21334451Seschrock { 21344451Seschrock zfs_cmd_t zc = { 0 }; 21354451Seschrock char msg[1024]; 21364451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21374451Seschrock 21384451Seschrock (void) snprintf(msg, sizeof (msg), 21394451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 21404451Seschrock 21414451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21424451Seschrock zc.zc_guid = guid; 21434451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 214410817SEric.Schrock@Sun.COM zc.zc_obj = aux; 21454451Seschrock 21464451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21474451Seschrock return (0); 21484451Seschrock 21494451Seschrock switch (errno) { 21504451Seschrock case EBUSY: 21514451Seschrock 21524451Seschrock /* 21534451Seschrock * There are no other replicas of this device. 21544451Seschrock */ 21554451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21564451Seschrock 21574451Seschrock default: 21584451Seschrock return (zpool_standard_error(hdl, errno, msg)); 21594451Seschrock } 21604451Seschrock 21614451Seschrock } 21624451Seschrock 21634451Seschrock /* 21644451Seschrock * Mark the given vdev degraded. 21654451Seschrock */ 21664451Seschrock int 216710817SEric.Schrock@Sun.COM zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21684451Seschrock { 21694451Seschrock zfs_cmd_t zc = { 0 }; 21704451Seschrock char msg[1024]; 21714451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21724451Seschrock 21734451Seschrock (void) snprintf(msg, sizeof (msg), 21744451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 21754451Seschrock 21764451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21774451Seschrock zc.zc_guid = guid; 21784451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 217910817SEric.Schrock@Sun.COM zc.zc_obj = aux; 21804451Seschrock 21814451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21824451Seschrock return (0); 21834451Seschrock 21844451Seschrock return (zpool_standard_error(hdl, errno, msg)); 21854451Seschrock } 21864451Seschrock 21874451Seschrock /* 21882082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 21892082Seschrock * a hot spare. 21902082Seschrock */ 21912082Seschrock static boolean_t 21922082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 21932082Seschrock { 21942082Seschrock nvlist_t **child; 21952082Seschrock uint_t c, children; 21962082Seschrock char *type; 21972082Seschrock 21982082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 21992082Seschrock &children) == 0) { 22002082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 22012082Seschrock &type) == 0); 22022082Seschrock 22032082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 22042082Seschrock children == 2 && child[which] == tgt) 22052082Seschrock return (B_TRUE); 22062082Seschrock 22072082Seschrock for (c = 0; c < children; c++) 22082082Seschrock if (is_replacing_spare(child[c], tgt, which)) 22092082Seschrock return (B_TRUE); 2210789Sahrens } 22112082Seschrock 22122082Seschrock return (B_FALSE); 2213789Sahrens } 2214789Sahrens 2215789Sahrens /* 2216789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 22174527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2218789Sahrens */ 2219789Sahrens int 2220789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2221789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2222789Sahrens { 2223789Sahrens zfs_cmd_t zc = { 0 }; 2224789Sahrens char msg[1024]; 2225789Sahrens int ret; 22262082Seschrock nvlist_t *tgt; 22277326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 22287326SEric.Schrock@Sun.COM uint64_t val; 22297041Seschrock char *path, *newname; 22302082Seschrock nvlist_t **child; 22312082Seschrock uint_t children; 22322082Seschrock nvlist_t *config_root; 22332082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22347965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2235789Sahrens 22361544Seschrock if (replacing) 22371544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 22381544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 22391544Seschrock else 22401544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 22411544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 22421544Seschrock 22437965SGeorge.Wilson@Sun.COM /* 22447965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 22457965SGeorge.Wilson@Sun.COM * EFI labeled device. 22467965SGeorge.Wilson@Sun.COM */ 22477965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 22487965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22497965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 22507965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 22517965SGeorge.Wilson@Sun.COM } 22527965SGeorge.Wilson@Sun.COM 2253789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22547326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 22557326SEric.Schrock@Sun.COM &islog)) == 0) 22562082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22572082Seschrock 22582468Sek110237 if (avail_spare) 22592082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22602082Seschrock 22615450Sbrendan if (l2cache) 22625450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 22635450Sbrendan 22642082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22652082Seschrock zc.zc_cookie = replacing; 22662082Seschrock 22672082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 22682082Seschrock &child, &children) != 0 || children != 1) { 22692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22702082Seschrock "new device must be a single disk")); 22712082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 22721544Seschrock } 22732082Seschrock 22742082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 22752082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 22762082Seschrock 227710594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 22787041Seschrock return (-1); 22797041Seschrock 22802082Seschrock /* 22812082Seschrock * If the target is a hot spare that has been swapped in, we can only 22822082Seschrock * replace it with another hot spare. 22832082Seschrock */ 22842082Seschrock if (replacing && 22852082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 22867326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 22877326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 22887326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 22892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22902082Seschrock "can only be replaced by another hot spare")); 22917041Seschrock free(newname); 22922082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 22932082Seschrock } 22942082Seschrock 22952082Seschrock /* 22962082Seschrock * If we are attempting to replace a spare, it canot be applied to an 22972082Seschrock * already spared device. 22982082Seschrock */ 22992082Seschrock if (replacing && 23002082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 23017326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 23027326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 23037326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 23042082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23052082Seschrock "device has already been replaced with a spare")); 23067041Seschrock free(newname); 23072082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 23082082Seschrock } 2309789Sahrens 23107041Seschrock free(newname); 23117041Seschrock 23125094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 23132082Seschrock return (-1); 2314789Sahrens 23154543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2316789Sahrens 23172676Seschrock zcmd_free_nvlists(&zc); 2318789Sahrens 23197965SGeorge.Wilson@Sun.COM if (ret == 0) { 23207965SGeorge.Wilson@Sun.COM if (rootpool) { 23217965SGeorge.Wilson@Sun.COM /* 23227965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 23237965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 23247965SGeorge.Wilson@Sun.COM * newly attached disk. 23257965SGeorge.Wilson@Sun.COM */ 23267965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 23277965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 23287965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 23299790SLin.Ling@Sun.COM 23309790SLin.Ling@Sun.COM /* 23319790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 23329790SLin.Ling@Sun.COM * booting up a half-baked vdev. 23339790SLin.Ling@Sun.COM */ 23349790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 23359790SLin.Ling@Sun.COM "sure to wait until resilver is done " 23369790SLin.Ling@Sun.COM "before rebooting.\n")); 23377965SGeorge.Wilson@Sun.COM } 2338789Sahrens return (0); 23397965SGeorge.Wilson@Sun.COM } 2340789Sahrens 2341789Sahrens switch (errno) { 23421544Seschrock case ENOTSUP: 2343789Sahrens /* 2344789Sahrens * Can't attach to or replace this type of vdev. 2345789Sahrens */ 23464527Sperrin if (replacing) { 23477326SEric.Schrock@Sun.COM if (islog) 23484527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23494527Sperrin "cannot replace a log with a spare")); 23504527Sperrin else 23514527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23524527Sperrin "cannot replace a replacing device")); 23534527Sperrin } else { 23542082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23552082Seschrock "can only attach to mirrors and top-level " 23562082Seschrock "disks")); 23574527Sperrin } 23582082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2359789Sahrens break; 2360789Sahrens 23611544Seschrock case EINVAL: 2362789Sahrens /* 2363789Sahrens * The new device must be a single disk. 2364789Sahrens */ 23652082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23662082Seschrock "new device must be a single disk")); 23672082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2368789Sahrens break; 2369789Sahrens 23701544Seschrock case EBUSY: 23712082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 23722082Seschrock new_disk); 23732082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2374789Sahrens break; 2375789Sahrens 23761544Seschrock case EOVERFLOW: 2377789Sahrens /* 2378789Sahrens * The new device is too small. 2379789Sahrens */ 23802082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23812082Seschrock "device is too small")); 23822082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2383789Sahrens break; 2384789Sahrens 23851544Seschrock case EDOM: 2386789Sahrens /* 2387789Sahrens * The new device has a different alignment requirement. 2388789Sahrens */ 23892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23902082Seschrock "devices have different sector alignment")); 23912082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2392789Sahrens break; 2393789Sahrens 23941544Seschrock case ENAMETOOLONG: 2395789Sahrens /* 2396789Sahrens * The resulting top-level vdev spec won't fit in the label. 2397789Sahrens */ 23982082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2399789Sahrens break; 2400789Sahrens 24011544Seschrock default: 24022082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2403789Sahrens } 2404789Sahrens 24052082Seschrock return (-1); 2406789Sahrens } 2407789Sahrens 2408789Sahrens /* 2409789Sahrens * Detach the specified device. 2410789Sahrens */ 2411789Sahrens int 2412789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2413789Sahrens { 2414789Sahrens zfs_cmd_t zc = { 0 }; 2415789Sahrens char msg[1024]; 24162082Seschrock nvlist_t *tgt; 24175450Sbrendan boolean_t avail_spare, l2cache; 24182082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2419789Sahrens 24201544Seschrock (void) snprintf(msg, sizeof (msg), 24211544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 24221544Seschrock 2423789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24247326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 24257326SEric.Schrock@Sun.COM NULL)) == 0) 24262082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2427789Sahrens 24282468Sek110237 if (avail_spare) 24292082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 24302082Seschrock 24315450Sbrendan if (l2cache) 24325450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 24335450Sbrendan 24342082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 24352082Seschrock 24364543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2437789Sahrens return (0); 2438789Sahrens 2439789Sahrens switch (errno) { 2440789Sahrens 24411544Seschrock case ENOTSUP: 2442789Sahrens /* 2443789Sahrens * Can't detach from this type of vdev. 2444789Sahrens */ 24452082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 24462082Seschrock "applicable to mirror and replacing vdevs")); 24472082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2448789Sahrens break; 2449789Sahrens 24501544Seschrock case EBUSY: 2451789Sahrens /* 2452789Sahrens * There are no other replicas of this device. 2453789Sahrens */ 24542082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2455789Sahrens break; 2456789Sahrens 24571544Seschrock default: 24582082Seschrock (void) zpool_standard_error(hdl, errno, msg); 24591544Seschrock } 24601544Seschrock 24612082Seschrock return (-1); 24622082Seschrock } 24632082Seschrock 24642082Seschrock /* 24655450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 24665450Sbrendan * and level 2 cache devices. 24672082Seschrock */ 24682082Seschrock int 24692082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 24702082Seschrock { 24712082Seschrock zfs_cmd_t zc = { 0 }; 24722082Seschrock char msg[1024]; 24732082Seschrock nvlist_t *tgt; 247410594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 24752082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 247610594SGeorge.Wilson@Sun.COM uint64_t version; 24772082Seschrock 24782082Seschrock (void) snprintf(msg, sizeof (msg), 24792082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 24802082Seschrock 24812082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24827326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 248310594SGeorge.Wilson@Sun.COM &islog)) == 0) 24842082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 248510594SGeorge.Wilson@Sun.COM /* 248610594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 248710594SGeorge.Wilson@Sun.COM */ 248810594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 24892082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 249010594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 249110594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 24922082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 24932082Seschrock } 24942082Seschrock 249510594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 249610594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 249710594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 249810594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 249910594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 250010594SGeorge.Wilson@Sun.COM } 250110594SGeorge.Wilson@Sun.COM 25022082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 25032082Seschrock 25044543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 25052082Seschrock return (0); 25062082Seschrock 25072082Seschrock return (zpool_standard_error(hdl, errno, msg)); 25081544Seschrock } 25091544Seschrock 25101544Seschrock /* 25111544Seschrock * Clear the errors for the pool, or the particular device if specified. 25121544Seschrock */ 25131544Seschrock int 2514*10921STim.Haley@Sun.COM zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 25151544Seschrock { 25161544Seschrock zfs_cmd_t zc = { 0 }; 25171544Seschrock char msg[1024]; 25182082Seschrock nvlist_t *tgt; 2519*10921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 25205450Sbrendan boolean_t avail_spare, l2cache; 25212082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2522*10921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 25231544Seschrock 25241544Seschrock if (path) 25251544Seschrock (void) snprintf(msg, sizeof (msg), 25261544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 25272676Seschrock path); 25281544Seschrock else 25291544Seschrock (void) snprintf(msg, sizeof (msg), 25301544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 25311544Seschrock zhp->zpool_name); 25321544Seschrock 25331544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25342082Seschrock if (path) { 25355450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 25367326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 25372082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 25382082Seschrock 25395450Sbrendan /* 25405450Sbrendan * Don't allow error clearing for hot spares. Do allow 25415450Sbrendan * error clearing for l2cache devices. 25425450Sbrendan */ 25432468Sek110237 if (avail_spare) 25442082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 25452082Seschrock 25462082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 25472082Seschrock &zc.zc_guid) == 0); 25481544Seschrock } 25491544Seschrock 2550*10921STim.Haley@Sun.COM zpool_get_rewind_policy(rewindnvl, &policy); 2551*10921STim.Haley@Sun.COM zc.zc_cookie = policy.zrp_request; 2552*10921STim.Haley@Sun.COM 2553*10921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0) 2554*10921STim.Haley@Sun.COM return (-1); 2555*10921STim.Haley@Sun.COM 2556*10921STim.Haley@Sun.COM if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0) 2557*10921STim.Haley@Sun.COM return (-1); 2558*10921STim.Haley@Sun.COM 2559*10921STim.Haley@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 || 2560*10921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) && 2561*10921STim.Haley@Sun.COM errno != EPERM && errno != EACCES)) { 2562*10921STim.Haley@Sun.COM if (policy.zrp_request & 2563*10921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 2564*10921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 2565*10921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, zc.zc_name, 2566*10921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 2567*10921STim.Haley@Sun.COM nvi); 2568*10921STim.Haley@Sun.COM nvlist_free(nvi); 2569*10921STim.Haley@Sun.COM } 2570*10921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 25711544Seschrock return (0); 2572*10921STim.Haley@Sun.COM } 2573*10921STim.Haley@Sun.COM 2574*10921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 25752082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2576789Sahrens } 2577789Sahrens 25783126Sahl /* 25794451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 25804451Seschrock */ 25814451Seschrock int 25824451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 25834451Seschrock { 25844451Seschrock zfs_cmd_t zc = { 0 }; 25854451Seschrock char msg[1024]; 25864451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 25874451Seschrock 25884451Seschrock (void) snprintf(msg, sizeof (msg), 25894451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 25904451Seschrock guid); 25914451Seschrock 25924451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25934451Seschrock zc.zc_guid = guid; 25944451Seschrock 25954451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 25964451Seschrock return (0); 25974451Seschrock 25984451Seschrock return (zpool_standard_error(hdl, errno, msg)); 25994451Seschrock } 26004451Seschrock 26014451Seschrock /* 26021354Seschrock * Convert from a devid string to a path. 26031354Seschrock */ 26041354Seschrock static char * 26051354Seschrock devid_to_path(char *devid_str) 26061354Seschrock { 26071354Seschrock ddi_devid_t devid; 26081354Seschrock char *minor; 26091354Seschrock char *path; 26101354Seschrock devid_nmlist_t *list = NULL; 26111354Seschrock int ret; 26121354Seschrock 26131354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 26141354Seschrock return (NULL); 26151354Seschrock 26161354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 26171354Seschrock 26181354Seschrock devid_str_free(minor); 26191354Seschrock devid_free(devid); 26201354Seschrock 26211354Seschrock if (ret != 0) 26221354Seschrock return (NULL); 26231354Seschrock 26242082Seschrock if ((path = strdup(list[0].devname)) == NULL) 26252082Seschrock return (NULL); 26262082Seschrock 26271354Seschrock devid_free_nmlist(list); 26281354Seschrock 26291354Seschrock return (path); 26301354Seschrock } 26311354Seschrock 26321354Seschrock /* 26331354Seschrock * Convert from a path to a devid string. 26341354Seschrock */ 26351354Seschrock static char * 26361354Seschrock path_to_devid(const char *path) 26371354Seschrock { 26381354Seschrock int fd; 26391354Seschrock ddi_devid_t devid; 26401354Seschrock char *minor, *ret; 26411354Seschrock 26421354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 26431354Seschrock return (NULL); 26441354Seschrock 26451354Seschrock minor = NULL; 26461354Seschrock ret = NULL; 26471354Seschrock if (devid_get(fd, &devid) == 0) { 26481354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 26491354Seschrock ret = devid_str_encode(devid, minor); 26501354Seschrock if (minor != NULL) 26511354Seschrock devid_str_free(minor); 26521354Seschrock devid_free(devid); 26531354Seschrock } 26541354Seschrock (void) close(fd); 26551354Seschrock 26561354Seschrock return (ret); 26571354Seschrock } 26581354Seschrock 26591354Seschrock /* 26601354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 26611354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 26621354Seschrock * type 'zpool status', and we'll display the correct information anyway. 26631354Seschrock */ 26641354Seschrock static void 26651354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 26661354Seschrock { 26671354Seschrock zfs_cmd_t zc = { 0 }; 26681354Seschrock 26691354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 26702676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 26711354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 26721544Seschrock &zc.zc_guid) == 0); 26731354Seschrock 26742082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 26751354Seschrock } 26761354Seschrock 26771354Seschrock /* 26781354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 26791354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 26801354Seschrock * We also check if this is a whole disk, in which case we strip off the 26811354Seschrock * trailing 's0' slice name. 26821354Seschrock * 26831354Seschrock * This routine is also responsible for identifying when disks have been 26841354Seschrock * reconfigured in a new location. The kernel will have opened the device by 26851354Seschrock * devid, but the path will still refer to the old location. To catch this, we 26861354Seschrock * first do a path -> devid translation (which is fast for the common case). If 26871354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 26881354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 26891354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 26901354Seschrock * of these checks. 26911354Seschrock */ 26921354Seschrock char * 269310594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 269410594SGeorge.Wilson@Sun.COM boolean_t verbose) 26951354Seschrock { 26961354Seschrock char *path, *devid; 26971544Seschrock uint64_t value; 26981544Seschrock char buf[64]; 26994451Seschrock vdev_stat_t *vs; 27004451Seschrock uint_t vsc; 27011354Seschrock 27021544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 27031544Seschrock &value) == 0) { 27041544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 27051544Seschrock &value) == 0); 27062856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 27072856Snd150628 (u_longlong_t)value); 27081544Seschrock path = buf; 27091544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 27101354Seschrock 27114451Seschrock /* 27124451Seschrock * If the device is dead (faulted, offline, etc) then don't 27134451Seschrock * bother opening it. Otherwise we may be forcing the user to 27144451Seschrock * open a misbehaving device, which can have undesirable 27154451Seschrock * effects. 27164451Seschrock */ 27174451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 27184451Seschrock (uint64_t **)&vs, &vsc) != 0 || 27194451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 27204451Seschrock zhp != NULL && 27211354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 27221354Seschrock /* 27231354Seschrock * Determine if the current path is correct. 27241354Seschrock */ 27251354Seschrock char *newdevid = path_to_devid(path); 27261354Seschrock 27271354Seschrock if (newdevid == NULL || 27281354Seschrock strcmp(devid, newdevid) != 0) { 27291354Seschrock char *newpath; 27301354Seschrock 27311354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 27321354Seschrock /* 27331354Seschrock * Update the path appropriately. 27341354Seschrock */ 27351354Seschrock set_path(zhp, nv, newpath); 27362082Seschrock if (nvlist_add_string(nv, 27372082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 27382082Seschrock verify(nvlist_lookup_string(nv, 27392082Seschrock ZPOOL_CONFIG_PATH, 27402082Seschrock &path) == 0); 27411354Seschrock free(newpath); 27421354Seschrock } 27431354Seschrock } 27441354Seschrock 27452082Seschrock if (newdevid) 27462082Seschrock devid_str_free(newdevid); 27471354Seschrock } 27481354Seschrock 27491354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 27501354Seschrock path += 9; 27511354Seschrock 27521354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 27531544Seschrock &value) == 0 && value) { 27542082Seschrock char *tmp = zfs_strdup(hdl, path); 27552082Seschrock if (tmp == NULL) 27562082Seschrock return (NULL); 27571354Seschrock tmp[strlen(path) - 2] = '\0'; 27581354Seschrock return (tmp); 27591354Seschrock } 27601354Seschrock } else { 27611354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 27622082Seschrock 27632082Seschrock /* 27642082Seschrock * If it's a raidz device, we need to stick in the parity level. 27652082Seschrock */ 27662082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 27672082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 27682082Seschrock &value) == 0); 27692082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 27702856Snd150628 (u_longlong_t)value); 27712082Seschrock path = buf; 27722082Seschrock } 277310594SGeorge.Wilson@Sun.COM 277410594SGeorge.Wilson@Sun.COM /* 277510594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 277610594SGeorge.Wilson@Sun.COM * naming convention. 277710594SGeorge.Wilson@Sun.COM */ 277810594SGeorge.Wilson@Sun.COM if (verbose) { 277910594SGeorge.Wilson@Sun.COM uint64_t id; 278010594SGeorge.Wilson@Sun.COM 278110594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 278210594SGeorge.Wilson@Sun.COM &id) == 0); 278310594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 278410594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 278510594SGeorge.Wilson@Sun.COM path = buf; 278610594SGeorge.Wilson@Sun.COM } 27871354Seschrock } 27881354Seschrock 27892082Seschrock return (zfs_strdup(hdl, path)); 27901354Seschrock } 27911544Seschrock 27921544Seschrock static int 27931544Seschrock zbookmark_compare(const void *a, const void *b) 27941544Seschrock { 27951544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 27961544Seschrock } 27971544Seschrock 27981544Seschrock /* 27991544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 28001544Seschrock * caller. 28011544Seschrock */ 28021544Seschrock int 28033444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 28041544Seschrock { 28051544Seschrock zfs_cmd_t zc = { 0 }; 28061544Seschrock uint64_t count; 28072676Seschrock zbookmark_t *zb = NULL; 28083444Sek110237 int i; 28091544Seschrock 28101544Seschrock /* 28111544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 28121544Seschrock * has increased, allocate more space and continue until we get the 28131544Seschrock * entire list. 28141544Seschrock */ 28151544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 28161544Seschrock &count) == 0); 28174820Sek110237 if (count == 0) 28184820Sek110237 return (0); 28192676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 28202856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 28212082Seschrock return (-1); 28222676Seschrock zc.zc_nvlist_dst_size = count; 28231544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 28241544Seschrock for (;;) { 28252082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 28262082Seschrock &zc) != 0) { 28272676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 28281544Seschrock if (errno == ENOMEM) { 28293823Svb160487 count = zc.zc_nvlist_dst_size; 28302676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 28313823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 28323823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 28332082Seschrock return (-1); 28341544Seschrock } else { 28351544Seschrock return (-1); 28361544Seschrock } 28371544Seschrock } else { 28381544Seschrock break; 28391544Seschrock } 28401544Seschrock } 28411544Seschrock 28421544Seschrock /* 28431544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 28441544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 28452676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 28461544Seschrock * _not_ copied as part of the process. So we point the start of our 28471544Seschrock * array appropriate and decrement the total number of elements. 28481544Seschrock */ 28492676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 28502676Seschrock zc.zc_nvlist_dst_size; 28512676Seschrock count -= zc.zc_nvlist_dst_size; 28521544Seschrock 28531544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 28541544Seschrock 28553444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 28561544Seschrock 28571544Seschrock /* 28583444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 28591544Seschrock */ 28601544Seschrock for (i = 0; i < count; i++) { 28611544Seschrock nvlist_t *nv; 28621544Seschrock 28633700Sek110237 /* ignoring zb_blkid and zb_level for now */ 28643700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 28653700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 28661544Seschrock continue; 28671544Seschrock 28683444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 28693444Sek110237 goto nomem; 28703444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 28713444Sek110237 zb[i].zb_objset) != 0) { 28723444Sek110237 nvlist_free(nv); 28732082Seschrock goto nomem; 28743444Sek110237 } 28753444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 28763444Sek110237 zb[i].zb_object) != 0) { 28773444Sek110237 nvlist_free(nv); 28783444Sek110237 goto nomem; 28791544Seschrock } 28803444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 28813444Sek110237 nvlist_free(nv); 28823444Sek110237 goto nomem; 28833444Sek110237 } 28843444Sek110237 nvlist_free(nv); 28851544Seschrock } 28861544Seschrock 28873265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 28881544Seschrock return (0); 28892082Seschrock 28902082Seschrock nomem: 28912676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 28922082Seschrock return (no_memory(zhp->zpool_hdl)); 28931544Seschrock } 28941760Seschrock 28951760Seschrock /* 28961760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 28971760Seschrock */ 28981760Seschrock int 28995094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 29001760Seschrock { 29011760Seschrock zfs_cmd_t zc = { 0 }; 29022082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 29031760Seschrock 29041760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 29055094Slling zc.zc_cookie = new_version; 29065094Slling 29074543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 29083237Slling return (zpool_standard_error_fmt(hdl, errno, 29092082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 29102082Seschrock zhp->zpool_name)); 29111760Seschrock return (0); 29121760Seschrock } 29132926Sek110237 29144988Sek110237 void 29154988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 29164988Sek110237 char *history_str) 29174988Sek110237 { 29184988Sek110237 int i; 29194988Sek110237 29204988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 29214988Sek110237 for (i = 1; i < argc; i++) { 29224988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 29234988Sek110237 HIS_MAX_RECORD_LEN) 29244988Sek110237 break; 29254988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 29264988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 29274988Sek110237 } 29284988Sek110237 } 29294988Sek110237 29302926Sek110237 /* 29314988Sek110237 * Stage command history for logging. 29322926Sek110237 */ 29334988Sek110237 int 29344988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 29352926Sek110237 { 29364988Sek110237 if (history_str == NULL) 29374988Sek110237 return (EINVAL); 29384988Sek110237 29394988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 29404988Sek110237 return (EINVAL); 29412926Sek110237 29424715Sek110237 if (hdl->libzfs_log_str != NULL) 29434543Smarks free(hdl->libzfs_log_str); 29442926Sek110237 29454988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 29464988Sek110237 return (no_memory(hdl)); 29474543Smarks 29484988Sek110237 return (0); 29492926Sek110237 } 29502926Sek110237 29512926Sek110237 /* 29522926Sek110237 * Perform ioctl to get some command history of a pool. 29532926Sek110237 * 29542926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 29552926Sek110237 * logical offset of the history buffer to start reading from. 29562926Sek110237 * 29572926Sek110237 * Upon return, 'off' is the next logical offset to read from and 29582926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 29592926Sek110237 */ 29602926Sek110237 static int 29612926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 29622926Sek110237 { 29632926Sek110237 zfs_cmd_t zc = { 0 }; 29642926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 29652926Sek110237 29662926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29672926Sek110237 29682926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 29692926Sek110237 zc.zc_history_len = *len; 29702926Sek110237 zc.zc_history_offset = *off; 29712926Sek110237 29722926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 29732926Sek110237 switch (errno) { 29742926Sek110237 case EPERM: 29753237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 29763237Slling dgettext(TEXT_DOMAIN, 29772926Sek110237 "cannot show history for pool '%s'"), 29782926Sek110237 zhp->zpool_name)); 29792926Sek110237 case ENOENT: 29803237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 29812926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 29822926Sek110237 "'%s'"), zhp->zpool_name)); 29833863Sek110237 case ENOTSUP: 29843863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 29853863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 29863863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 29872926Sek110237 default: 29883237Slling return (zpool_standard_error_fmt(hdl, errno, 29892926Sek110237 dgettext(TEXT_DOMAIN, 29902926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 29912926Sek110237 } 29922926Sek110237 } 29932926Sek110237 29942926Sek110237 *len = zc.zc_history_len; 29952926Sek110237 *off = zc.zc_history_offset; 29962926Sek110237 29972926Sek110237 return (0); 29982926Sek110237 } 29992926Sek110237 30002926Sek110237 /* 30012926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 30022926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 30032926Sek110237 * processed as there wasn't a complete record. 30042926Sek110237 */ 300510685SGeorge.Wilson@Sun.COM int 30062926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 30072926Sek110237 nvlist_t ***records, uint_t *numrecords) 30082926Sek110237 { 30092926Sek110237 uint64_t reclen; 30102926Sek110237 nvlist_t *nv; 30112926Sek110237 int i; 30122926Sek110237 30132926Sek110237 while (bytes_read > sizeof (reclen)) { 30142926Sek110237 30152926Sek110237 /* get length of packed record (stored as little endian) */ 30162926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 30172926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 30182926Sek110237 30192926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 30202926Sek110237 break; 30212926Sek110237 30222926Sek110237 /* unpack record */ 30232926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 30242926Sek110237 return (ENOMEM); 30252926Sek110237 bytes_read -= sizeof (reclen) + reclen; 30262926Sek110237 buf += sizeof (reclen) + reclen; 30272926Sek110237 30282926Sek110237 /* add record to nvlist array */ 30292926Sek110237 (*numrecords)++; 30302926Sek110237 if (ISP2(*numrecords + 1)) { 30312926Sek110237 *records = realloc(*records, 30322926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 30332926Sek110237 } 30342926Sek110237 (*records)[*numrecords - 1] = nv; 30352926Sek110237 } 30362926Sek110237 30372926Sek110237 *leftover = bytes_read; 30382926Sek110237 return (0); 30392926Sek110237 } 30402926Sek110237 30412926Sek110237 #define HIS_BUF_LEN (128*1024) 30422926Sek110237 30432926Sek110237 /* 30442926Sek110237 * Retrieve the command history of a pool. 30452926Sek110237 */ 30462926Sek110237 int 30472926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 30482926Sek110237 { 30492926Sek110237 char buf[HIS_BUF_LEN]; 30502926Sek110237 uint64_t off = 0; 30512926Sek110237 nvlist_t **records = NULL; 30522926Sek110237 uint_t numrecords = 0; 30532926Sek110237 int err, i; 30542926Sek110237 30552926Sek110237 do { 30562926Sek110237 uint64_t bytes_read = sizeof (buf); 30572926Sek110237 uint64_t leftover; 30582926Sek110237 30592926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 30602926Sek110237 break; 30612926Sek110237 30622926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 30632926Sek110237 if (!bytes_read) 30642926Sek110237 break; 30652926Sek110237 30662926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 30672926Sek110237 &leftover, &records, &numrecords)) != 0) 30682926Sek110237 break; 30692926Sek110237 off -= leftover; 30702926Sek110237 30712926Sek110237 /* CONSTCOND */ 30722926Sek110237 } while (1); 30732926Sek110237 30742926Sek110237 if (!err) { 30752926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 30762926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 30772926Sek110237 records, numrecords) == 0); 30782926Sek110237 } 30792926Sek110237 for (i = 0; i < numrecords; i++) 30802926Sek110237 nvlist_free(records[i]); 30812926Sek110237 free(records); 30822926Sek110237 30832926Sek110237 return (err); 30842926Sek110237 } 30853444Sek110237 30863444Sek110237 void 30873444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 30883444Sek110237 char *pathname, size_t len) 30893444Sek110237 { 30903444Sek110237 zfs_cmd_t zc = { 0 }; 30913444Sek110237 boolean_t mounted = B_FALSE; 30923444Sek110237 char *mntpnt = NULL; 30933444Sek110237 char dsname[MAXNAMELEN]; 30943444Sek110237 30953444Sek110237 if (dsobj == 0) { 30963444Sek110237 /* special case for the MOS */ 30973444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 30983444Sek110237 return; 30993444Sek110237 } 31003444Sek110237 31013444Sek110237 /* get the dataset's name */ 31023444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 31033444Sek110237 zc.zc_obj = dsobj; 31043444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 31053444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 31063444Sek110237 /* just write out a path of two object numbers */ 31073444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 31083444Sek110237 dsobj, obj); 31093444Sek110237 return; 31103444Sek110237 } 31113444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 31123444Sek110237 31133444Sek110237 /* find out if the dataset is mounted */ 31143444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 31153444Sek110237 31163444Sek110237 /* get the corrupted object's path */ 31173444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 31183444Sek110237 zc.zc_obj = obj; 31193444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 31203444Sek110237 &zc) == 0) { 31213444Sek110237 if (mounted) { 31223444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 31233444Sek110237 zc.zc_value); 31243444Sek110237 } else { 31253444Sek110237 (void) snprintf(pathname, len, "%s:%s", 31263444Sek110237 dsname, zc.zc_value); 31273444Sek110237 } 31283444Sek110237 } else { 31293444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 31303444Sek110237 } 31313444Sek110237 free(mntpnt); 31323444Sek110237 } 31333912Slling 31344276Staylor /* 31357042Sgw25295 * Read the EFI label from the config, if a label does not exist then 31367042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 31377042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 31387042Sgw25295 * partition. 31397042Sgw25295 */ 31407042Sgw25295 static int 31417042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 31427042Sgw25295 { 31437042Sgw25295 char *path; 31447042Sgw25295 int fd; 31457042Sgw25295 char diskname[MAXPATHLEN]; 31467042Sgw25295 int err = -1; 31477042Sgw25295 31487042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 31497042Sgw25295 return (err); 31507042Sgw25295 31517042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 31527042Sgw25295 strrchr(path, '/')); 31537042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 31547042Sgw25295 struct dk_gpt *vtoc; 31557042Sgw25295 31567042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 31577042Sgw25295 if (sb != NULL) 31587042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 31597042Sgw25295 efi_free(vtoc); 31607042Sgw25295 } 31617042Sgw25295 (void) close(fd); 31627042Sgw25295 } 31637042Sgw25295 return (err); 31647042Sgw25295 } 31657042Sgw25295 31667042Sgw25295 /* 31674276Staylor * determine where a partition starts on a disk in the current 31684276Staylor * configuration 31694276Staylor */ 31704276Staylor static diskaddr_t 31714276Staylor find_start_block(nvlist_t *config) 31724276Staylor { 31734276Staylor nvlist_t **child; 31744276Staylor uint_t c, children; 31754276Staylor diskaddr_t sb = MAXOFFSET_T; 31764276Staylor uint64_t wholedisk; 31774276Staylor 31784276Staylor if (nvlist_lookup_nvlist_array(config, 31794276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 31804276Staylor if (nvlist_lookup_uint64(config, 31814276Staylor ZPOOL_CONFIG_WHOLE_DISK, 31824276Staylor &wholedisk) != 0 || !wholedisk) { 31834276Staylor return (MAXOFFSET_T); 31844276Staylor } 31857042Sgw25295 if (read_efi_label(config, &sb) < 0) 31867042Sgw25295 sb = MAXOFFSET_T; 31874276Staylor return (sb); 31884276Staylor } 31894276Staylor 31904276Staylor for (c = 0; c < children; c++) { 31914276Staylor sb = find_start_block(child[c]); 31924276Staylor if (sb != MAXOFFSET_T) { 31934276Staylor return (sb); 31944276Staylor } 31954276Staylor } 31964276Staylor return (MAXOFFSET_T); 31974276Staylor } 31984276Staylor 31994276Staylor /* 32004276Staylor * Label an individual disk. The name provided is the short name, 32014276Staylor * stripped of any leading /dev path. 32024276Staylor */ 32034276Staylor int 32044276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 32054276Staylor { 32064276Staylor char path[MAXPATHLEN]; 32074276Staylor struct dk_gpt *vtoc; 32084276Staylor int fd; 32094276Staylor size_t resv = EFI_MIN_RESV_SIZE; 32104276Staylor uint64_t slice_size; 32114276Staylor diskaddr_t start_block; 32124276Staylor char errbuf[1024]; 32134276Staylor 32146289Smmusante /* prepare an error message just in case */ 32156289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 32166289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 32176289Smmusante 32184276Staylor if (zhp) { 32194276Staylor nvlist_t *nvroot; 32204276Staylor 32217965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 32227965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32237965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 32247965SGeorge.Wilson@Sun.COM "pools.")); 32257965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 32267965SGeorge.Wilson@Sun.COM } 32277965SGeorge.Wilson@Sun.COM 32284276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 32294276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 32304276Staylor 32314276Staylor if (zhp->zpool_start_block == 0) 32324276Staylor start_block = find_start_block(nvroot); 32334276Staylor else 32344276Staylor start_block = zhp->zpool_start_block; 32354276Staylor zhp->zpool_start_block = start_block; 32364276Staylor } else { 32374276Staylor /* new pool */ 32384276Staylor start_block = NEW_START_BLOCK; 32394276Staylor } 32404276Staylor 32414276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 32424276Staylor BACKUP_SLICE); 32434276Staylor 32444276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 32454276Staylor /* 32464276Staylor * This shouldn't happen. We've long since verified that this 32474276Staylor * is a valid device. 32484276Staylor */ 32496289Smmusante zfs_error_aux(hdl, 32506289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 32514276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 32524276Staylor } 32534276Staylor 32544276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 32554276Staylor /* 32564276Staylor * The only way this can fail is if we run out of memory, or we 32574276Staylor * were unable to read the disk's capacity 32584276Staylor */ 32594276Staylor if (errno == ENOMEM) 32604276Staylor (void) no_memory(hdl); 32614276Staylor 32624276Staylor (void) close(fd); 32636289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32646289Smmusante "unable to read disk capacity"), name); 32654276Staylor 32664276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 32674276Staylor } 32684276Staylor 32694276Staylor slice_size = vtoc->efi_last_u_lba + 1; 32704276Staylor slice_size -= EFI_MIN_RESV_SIZE; 32714276Staylor if (start_block == MAXOFFSET_T) 32724276Staylor start_block = NEW_START_BLOCK; 32734276Staylor slice_size -= start_block; 32744276Staylor 32754276Staylor vtoc->efi_parts[0].p_start = start_block; 32764276Staylor vtoc->efi_parts[0].p_size = slice_size; 32774276Staylor 32784276Staylor /* 32794276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 32804276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 32814276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 32824276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 32834276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 32844276Staylor * can get, in the absence of V_OTHER. 32854276Staylor */ 32864276Staylor vtoc->efi_parts[0].p_tag = V_USR; 32874276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 32884276Staylor 32894276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 32904276Staylor vtoc->efi_parts[8].p_size = resv; 32914276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 32924276Staylor 32934276Staylor if (efi_write(fd, vtoc) != 0) { 32944276Staylor /* 32954276Staylor * Some block drivers (like pcata) may not support EFI 32964276Staylor * GPT labels. Print out a helpful error message dir- 32974276Staylor * ecting the user to manually label the disk and give 32984276Staylor * a specific slice. 32994276Staylor */ 33004276Staylor (void) close(fd); 33014276Staylor efi_free(vtoc); 33024276Staylor 33034276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33046289Smmusante "try using fdisk(1M) and then provide a specific slice")); 33054276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 33064276Staylor } 33074276Staylor 33084276Staylor (void) close(fd); 33094276Staylor efi_free(vtoc); 33104276Staylor return (0); 33114276Staylor } 33126423Sgw25295 33136423Sgw25295 static boolean_t 33146423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 33156423Sgw25295 { 33166423Sgw25295 char *type; 33176423Sgw25295 nvlist_t **child; 33186423Sgw25295 uint_t children, c; 33196423Sgw25295 33206423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 33216423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 33226423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 33236423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 332410594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 33256423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 33266423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33276423Sgw25295 "vdev type '%s' is not supported"), type); 33286423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 33296423Sgw25295 return (B_FALSE); 33306423Sgw25295 } 33316423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 33326423Sgw25295 &child, &children) == 0) { 33336423Sgw25295 for (c = 0; c < children; c++) { 33346423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 33356423Sgw25295 return (B_FALSE); 33366423Sgw25295 } 33376423Sgw25295 } 33386423Sgw25295 return (B_TRUE); 33396423Sgw25295 } 33406423Sgw25295 33416423Sgw25295 /* 33426423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 33436423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 33446423Sgw25295 */ 33456423Sgw25295 int 33466423Sgw25295 zvol_check_dump_config(char *arg) 33476423Sgw25295 { 33486423Sgw25295 zpool_handle_t *zhp = NULL; 33496423Sgw25295 nvlist_t *config, *nvroot; 33506423Sgw25295 char *p, *volname; 33516423Sgw25295 nvlist_t **top; 33526423Sgw25295 uint_t toplevels; 33536423Sgw25295 libzfs_handle_t *hdl; 33546423Sgw25295 char errbuf[1024]; 33556423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 33566423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 33576423Sgw25295 int ret = 1; 33586423Sgw25295 33596423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 33606423Sgw25295 return (-1); 33616423Sgw25295 } 33626423Sgw25295 33636423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 33646423Sgw25295 "dump is not supported on device '%s'"), arg); 33656423Sgw25295 33666423Sgw25295 if ((hdl = libzfs_init()) == NULL) 33676423Sgw25295 return (1); 33686423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 33696423Sgw25295 33706423Sgw25295 volname = arg + pathlen; 33716423Sgw25295 33726423Sgw25295 /* check the configuration of the pool */ 33736423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 33746423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33756423Sgw25295 "malformed dataset name")); 33766423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 33776423Sgw25295 return (1); 33786423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 33796423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33806423Sgw25295 "dataset name is too long")); 33816423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 33826423Sgw25295 return (1); 33836423Sgw25295 } else { 33846423Sgw25295 (void) strncpy(poolname, volname, p - volname); 33856423Sgw25295 poolname[p - volname] = '\0'; 33866423Sgw25295 } 33876423Sgw25295 33886423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 33896423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33906423Sgw25295 "could not open pool '%s'"), poolname); 33916423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 33926423Sgw25295 goto out; 33936423Sgw25295 } 33946423Sgw25295 config = zpool_get_config(zhp, NULL); 33956423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 33966423Sgw25295 &nvroot) != 0) { 33976423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33986423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 33996423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 34006423Sgw25295 goto out; 34016423Sgw25295 } 34026423Sgw25295 34036423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 34046423Sgw25295 &top, &toplevels) == 0); 34056423Sgw25295 if (toplevels != 1) { 34066423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34076423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 34086423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 34096423Sgw25295 goto out; 34106423Sgw25295 } 34116423Sgw25295 34126423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 34136423Sgw25295 goto out; 34146423Sgw25295 } 34156423Sgw25295 ret = 0; 34166423Sgw25295 34176423Sgw25295 out: 34186423Sgw25295 if (zhp) 34196423Sgw25295 zpool_close(zhp); 34206423Sgw25295 libzfs_fini(hdl); 34216423Sgw25295 return (ret); 34226423Sgw25295 } 3423