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 /* 2312296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <ctype.h> 27789Sahrens #include <errno.h> 28789Sahrens #include <devid.h> 29789Sahrens #include <fcntl.h> 30789Sahrens #include <libintl.h> 31789Sahrens #include <stdio.h> 32789Sahrens #include <stdlib.h> 333126Sahl #include <strings.h> 34789Sahrens #include <unistd.h> 354276Staylor #include <sys/efi_partition.h> 364276Staylor #include <sys/vtoc.h> 37789Sahrens #include <sys/zfs_ioctl.h> 389816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 39789Sahrens 40789Sahrens #include "zfs_namecheck.h" 413912Slling #include "zfs_prop.h" 42789Sahrens #include "libzfs_impl.h" 4310921STim.Haley@Sun.COM #include "zfs_comutil.h" 44789Sahrens 457042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 465094Slling 479816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 489816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 499816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 509816SGeorge.Wilson@Sun.COM 51*13049SGeorge.Wilson@Sun.COM typedef struct prop_flags { 52*13049SGeorge.Wilson@Sun.COM int create:1; /* Validate property on creation */ 53*13049SGeorge.Wilson@Sun.COM int import:1; /* Validate property on import */ 54*13049SGeorge.Wilson@Sun.COM } prop_flags_t; 55*13049SGeorge.Wilson@Sun.COM 565094Slling /* 575094Slling * ==================================================================== 585094Slling * zpool property functions 595094Slling * ==================================================================== 605094Slling */ 615094Slling 625094Slling static int 635094Slling zpool_get_all_props(zpool_handle_t *zhp) 645094Slling { 655094Slling zfs_cmd_t zc = { 0 }; 665094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 675094Slling 685094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 695094Slling 705094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 715094Slling return (-1); 725094Slling 735094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 745094Slling if (errno == ENOMEM) { 755094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 765094Slling zcmd_free_nvlists(&zc); 775094Slling return (-1); 785094Slling } 795094Slling } else { 805094Slling zcmd_free_nvlists(&zc); 815094Slling return (-1); 825094Slling } 835094Slling } 845094Slling 855094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 865094Slling zcmd_free_nvlists(&zc); 875094Slling return (-1); 885094Slling } 895094Slling 905094Slling zcmd_free_nvlists(&zc); 915094Slling 925094Slling return (0); 935094Slling } 945094Slling 955094Slling static int 965094Slling zpool_props_refresh(zpool_handle_t *zhp) 975094Slling { 985094Slling nvlist_t *old_props; 995094Slling 1005094Slling old_props = zhp->zpool_props; 1015094Slling 1025094Slling if (zpool_get_all_props(zhp) != 0) 1035094Slling return (-1); 1045094Slling 1055094Slling nvlist_free(old_props); 1065094Slling return (0); 1075094Slling } 1085094Slling 1095094Slling static char * 1105094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1115094Slling zprop_source_t *src) 1125094Slling { 1135094Slling nvlist_t *nv, *nvl; 1145094Slling uint64_t ival; 1155094Slling char *value; 1165094Slling zprop_source_t source; 1175094Slling 1185094Slling nvl = zhp->zpool_props; 1195094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1205094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1215094Slling source = ival; 1225094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1235094Slling } else { 1245094Slling source = ZPROP_SRC_DEFAULT; 1255094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1265094Slling value = "-"; 1275094Slling } 1285094Slling 1295094Slling if (src) 1305094Slling *src = source; 1315094Slling 1325094Slling return (value); 1335094Slling } 1345094Slling 1355094Slling uint64_t 1365094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1375094Slling { 1385094Slling nvlist_t *nv, *nvl; 1395094Slling uint64_t value; 1405094Slling zprop_source_t source; 1415094Slling 1427294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1437294Sperrin /* 1447294Sperrin * zpool_get_all_props() has most likely failed because 1457294Sperrin * the pool is faulted, but if all we need is the top level 1467294Sperrin * vdev's guid then get it from the zhp config nvlist. 1477294Sperrin */ 1487294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1497294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1507294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1517294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1527294Sperrin == 0)) { 1537294Sperrin return (value); 1547294Sperrin } 1555094Slling return (zpool_prop_default_numeric(prop)); 1567294Sperrin } 1575094Slling 1585094Slling nvl = zhp->zpool_props; 1595094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1605094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 1615094Slling source = value; 1625094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1635094Slling } else { 1645094Slling source = ZPROP_SRC_DEFAULT; 1655094Slling value = zpool_prop_default_numeric(prop); 1665094Slling } 1675094Slling 1685094Slling if (src) 1695094Slling *src = source; 1705094Slling 1715094Slling return (value); 1725094Slling } 1735094Slling 1745094Slling /* 1755094Slling * Map VDEV STATE to printed strings. 1765094Slling */ 1775094Slling char * 1785094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 1795094Slling { 1805094Slling switch (state) { 1815094Slling case VDEV_STATE_CLOSED: 1825094Slling case VDEV_STATE_OFFLINE: 1835094Slling return (gettext("OFFLINE")); 1845094Slling case VDEV_STATE_REMOVED: 1855094Slling return (gettext("REMOVED")); 1865094Slling case VDEV_STATE_CANT_OPEN: 1877294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 1885094Slling return (gettext("FAULTED")); 18911422SMark.Musante@Sun.COM else if (aux == VDEV_AUX_SPLIT_POOL) 19011422SMark.Musante@Sun.COM return (gettext("SPLIT")); 1915094Slling else 1925094Slling return (gettext("UNAVAIL")); 1935094Slling case VDEV_STATE_FAULTED: 1945094Slling return (gettext("FAULTED")); 1955094Slling case VDEV_STATE_DEGRADED: 1965094Slling return (gettext("DEGRADED")); 1975094Slling case VDEV_STATE_HEALTHY: 1985094Slling return (gettext("ONLINE")); 1995094Slling } 2005094Slling 2015094Slling return (gettext("UNKNOWN")); 2025094Slling } 2035094Slling 2045094Slling /* 2055094Slling * Get a zpool property value for 'prop' and return the value in 2065094Slling * a pre-allocated buffer. 2075094Slling */ 2085094Slling int 2095094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2105094Slling zprop_source_t *srctype) 2115094Slling { 2125094Slling uint64_t intval; 2135094Slling const char *strval; 2145094Slling zprop_source_t src = ZPROP_SRC_NONE; 2155094Slling nvlist_t *nvroot; 2165094Slling vdev_stat_t *vs; 2175094Slling uint_t vsc; 2185094Slling 2195094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2208525SEric.Schrock@Sun.COM switch (prop) { 2218525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2225094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2238525SEric.Schrock@Sun.COM break; 2248525SEric.Schrock@Sun.COM 2258525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2265094Slling (void) strlcpy(buf, "FAULTED", len); 2278525SEric.Schrock@Sun.COM break; 2288525SEric.Schrock@Sun.COM 2298525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2308525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2318525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2328525SEric.Schrock@Sun.COM break; 2338525SEric.Schrock@Sun.COM 2348525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2358525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2368525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2378525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2388525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2398525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2408525SEric.Schrock@Sun.COM len); 2418525SEric.Schrock@Sun.COM if (srctype != NULL) 2428525SEric.Schrock@Sun.COM *srctype = src; 2438525SEric.Schrock@Sun.COM return (0); 2448525SEric.Schrock@Sun.COM } 2458525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2468525SEric.Schrock@Sun.COM default: 2475094Slling (void) strlcpy(buf, "-", len); 2488525SEric.Schrock@Sun.COM break; 2498525SEric.Schrock@Sun.COM } 2508525SEric.Schrock@Sun.COM 2518525SEric.Schrock@Sun.COM if (srctype != NULL) 2528525SEric.Schrock@Sun.COM *srctype = src; 2535094Slling return (0); 2545094Slling } 2555094Slling 2565094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2575094Slling prop != ZPOOL_PROP_NAME) 2585094Slling return (-1); 2595094Slling 2605094Slling switch (zpool_prop_get_type(prop)) { 2615094Slling case PROP_TYPE_STRING: 2625094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 2635094Slling len); 2645094Slling break; 2655094Slling 2665094Slling case PROP_TYPE_NUMBER: 2675094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2685094Slling 2695094Slling switch (prop) { 2705094Slling case ZPOOL_PROP_SIZE: 27110956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_ALLOCATED: 27210956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_FREE: 2735094Slling (void) zfs_nicenum(intval, buf, len); 2745094Slling break; 2755094Slling 2765094Slling case ZPOOL_PROP_CAPACITY: 2775094Slling (void) snprintf(buf, len, "%llu%%", 2785094Slling (u_longlong_t)intval); 2795094Slling break; 2805094Slling 28110922SJeff.Bonwick@Sun.COM case ZPOOL_PROP_DEDUPRATIO: 28210922SJeff.Bonwick@Sun.COM (void) snprintf(buf, len, "%llu.%02llux", 28310922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval / 100), 28410922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval % 100)); 28510922SJeff.Bonwick@Sun.COM break; 28610922SJeff.Bonwick@Sun.COM 2875094Slling case ZPOOL_PROP_HEALTH: 2885094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 2895094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2905094Slling verify(nvlist_lookup_uint64_array(nvroot, 29112296SLin.Ling@Sun.COM ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) 29212296SLin.Ling@Sun.COM == 0); 2935094Slling 2945094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 2955094Slling vs->vs_aux), len); 2965094Slling break; 2975094Slling default: 2985094Slling (void) snprintf(buf, len, "%llu", intval); 2995094Slling } 3005094Slling break; 3015094Slling 3025094Slling case PROP_TYPE_INDEX: 3035094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3045094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3055094Slling != 0) 3065094Slling return (-1); 3075094Slling (void) strlcpy(buf, strval, len); 3085094Slling break; 3095094Slling 3105094Slling default: 3115094Slling abort(); 3125094Slling } 3135094Slling 3145094Slling if (srctype) 3155094Slling *srctype = src; 3165094Slling 3175094Slling return (0); 3185094Slling } 3195094Slling 3205094Slling /* 3215094Slling * Check if the bootfs name has the same pool name as it is set to. 3225094Slling * Assuming bootfs is a valid dataset name. 3235094Slling */ 3245094Slling static boolean_t 3255094Slling bootfs_name_valid(const char *pool, char *bootfs) 3265094Slling { 3275094Slling int len = strlen(pool); 3285094Slling 3297300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3305094Slling return (B_FALSE); 3315094Slling 3325094Slling if (strncmp(pool, bootfs, len) == 0 && 3335094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3345094Slling return (B_TRUE); 3355094Slling 3365094Slling return (B_FALSE); 3375094Slling } 3385094Slling 3395094Slling /* 3407042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3417042Sgw25295 * an EFI label. 3427042Sgw25295 */ 3437042Sgw25295 static boolean_t 3447042Sgw25295 pool_uses_efi(nvlist_t *config) 3457042Sgw25295 { 3467042Sgw25295 nvlist_t **child; 3477042Sgw25295 uint_t c, children; 3487042Sgw25295 3497042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3507042Sgw25295 &child, &children) != 0) 3517042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3527042Sgw25295 3537042Sgw25295 for (c = 0; c < children; c++) { 3547042Sgw25295 if (pool_uses_efi(child[c])) 3557042Sgw25295 return (B_TRUE); 3567042Sgw25295 } 3577042Sgw25295 return (B_FALSE); 3587042Sgw25295 } 3597042Sgw25295 3607965SGeorge.Wilson@Sun.COM static boolean_t 3617965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3627965SGeorge.Wilson@Sun.COM { 3637965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3647965SGeorge.Wilson@Sun.COM 3657965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 3667965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 3677965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 3687965SGeorge.Wilson@Sun.COM } 3697965SGeorge.Wilson@Sun.COM 3707965SGeorge.Wilson@Sun.COM 3717042Sgw25295 /* 3725094Slling * Given an nvlist of zpool properties to be set, validate that they are 3735094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 3745094Slling * specified as strings. 3755094Slling */ 3765094Slling static nvlist_t * 3777184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 378*13049SGeorge.Wilson@Sun.COM nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf) 3795094Slling { 3805094Slling nvpair_t *elem; 3815094Slling nvlist_t *retprops; 3825094Slling zpool_prop_t prop; 3835094Slling char *strval; 3845094Slling uint64_t intval; 3855363Seschrock char *slash; 3865363Seschrock struct stat64 statbuf; 3877042Sgw25295 zpool_handle_t *zhp; 3887042Sgw25295 nvlist_t *nvroot; 3895094Slling 3905094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 3915094Slling (void) no_memory(hdl); 3925094Slling return (NULL); 3935094Slling } 3945094Slling 3955094Slling elem = NULL; 3965094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 3975094Slling const char *propname = nvpair_name(elem); 3985094Slling 3995094Slling /* 4005094Slling * Make sure this property is valid and applies to this type. 4015094Slling */ 4025094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4035094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4045094Slling "invalid property '%s'"), propname); 4055094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4065094Slling goto error; 4075094Slling } 4085094Slling 4095094Slling if (zpool_prop_readonly(prop)) { 4105094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4115094Slling "is readonly"), propname); 4125094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4135094Slling goto error; 4145094Slling } 4155094Slling 4165094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4175094Slling &strval, &intval, errbuf) != 0) 4185094Slling goto error; 4195094Slling 4205094Slling /* 4215094Slling * Perform additional checking for specific properties. 4225094Slling */ 4235094Slling switch (prop) { 4245094Slling case ZPOOL_PROP_VERSION: 4255094Slling if (intval < version || intval > SPA_VERSION) { 4265094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4275094Slling "property '%s' number %d is invalid."), 4285094Slling propname, intval); 4295094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4305094Slling goto error; 4315094Slling } 4325094Slling break; 4335094Slling 4345094Slling case ZPOOL_PROP_BOOTFS: 435*13049SGeorge.Wilson@Sun.COM if (flags.create || flags.import) { 4365094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4375094Slling "property '%s' cannot be set at creation " 4385094Slling "or import time"), propname); 4395094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4405094Slling goto error; 4415094Slling } 4425094Slling 4435094Slling if (version < SPA_VERSION_BOOTFS) { 4445094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4455094Slling "pool must be upgraded to support " 4465094Slling "'%s' property"), propname); 4475094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4485094Slling goto error; 4495094Slling } 4505094Slling 4515094Slling /* 4525094Slling * bootfs property value has to be a dataset name and 4535094Slling * the dataset has to be in the same pool as it sets to. 4545094Slling */ 4555094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4565094Slling strval)) { 4575094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4585094Slling "is an invalid name"), strval); 4595094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4605094Slling goto error; 4615094Slling } 4627042Sgw25295 4637042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4647042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4657042Sgw25295 "could not open pool '%s'"), poolname); 4667042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4677042Sgw25295 goto error; 4687042Sgw25295 } 4697042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 4707042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 4717042Sgw25295 4727042Sgw25295 /* 4737042Sgw25295 * bootfs property cannot be set on a disk which has 4747042Sgw25295 * been EFI labeled. 4757042Sgw25295 */ 4767042Sgw25295 if (pool_uses_efi(nvroot)) { 4777042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4787042Sgw25295 "property '%s' not supported on " 4797042Sgw25295 "EFI labeled devices"), propname); 4807042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 4817042Sgw25295 zpool_close(zhp); 4827042Sgw25295 goto error; 4837042Sgw25295 } 4847042Sgw25295 zpool_close(zhp); 4855094Slling break; 4865094Slling 4875094Slling case ZPOOL_PROP_ALTROOT: 488*13049SGeorge.Wilson@Sun.COM if (!flags.create && !flags.import) { 4895094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4905094Slling "property '%s' can only be set during pool " 4915094Slling "creation or import"), propname); 4925094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4935094Slling goto error; 4945094Slling } 4955094Slling 4965094Slling if (strval[0] != '/') { 4975094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4985094Slling "bad alternate root '%s'"), strval); 4995094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5005094Slling goto error; 5015094Slling } 5025094Slling break; 5035363Seschrock 5045363Seschrock case ZPOOL_PROP_CACHEFILE: 5055363Seschrock if (strval[0] == '\0') 5065363Seschrock break; 5075363Seschrock 5085363Seschrock if (strcmp(strval, "none") == 0) 5095363Seschrock break; 5105363Seschrock 5115363Seschrock if (strval[0] != '/') { 5125363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5135363Seschrock "property '%s' must be empty, an " 5145363Seschrock "absolute path, or 'none'"), propname); 5155363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5165363Seschrock goto error; 5175363Seschrock } 5185363Seschrock 5195363Seschrock slash = strrchr(strval, '/'); 5205363Seschrock 5215363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5225363Seschrock strcmp(slash, "/..") == 0) { 5235363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5245363Seschrock "'%s' is not a valid file"), strval); 5255363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5265363Seschrock goto error; 5275363Seschrock } 5285363Seschrock 5295363Seschrock *slash = '\0'; 5305363Seschrock 5315621Seschrock if (strval[0] != '\0' && 5325621Seschrock (stat64(strval, &statbuf) != 0 || 5335621Seschrock !S_ISDIR(statbuf.st_mode))) { 5345363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5355363Seschrock "'%s' is not a valid directory"), 5365363Seschrock strval); 5375363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5385363Seschrock goto error; 5395363Seschrock } 5405363Seschrock 5415363Seschrock *slash = '/'; 5425363Seschrock break; 543*13049SGeorge.Wilson@Sun.COM 544*13049SGeorge.Wilson@Sun.COM case ZPOOL_PROP_READONLY: 545*13049SGeorge.Wilson@Sun.COM if (!flags.import) { 546*13049SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 547*13049SGeorge.Wilson@Sun.COM "property '%s' can only be set at " 548*13049SGeorge.Wilson@Sun.COM "import time"), propname); 549*13049SGeorge.Wilson@Sun.COM (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 550*13049SGeorge.Wilson@Sun.COM goto error; 551*13049SGeorge.Wilson@Sun.COM } 552*13049SGeorge.Wilson@Sun.COM break; 5535094Slling } 5545094Slling } 5555094Slling 5565094Slling return (retprops); 5575094Slling error: 5585094Slling nvlist_free(retprops); 5595094Slling return (NULL); 5605094Slling } 5615094Slling 5625094Slling /* 5635094Slling * Set zpool property : propname=propval. 5645094Slling */ 5655094Slling int 5665094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5675094Slling { 5685094Slling zfs_cmd_t zc = { 0 }; 5695094Slling int ret = -1; 5705094Slling char errbuf[1024]; 5715094Slling nvlist_t *nvl = NULL; 5725094Slling nvlist_t *realprops; 5735094Slling uint64_t version; 574*13049SGeorge.Wilson@Sun.COM prop_flags_t flags = { 0 }; 5755094Slling 5765094Slling (void) snprintf(errbuf, sizeof (errbuf), 5775094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 5785094Slling zhp->zpool_name); 5795094Slling 5805094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5815094Slling return (no_memory(zhp->zpool_hdl)); 5825094Slling 5835094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 5845094Slling nvlist_free(nvl); 5855094Slling return (no_memory(zhp->zpool_hdl)); 5865094Slling } 5875094Slling 5885094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5897184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 590*13049SGeorge.Wilson@Sun.COM zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) { 5915094Slling nvlist_free(nvl); 5925094Slling return (-1); 5935094Slling } 5945094Slling 5955094Slling nvlist_free(nvl); 5965094Slling nvl = realprops; 5975094Slling 5985094Slling /* 5995094Slling * Execute the corresponding ioctl() to set this property. 6005094Slling */ 6015094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 6025094Slling 6035094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 6045094Slling nvlist_free(nvl); 6055094Slling return (-1); 6065094Slling } 6075094Slling 6085094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 6095094Slling 6105094Slling zcmd_free_nvlists(&zc); 6115094Slling nvlist_free(nvl); 6125094Slling 6135094Slling if (ret) 6145094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6155094Slling else 6165094Slling (void) zpool_props_refresh(zhp); 6175094Slling 6185094Slling return (ret); 6195094Slling } 6205094Slling 6215094Slling int 6225094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6235094Slling { 6245094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6255094Slling zprop_list_t *entry; 6265094Slling char buf[ZFS_MAXPROPLEN]; 6275094Slling 6285094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6295094Slling return (-1); 6305094Slling 6315094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6325094Slling 6335094Slling if (entry->pl_fixed) 6345094Slling continue; 6355094Slling 6365094Slling if (entry->pl_prop != ZPROP_INVAL && 6375094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6385094Slling NULL) == 0) { 6395094Slling if (strlen(buf) > entry->pl_width) 6405094Slling entry->pl_width = strlen(buf); 6415094Slling } 6425094Slling } 6435094Slling 6445094Slling return (0); 6455094Slling } 6465094Slling 6475094Slling 648789Sahrens /* 6499816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6509816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6519816SGeorge.Wilson@Sun.COM */ 6529816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6539816SGeorge.Wilson@Sun.COM 6549816SGeorge.Wilson@Sun.COM /* 655789Sahrens * Validate the given pool name, optionally putting an extended error message in 656789Sahrens * 'buf'. 657789Sahrens */ 6586423Sgw25295 boolean_t 6592082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 660789Sahrens { 661789Sahrens namecheck_err_t why; 662789Sahrens char what; 6631773Seschrock int ret; 664789Sahrens 6651773Seschrock ret = pool_namecheck(pool, &why, &what); 6661773Seschrock 6671773Seschrock /* 6681773Seschrock * The rules for reserved pool names were extended at a later point. 6691773Seschrock * But we need to support users with existing pools that may now be 6701773Seschrock * invalid. So we only check for this expanded set of names during a 6711773Seschrock * create (or import), and only in userland. 6721773Seschrock */ 6731773Seschrock if (ret == 0 && !isopen && 6741773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6751773Seschrock strncmp(pool, "raidz", 5) == 0 || 6764527Sperrin strncmp(pool, "spare", 5) == 0 || 6774527Sperrin strcmp(pool, "log") == 0)) { 6786423Sgw25295 if (hdl != NULL) 6796423Sgw25295 zfs_error_aux(hdl, 6806423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 6812082Seschrock return (B_FALSE); 6821773Seschrock } 6831773Seschrock 6841773Seschrock 6851773Seschrock if (ret != 0) { 6862082Seschrock if (hdl != NULL) { 687789Sahrens switch (why) { 6881003Slling case NAME_ERR_TOOLONG: 6892082Seschrock zfs_error_aux(hdl, 6901003Slling dgettext(TEXT_DOMAIN, "name is too long")); 6911003Slling break; 6921003Slling 693789Sahrens case NAME_ERR_INVALCHAR: 6942082Seschrock zfs_error_aux(hdl, 695789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 696789Sahrens "'%c' in pool name"), what); 697789Sahrens break; 698789Sahrens 699789Sahrens case NAME_ERR_NOLETTER: 7002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7012082Seschrock "name must begin with a letter")); 702789Sahrens break; 703789Sahrens 704789Sahrens case NAME_ERR_RESERVED: 7052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7062082Seschrock "name is reserved")); 707789Sahrens break; 708789Sahrens 709789Sahrens case NAME_ERR_DISKLIKE: 7102082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7112082Seschrock "pool name is reserved")); 712789Sahrens break; 7132856Snd150628 7142856Snd150628 case NAME_ERR_LEADING_SLASH: 7152856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7162856Snd150628 "leading slash in name")); 7172856Snd150628 break; 7182856Snd150628 7192856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7202856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7212856Snd150628 "empty component in name")); 7222856Snd150628 break; 7232856Snd150628 7242856Snd150628 case NAME_ERR_TRAILING_SLASH: 7252856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7262856Snd150628 "trailing slash in name")); 7272856Snd150628 break; 7282856Snd150628 7292856Snd150628 case NAME_ERR_MULTIPLE_AT: 7302856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7312856Snd150628 "multiple '@' delimiters in name")); 7322856Snd150628 break; 7332856Snd150628 734789Sahrens } 735789Sahrens } 7362082Seschrock return (B_FALSE); 737789Sahrens } 738789Sahrens 7392082Seschrock return (B_TRUE); 740789Sahrens } 741789Sahrens 742789Sahrens /* 743789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 744789Sahrens * state. 745789Sahrens */ 746789Sahrens zpool_handle_t * 7472082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 748789Sahrens { 749789Sahrens zpool_handle_t *zhp; 7502142Seschrock boolean_t missing; 751789Sahrens 752789Sahrens /* 753789Sahrens * Make sure the pool name is valid. 754789Sahrens */ 7552082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7563237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7572082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7582082Seschrock pool); 759789Sahrens return (NULL); 760789Sahrens } 761789Sahrens 7622082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7632082Seschrock return (NULL); 764789Sahrens 7652082Seschrock zhp->zpool_hdl = hdl; 766789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 767789Sahrens 7682142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7692142Seschrock zpool_close(zhp); 7702142Seschrock return (NULL); 7712142Seschrock } 7722142Seschrock 7732142Seschrock if (missing) { 7745094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7753237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 7765094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 7772142Seschrock zpool_close(zhp); 7782142Seschrock return (NULL); 779789Sahrens } 780789Sahrens 781789Sahrens return (zhp); 782789Sahrens } 783789Sahrens 784789Sahrens /* 785789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 786789Sahrens * the configuration cache may be out of date). 787789Sahrens */ 7882142Seschrock int 7892142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 790789Sahrens { 791789Sahrens zpool_handle_t *zhp; 7922142Seschrock boolean_t missing; 793789Sahrens 7942142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7952142Seschrock return (-1); 796789Sahrens 7972082Seschrock zhp->zpool_hdl = hdl; 798789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 799789Sahrens 8002142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 8012142Seschrock zpool_close(zhp); 8022142Seschrock return (-1); 803789Sahrens } 804789Sahrens 8052142Seschrock if (missing) { 8062142Seschrock zpool_close(zhp); 8072142Seschrock *ret = NULL; 8082142Seschrock return (0); 8092142Seschrock } 8102142Seschrock 8112142Seschrock *ret = zhp; 8122142Seschrock return (0); 813789Sahrens } 814789Sahrens 815789Sahrens /* 816789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 817789Sahrens * state. 818789Sahrens */ 819789Sahrens zpool_handle_t * 8202082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 821789Sahrens { 822789Sahrens zpool_handle_t *zhp; 823789Sahrens 8242082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 825789Sahrens return (NULL); 826789Sahrens 827789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8283237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8292082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 830789Sahrens zpool_close(zhp); 831789Sahrens return (NULL); 832789Sahrens } 833789Sahrens 834789Sahrens return (zhp); 835789Sahrens } 836789Sahrens 837789Sahrens /* 838789Sahrens * Close the handle. Simply frees the memory associated with the handle. 839789Sahrens */ 840789Sahrens void 841789Sahrens zpool_close(zpool_handle_t *zhp) 842789Sahrens { 843789Sahrens if (zhp->zpool_config) 844789Sahrens nvlist_free(zhp->zpool_config); 845952Seschrock if (zhp->zpool_old_config) 846952Seschrock nvlist_free(zhp->zpool_old_config); 8473912Slling if (zhp->zpool_props) 8483912Slling nvlist_free(zhp->zpool_props); 849789Sahrens free(zhp); 850789Sahrens } 851789Sahrens 852789Sahrens /* 853789Sahrens * Return the name of the pool. 854789Sahrens */ 855789Sahrens const char * 856789Sahrens zpool_get_name(zpool_handle_t *zhp) 857789Sahrens { 858789Sahrens return (zhp->zpool_name); 859789Sahrens } 860789Sahrens 861789Sahrens 862789Sahrens /* 863789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 864789Sahrens */ 865789Sahrens int 866789Sahrens zpool_get_state(zpool_handle_t *zhp) 867789Sahrens { 868789Sahrens return (zhp->zpool_state); 869789Sahrens } 870789Sahrens 871789Sahrens /* 872789Sahrens * Create the named pool, using the provided vdev list. It is assumed 873789Sahrens * that the consumer has already validated the contents of the nvlist, so we 874789Sahrens * don't have to worry about error semantics. 875789Sahrens */ 876789Sahrens int 8772082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8787184Stimh nvlist_t *props, nvlist_t *fsprops) 879789Sahrens { 880789Sahrens zfs_cmd_t zc = { 0 }; 8817184Stimh nvlist_t *zc_fsprops = NULL; 8827184Stimh nvlist_t *zc_props = NULL; 8832082Seschrock char msg[1024]; 8845094Slling char *altroot; 8857184Stimh int ret = -1; 8862082Seschrock 8872082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 8882082Seschrock "cannot create '%s'"), pool); 889789Sahrens 8902082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 8912082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 8922082Seschrock 8935320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 8945320Slling return (-1); 8955320Slling 8967184Stimh if (props) { 897*13049SGeorge.Wilson@Sun.COM prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE }; 898*13049SGeorge.Wilson@Sun.COM 8997184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 900*13049SGeorge.Wilson@Sun.COM SPA_VERSION_1, flags, msg)) == NULL) { 9017184Stimh goto create_failed; 9027184Stimh } 9035320Slling } 904789Sahrens 9057184Stimh if (fsprops) { 9067184Stimh uint64_t zoned; 9077184Stimh char *zonestr; 9087184Stimh 9097184Stimh zoned = ((nvlist_lookup_string(fsprops, 9107184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 9117184Stimh strcmp(zonestr, "on") == 0); 9127184Stimh 9137184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9147184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9157184Stimh goto create_failed; 9167184Stimh } 9177184Stimh if (!zc_props && 9187184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9197184Stimh goto create_failed; 9207184Stimh } 9217184Stimh if (nvlist_add_nvlist(zc_props, 9227184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9237184Stimh goto create_failed; 9247184Stimh } 9257184Stimh } 9267184Stimh 9277184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9287184Stimh goto create_failed; 9297184Stimh 930789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 931789Sahrens 9327184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9335320Slling 9342676Seschrock zcmd_free_nvlists(&zc); 9357184Stimh nvlist_free(zc_props); 9367184Stimh nvlist_free(zc_fsprops); 9372082Seschrock 938789Sahrens switch (errno) { 939789Sahrens case EBUSY: 940789Sahrens /* 941789Sahrens * This can happen if the user has specified the same 942789Sahrens * device multiple times. We can't reliably detect this 943789Sahrens * until we try to add it and see we already have a 944789Sahrens * label. 945789Sahrens */ 9462082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9472082Seschrock "one or more vdevs refer to the same device")); 9482082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 949789Sahrens 950789Sahrens case EOVERFLOW: 951789Sahrens /* 9522082Seschrock * This occurs when one of the devices is below 953789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 954789Sahrens * device was the problem device since there's no 955789Sahrens * reliable way to determine device size from userland. 956789Sahrens */ 957789Sahrens { 958789Sahrens char buf[64]; 959789Sahrens 960789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 961789Sahrens 9622082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9632082Seschrock "one or more devices is less than the " 9642082Seschrock "minimum size (%s)"), buf); 965789Sahrens } 9662082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 967789Sahrens 968789Sahrens case ENOSPC: 9692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9702082Seschrock "one or more devices is out of space")); 9712082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 972789Sahrens 9735450Sbrendan case ENOTBLK: 9745450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9755450Sbrendan "cache device must be a disk or disk slice")); 9765450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9775450Sbrendan 978789Sahrens default: 9792082Seschrock return (zpool_standard_error(hdl, errno, msg)); 980789Sahrens } 981789Sahrens } 982789Sahrens 983789Sahrens /* 984789Sahrens * If this is an alternate root pool, then we automatically set the 9852676Seschrock * mountpoint of the root dataset to be '/'. 986789Sahrens */ 9875094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 9885094Slling &altroot) == 0) { 989789Sahrens zfs_handle_t *zhp; 990789Sahrens 9915094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 9922676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 9932676Seschrock "/") == 0); 994789Sahrens 995789Sahrens zfs_close(zhp); 996789Sahrens } 997789Sahrens 9987184Stimh create_failed: 9995320Slling zcmd_free_nvlists(&zc); 10007184Stimh nvlist_free(zc_props); 10017184Stimh nvlist_free(zc_fsprops); 10027184Stimh return (ret); 1003789Sahrens } 1004789Sahrens 1005789Sahrens /* 1006789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1007789Sahrens * datasets left in the pool. 1008789Sahrens */ 1009789Sahrens int 1010789Sahrens zpool_destroy(zpool_handle_t *zhp) 1011789Sahrens { 1012789Sahrens zfs_cmd_t zc = { 0 }; 1013789Sahrens zfs_handle_t *zfp = NULL; 10142082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10152082Seschrock char msg[1024]; 1016789Sahrens 1017789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 101813037SMark.Musante@Sun.COM (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL) 1019789Sahrens return (-1); 1020789Sahrens 1021789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1022789Sahrens 102313037SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10242082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10252082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1026789Sahrens 10272082Seschrock if (errno == EROFS) { 10282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10292082Seschrock "one or more devices is read only")); 10302082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10312082Seschrock } else { 10322082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1033789Sahrens } 1034789Sahrens 1035789Sahrens if (zfp) 1036789Sahrens zfs_close(zfp); 1037789Sahrens return (-1); 1038789Sahrens } 1039789Sahrens 1040789Sahrens if (zfp) { 1041789Sahrens remove_mountpoint(zfp); 1042789Sahrens zfs_close(zfp); 1043789Sahrens } 1044789Sahrens 1045789Sahrens return (0); 1046789Sahrens } 1047789Sahrens 1048789Sahrens /* 1049789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1050789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1051789Sahrens */ 1052789Sahrens int 1053789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1054789Sahrens { 10552676Seschrock zfs_cmd_t zc = { 0 }; 10562082Seschrock int ret; 10572082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10582082Seschrock char msg[1024]; 10595450Sbrendan nvlist_t **spares, **l2cache; 10605450Sbrendan uint_t nspares, nl2cache; 10612082Seschrock 10622082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10632082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10642082Seschrock 10655450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10665450Sbrendan SPA_VERSION_SPARES && 10672082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10682082Seschrock &spares, &nspares) == 0) { 10692082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10702082Seschrock "upgraded to add hot spares")); 10712082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10722082Seschrock } 1073789Sahrens 10747965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10757965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10767965SGeorge.Wilson@Sun.COM uint64_t s; 10777965SGeorge.Wilson@Sun.COM 10787965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 10797965SGeorge.Wilson@Sun.COM char *path; 10807965SGeorge.Wilson@Sun.COM 10817965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 10827965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 10837965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10847965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 10857965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 108610594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 108710594SGeorge.Wilson@Sun.COM B_FALSE)); 10887965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 10897965SGeorge.Wilson@Sun.COM } 10907965SGeorge.Wilson@Sun.COM } 10917965SGeorge.Wilson@Sun.COM } 10927965SGeorge.Wilson@Sun.COM 10935450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10945450Sbrendan SPA_VERSION_L2CACHE && 10955450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 10965450Sbrendan &l2cache, &nl2cache) == 0) { 10975450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10985450Sbrendan "upgraded to add cache devices")); 10995450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 11005450Sbrendan } 11015450Sbrendan 11025094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 11032082Seschrock return (-1); 1104789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1105789Sahrens 110613037SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1107789Sahrens switch (errno) { 1108789Sahrens case EBUSY: 1109789Sahrens /* 1110789Sahrens * This can happen if the user has specified the same 1111789Sahrens * device multiple times. We can't reliably detect this 1112789Sahrens * until we try to add it and see we already have a 1113789Sahrens * label. 1114789Sahrens */ 11152082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11162082Seschrock "one or more vdevs refer to the same device")); 11172082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1118789Sahrens break; 1119789Sahrens 1120789Sahrens case EOVERFLOW: 1121789Sahrens /* 1122789Sahrens * This occurrs when one of the devices is below 1123789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1124789Sahrens * device was the problem device since there's no 1125789Sahrens * reliable way to determine device size from userland. 1126789Sahrens */ 1127789Sahrens { 1128789Sahrens char buf[64]; 1129789Sahrens 1130789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1131789Sahrens 11322082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11332082Seschrock "device is less than the minimum " 11342082Seschrock "size (%s)"), buf); 1135789Sahrens } 11362082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11372082Seschrock break; 11382082Seschrock 11392082Seschrock case ENOTSUP: 11402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11414527Sperrin "pool must be upgraded to add these vdevs")); 11422082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1143789Sahrens break; 1144789Sahrens 11453912Slling case EDOM: 11463912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11474527Sperrin "root pool can not have multiple vdevs" 11484527Sperrin " or separate logs")); 11493912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11503912Slling break; 11513912Slling 11525450Sbrendan case ENOTBLK: 11535450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11545450Sbrendan "cache device must be a disk or disk slice")); 11555450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11565450Sbrendan break; 11575450Sbrendan 1158789Sahrens default: 11592082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1160789Sahrens } 1161789Sahrens 11622082Seschrock ret = -1; 11632082Seschrock } else { 11642082Seschrock ret = 0; 1165789Sahrens } 1166789Sahrens 11672676Seschrock zcmd_free_nvlists(&zc); 1168789Sahrens 11692082Seschrock return (ret); 1170789Sahrens } 1171789Sahrens 1172789Sahrens /* 1173789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1174789Sahrens * mounted datasets in the pool. 1175789Sahrens */ 1176789Sahrens int 11778211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1178789Sahrens { 1179789Sahrens zfs_cmd_t zc = { 0 }; 11807214Slling char msg[1024]; 1181789Sahrens 11827214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 11837214Slling "cannot export '%s'"), zhp->zpool_name); 11847214Slling 1185789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 11867214Slling zc.zc_cookie = force; 11878211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 11887214Slling 11897214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 11907214Slling switch (errno) { 11917214Slling case EXDEV: 11927214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 11937214Slling "use '-f' to override the following errors:\n" 11947214Slling "'%s' has an active shared spare which could be" 11957214Slling " used by other pools once '%s' is exported."), 11967214Slling zhp->zpool_name, zhp->zpool_name); 11977214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 11987214Slling msg)); 11997214Slling default: 12007214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 12017214Slling msg)); 12027214Slling } 12037214Slling } 12047214Slling 1205789Sahrens return (0); 1206789Sahrens } 1207789Sahrens 12088211SGeorge.Wilson@Sun.COM int 12098211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 12108211SGeorge.Wilson@Sun.COM { 12118211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12128211SGeorge.Wilson@Sun.COM } 12138211SGeorge.Wilson@Sun.COM 12148211SGeorge.Wilson@Sun.COM int 12158211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12168211SGeorge.Wilson@Sun.COM { 12178211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12188211SGeorge.Wilson@Sun.COM } 12198211SGeorge.Wilson@Sun.COM 122010921STim.Haley@Sun.COM static void 122110921STim.Haley@Sun.COM zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 122212949SGeorge.Wilson@Sun.COM nvlist_t *config) 122310921STim.Haley@Sun.COM { 122412949SGeorge.Wilson@Sun.COM nvlist_t *nv = NULL; 122510921STim.Haley@Sun.COM uint64_t rewindto; 122610921STim.Haley@Sun.COM int64_t loss = -1; 122710921STim.Haley@Sun.COM struct tm t; 122810921STim.Haley@Sun.COM char timestr[128]; 122910921STim.Haley@Sun.COM 123012949SGeorge.Wilson@Sun.COM if (!hdl->libzfs_printerr || config == NULL) 123112949SGeorge.Wilson@Sun.COM return; 123212949SGeorge.Wilson@Sun.COM 123312949SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0) 123410921STim.Haley@Sun.COM return; 123510921STim.Haley@Sun.COM 123612949SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 123710921STim.Haley@Sun.COM return; 123812949SGeorge.Wilson@Sun.COM (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 123910921STim.Haley@Sun.COM 124010921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 124110921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 124210921STim.Haley@Sun.COM if (dryrun) { 124310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 124410921STim.Haley@Sun.COM "Would be able to return %s " 124510921STim.Haley@Sun.COM "to its state as of %s.\n"), 124610921STim.Haley@Sun.COM name, timestr); 124710921STim.Haley@Sun.COM } else { 124810921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 124910921STim.Haley@Sun.COM "Pool %s returned to its state as of %s.\n"), 125010921STim.Haley@Sun.COM name, timestr); 125110921STim.Haley@Sun.COM } 125210921STim.Haley@Sun.COM if (loss > 120) { 125310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 125410921STim.Haley@Sun.COM "%s approximately %lld "), 125510921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", 125610921STim.Haley@Sun.COM (loss + 30) / 60); 125710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 125810921STim.Haley@Sun.COM "minutes of transactions.\n")); 125910921STim.Haley@Sun.COM } else if (loss > 0) { 126010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 126110921STim.Haley@Sun.COM "%s approximately %lld "), 126210921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", loss); 126310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 126410921STim.Haley@Sun.COM "seconds of transactions.\n")); 126510921STim.Haley@Sun.COM } 126610921STim.Haley@Sun.COM } 126710921STim.Haley@Sun.COM } 126810921STim.Haley@Sun.COM 126910921STim.Haley@Sun.COM void 127010921STim.Haley@Sun.COM zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 127110921STim.Haley@Sun.COM nvlist_t *config) 127210921STim.Haley@Sun.COM { 127312949SGeorge.Wilson@Sun.COM nvlist_t *nv = NULL; 127410921STim.Haley@Sun.COM int64_t loss = -1; 127510921STim.Haley@Sun.COM uint64_t edata = UINT64_MAX; 127610921STim.Haley@Sun.COM uint64_t rewindto; 127710921STim.Haley@Sun.COM struct tm t; 127810921STim.Haley@Sun.COM char timestr[128]; 127910921STim.Haley@Sun.COM 128010921STim.Haley@Sun.COM if (!hdl->libzfs_printerr) 128110921STim.Haley@Sun.COM return; 128210921STim.Haley@Sun.COM 128310921STim.Haley@Sun.COM if (reason >= 0) 128410921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 128510921STim.Haley@Sun.COM else 128610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "\t")); 128710921STim.Haley@Sun.COM 128810921STim.Haley@Sun.COM /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 128912949SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || 129012949SGeorge.Wilson@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 129110921STim.Haley@Sun.COM goto no_info; 129210921STim.Haley@Sun.COM 129312949SGeorge.Wilson@Sun.COM (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 129412949SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 129510921STim.Haley@Sun.COM &edata); 129610921STim.Haley@Sun.COM 129710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 129810921STim.Haley@Sun.COM "Recovery is possible, but will result in some data loss.\n")); 129910921STim.Haley@Sun.COM 130010921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 130110921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 130210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 130310921STim.Haley@Sun.COM "\tReturning the pool to its state as of %s\n" 130410921STim.Haley@Sun.COM "\tshould correct the problem. "), 130510921STim.Haley@Sun.COM timestr); 130610921STim.Haley@Sun.COM } else { 130710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 130810921STim.Haley@Sun.COM "\tReverting the pool to an earlier state " 130910921STim.Haley@Sun.COM "should correct the problem.\n\t")); 131010921STim.Haley@Sun.COM } 131110921STim.Haley@Sun.COM 131210921STim.Haley@Sun.COM if (loss > 120) { 131310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 131410921STim.Haley@Sun.COM "Approximately %lld minutes of data\n" 131510921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 131610921STim.Haley@Sun.COM } else if (loss > 0) { 131710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 131810921STim.Haley@Sun.COM "Approximately %lld seconds of data\n" 131910921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), loss); 132010921STim.Haley@Sun.COM } 132110921STim.Haley@Sun.COM if (edata != 0 && edata != UINT64_MAX) { 132210921STim.Haley@Sun.COM if (edata == 1) { 132310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 132410921STim.Haley@Sun.COM "After rewind, at least\n" 132510921STim.Haley@Sun.COM "\tone persistent user-data error will remain. ")); 132610921STim.Haley@Sun.COM } else { 132710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 132810921STim.Haley@Sun.COM "After rewind, several\n" 132910921STim.Haley@Sun.COM "\tpersistent user-data errors will remain. ")); 133010921STim.Haley@Sun.COM } 133110921STim.Haley@Sun.COM } 133210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 133311026STim.Haley@Sun.COM "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "), 133411026STim.Haley@Sun.COM reason >= 0 ? "clear" : "import", name); 133510921STim.Haley@Sun.COM 133610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 133710921STim.Haley@Sun.COM "A scrub of the pool\n" 133810921STim.Haley@Sun.COM "\tis strongly recommended after recovery.\n")); 133910921STim.Haley@Sun.COM return; 134010921STim.Haley@Sun.COM 134110921STim.Haley@Sun.COM no_info: 134210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 134310921STim.Haley@Sun.COM "Destroy and re-create the pool from\n\ta backup source.\n")); 134410921STim.Haley@Sun.COM } 134510921STim.Haley@Sun.COM 1346789Sahrens /* 13475094Slling * zpool_import() is a contracted interface. Should be kept the same 13485094Slling * if possible. 13495094Slling * 13505094Slling * Applications should use zpool_import_props() to import a pool with 13515094Slling * new properties value to be set. 1352789Sahrens */ 1353789Sahrens int 13542082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 13555094Slling char *altroot) 13565094Slling { 13575094Slling nvlist_t *props = NULL; 13585094Slling int ret; 13595094Slling 13605094Slling if (altroot != NULL) { 13615094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 13625094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13635094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13645094Slling newname)); 13655094Slling } 13665094Slling 13675094Slling if (nvlist_add_string(props, 13688084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 13698084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 13708084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 13715094Slling nvlist_free(props); 13725094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13735094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13745094Slling newname)); 13755094Slling } 13765094Slling } 13775094Slling 137812949SGeorge.Wilson@Sun.COM ret = zpool_import_props(hdl, config, newname, props, 137912949SGeorge.Wilson@Sun.COM ZFS_IMPORT_NORMAL); 13805094Slling if (props) 13815094Slling nvlist_free(props); 13825094Slling return (ret); 13835094Slling } 13845094Slling 138512949SGeorge.Wilson@Sun.COM static void 138612949SGeorge.Wilson@Sun.COM print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv, 138712949SGeorge.Wilson@Sun.COM int indent) 138812949SGeorge.Wilson@Sun.COM { 138912949SGeorge.Wilson@Sun.COM nvlist_t **child; 139012949SGeorge.Wilson@Sun.COM uint_t c, children; 139112949SGeorge.Wilson@Sun.COM char *vname; 139212949SGeorge.Wilson@Sun.COM uint64_t is_log = 0; 139312949SGeorge.Wilson@Sun.COM 139412949SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, 139512949SGeorge.Wilson@Sun.COM &is_log); 139612949SGeorge.Wilson@Sun.COM 139712949SGeorge.Wilson@Sun.COM if (name != NULL) 139812949SGeorge.Wilson@Sun.COM (void) printf("\t%*s%s%s\n", indent, "", name, 139912949SGeorge.Wilson@Sun.COM is_log ? " [log]" : ""); 140012949SGeorge.Wilson@Sun.COM 140112949SGeorge.Wilson@Sun.COM if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 140212949SGeorge.Wilson@Sun.COM &child, &children) != 0) 140312949SGeorge.Wilson@Sun.COM return; 140412949SGeorge.Wilson@Sun.COM 140512949SGeorge.Wilson@Sun.COM for (c = 0; c < children; c++) { 140612949SGeorge.Wilson@Sun.COM vname = zpool_vdev_name(hdl, NULL, child[c], B_TRUE); 140712949SGeorge.Wilson@Sun.COM print_vdev_tree(hdl, vname, child[c], indent + 2); 140812949SGeorge.Wilson@Sun.COM free(vname); 140912949SGeorge.Wilson@Sun.COM } 141012949SGeorge.Wilson@Sun.COM } 141112949SGeorge.Wilson@Sun.COM 14125094Slling /* 14135094Slling * Import the given pool using the known configuration and a list of 14145094Slling * properties to be set. The configuration should have come from 14155094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 14165094Slling * is imported with a different name. 14175094Slling */ 14185094Slling int 14195094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 142012949SGeorge.Wilson@Sun.COM nvlist_t *props, int flags) 1421789Sahrens { 14222676Seschrock zfs_cmd_t zc = { 0 }; 142310921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 142412949SGeorge.Wilson@Sun.COM nvlist_t *nv = NULL; 142512949SGeorge.Wilson@Sun.COM nvlist_t *nvinfo = NULL; 142612949SGeorge.Wilson@Sun.COM nvlist_t *missing = NULL; 1427789Sahrens char *thename; 1428789Sahrens char *origname; 1429789Sahrens int ret; 143012949SGeorge.Wilson@Sun.COM int error = 0; 14315094Slling char errbuf[1024]; 1432789Sahrens 1433789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1434789Sahrens &origname) == 0); 1435789Sahrens 14365094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 14375094Slling "cannot import pool '%s'"), origname); 14385094Slling 1439789Sahrens if (newname != NULL) { 14402082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 14413237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 14422082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 14432082Seschrock newname)); 1444789Sahrens thename = (char *)newname; 1445789Sahrens } else { 1446789Sahrens thename = origname; 1447789Sahrens } 1448789Sahrens 14495094Slling if (props) { 14505094Slling uint64_t version; 1451*13049SGeorge.Wilson@Sun.COM prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 14525094Slling 14535094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 14545094Slling &version) == 0); 14555094Slling 14567184Stimh if ((props = zpool_valid_proplist(hdl, origname, 1457*13049SGeorge.Wilson@Sun.COM props, version, flags, errbuf)) == NULL) { 14585094Slling return (-1); 14595320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 14605320Slling nvlist_free(props); 14615094Slling return (-1); 14625320Slling } 14635094Slling } 1464789Sahrens 1465789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1466789Sahrens 1467789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 14681544Seschrock &zc.zc_guid) == 0); 1469789Sahrens 14705320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 14715320Slling nvlist_free(props); 14722082Seschrock return (-1); 14735320Slling } 147412974SGeorge.Wilson@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) { 147510921STim.Haley@Sun.COM nvlist_free(props); 147610921STim.Haley@Sun.COM return (-1); 147710921STim.Haley@Sun.COM } 1478789Sahrens 147912949SGeorge.Wilson@Sun.COM zc.zc_cookie = flags; 148012949SGeorge.Wilson@Sun.COM while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 && 148112949SGeorge.Wilson@Sun.COM errno == ENOMEM) { 148212949SGeorge.Wilson@Sun.COM if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 148312949SGeorge.Wilson@Sun.COM zcmd_free_nvlists(&zc); 148412949SGeorge.Wilson@Sun.COM return (-1); 148512949SGeorge.Wilson@Sun.COM } 148612949SGeorge.Wilson@Sun.COM } 148712949SGeorge.Wilson@Sun.COM if (ret != 0) 148812949SGeorge.Wilson@Sun.COM error = errno; 148912949SGeorge.Wilson@Sun.COM 149012949SGeorge.Wilson@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nv); 149112949SGeorge.Wilson@Sun.COM zpool_get_rewind_policy(config, &policy); 149212949SGeorge.Wilson@Sun.COM 149312949SGeorge.Wilson@Sun.COM if (error) { 1494789Sahrens char desc[1024]; 149510921STim.Haley@Sun.COM 149610921STim.Haley@Sun.COM /* 149710921STim.Haley@Sun.COM * Dry-run failed, but we print out what success 149810921STim.Haley@Sun.COM * looks like if we found a best txg 149910921STim.Haley@Sun.COM */ 150012949SGeorge.Wilson@Sun.COM if (policy.zrp_request & ZPOOL_TRY_REWIND) { 150110921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 150212949SGeorge.Wilson@Sun.COM B_TRUE, nv); 150312949SGeorge.Wilson@Sun.COM nvlist_free(nv); 150410921STim.Haley@Sun.COM return (-1); 150510921STim.Haley@Sun.COM } 150610921STim.Haley@Sun.COM 1507789Sahrens if (newname == NULL) 1508789Sahrens (void) snprintf(desc, sizeof (desc), 1509789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1510789Sahrens thename); 1511789Sahrens else 1512789Sahrens (void) snprintf(desc, sizeof (desc), 1513789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1514789Sahrens origname, thename); 1515789Sahrens 151612949SGeorge.Wilson@Sun.COM switch (error) { 15171544Seschrock case ENOTSUP: 15181544Seschrock /* 15191544Seschrock * Unsupported version. 15201544Seschrock */ 15212082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 15221544Seschrock break; 15231544Seschrock 15242174Seschrock case EINVAL: 15252174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 15262174Seschrock break; 15272174Seschrock 152811814SChris.Kirby@sun.com case EROFS: 152911814SChris.Kirby@sun.com zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 153011814SChris.Kirby@sun.com "one or more devices is read only")); 153111814SChris.Kirby@sun.com (void) zfs_error(hdl, EZFS_BADDEV, desc); 153211814SChris.Kirby@sun.com break; 153311814SChris.Kirby@sun.com 153412949SGeorge.Wilson@Sun.COM case ENXIO: 153512949SGeorge.Wilson@Sun.COM if (nv && nvlist_lookup_nvlist(nv, 153612949SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && 153712949SGeorge.Wilson@Sun.COM nvlist_lookup_nvlist(nvinfo, 153812949SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) { 153912949SGeorge.Wilson@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 154012949SGeorge.Wilson@Sun.COM "The devices below are missing, use " 154112949SGeorge.Wilson@Sun.COM "'-m' to import the pool anyway:\n")); 154212949SGeorge.Wilson@Sun.COM print_vdev_tree(hdl, NULL, missing, 2); 154312949SGeorge.Wilson@Sun.COM (void) printf("\n"); 154412949SGeorge.Wilson@Sun.COM } 154512949SGeorge.Wilson@Sun.COM (void) zpool_standard_error(hdl, error, desc); 154612949SGeorge.Wilson@Sun.COM break; 154712949SGeorge.Wilson@Sun.COM 154812949SGeorge.Wilson@Sun.COM case EEXIST: 154912949SGeorge.Wilson@Sun.COM (void) zpool_standard_error(hdl, error, desc); 155012949SGeorge.Wilson@Sun.COM break; 155112949SGeorge.Wilson@Sun.COM 1552789Sahrens default: 155312949SGeorge.Wilson@Sun.COM (void) zpool_standard_error(hdl, error, desc); 155410921STim.Haley@Sun.COM zpool_explain_recover(hdl, 155512949SGeorge.Wilson@Sun.COM newname ? origname : thename, -error, nv); 155610921STim.Haley@Sun.COM break; 1557789Sahrens } 1558789Sahrens 155912949SGeorge.Wilson@Sun.COM nvlist_free(nv); 1560789Sahrens ret = -1; 1561789Sahrens } else { 1562789Sahrens zpool_handle_t *zhp; 15634543Smarks 1564789Sahrens /* 1565789Sahrens * This should never fail, but play it safe anyway. 1566789Sahrens */ 156710588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 15682142Seschrock ret = -1; 156910588SEric.Taylor@Sun.COM else if (zhp != NULL) 1570789Sahrens zpool_close(zhp); 157110921STim.Haley@Sun.COM if (policy.zrp_request & 157210921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 157310921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 157412949SGeorge.Wilson@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), nv); 157510921STim.Haley@Sun.COM } 157612949SGeorge.Wilson@Sun.COM nvlist_free(nv); 157710921STim.Haley@Sun.COM return (0); 1578789Sahrens } 1579789Sahrens 15802676Seschrock zcmd_free_nvlists(&zc); 15815320Slling nvlist_free(props); 15825320Slling 1583789Sahrens return (ret); 1584789Sahrens } 1585789Sahrens 1586789Sahrens /* 158712296SLin.Ling@Sun.COM * Scan the pool. 1588789Sahrens */ 1589789Sahrens int 159012296SLin.Ling@Sun.COM zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func) 1591789Sahrens { 1592789Sahrens zfs_cmd_t zc = { 0 }; 1593789Sahrens char msg[1024]; 15942082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1595789Sahrens 1596789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 159712296SLin.Ling@Sun.COM zc.zc_cookie = func; 159812296SLin.Ling@Sun.COM 159913037SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0 || 160012296SLin.Ling@Sun.COM (errno == ENOENT && func != POOL_SCAN_NONE)) 1601789Sahrens return (0); 1602789Sahrens 160312296SLin.Ling@Sun.COM if (func == POOL_SCAN_SCRUB) { 160412296SLin.Ling@Sun.COM (void) snprintf(msg, sizeof (msg), 160512296SLin.Ling@Sun.COM dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 160612296SLin.Ling@Sun.COM } else if (func == POOL_SCAN_NONE) { 160712296SLin.Ling@Sun.COM (void) snprintf(msg, sizeof (msg), 160812296SLin.Ling@Sun.COM dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"), 160912296SLin.Ling@Sun.COM zc.zc_name); 161012296SLin.Ling@Sun.COM } else { 161112296SLin.Ling@Sun.COM assert(!"unexpected result"); 161212296SLin.Ling@Sun.COM } 161312296SLin.Ling@Sun.COM 161412296SLin.Ling@Sun.COM if (errno == EBUSY) { 161512296SLin.Ling@Sun.COM nvlist_t *nvroot; 161612296SLin.Ling@Sun.COM pool_scan_stat_t *ps = NULL; 161712296SLin.Ling@Sun.COM uint_t psc; 161812296SLin.Ling@Sun.COM 161912296SLin.Ling@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, 162012296SLin.Ling@Sun.COM ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 162112296SLin.Ling@Sun.COM (void) nvlist_lookup_uint64_array(nvroot, 162212296SLin.Ling@Sun.COM ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc); 162312296SLin.Ling@Sun.COM if (ps && ps->pss_func == POOL_SCAN_SCRUB) 162412296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_SCRUBBING, msg)); 162512296SLin.Ling@Sun.COM else 162612296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_RESILVERING, msg)); 162712296SLin.Ling@Sun.COM } else if (errno == ENOENT) { 162812296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_NO_SCRUB, msg)); 162912296SLin.Ling@Sun.COM } else { 16302082Seschrock return (zpool_standard_error(hdl, errno, msg)); 163112296SLin.Ling@Sun.COM } 1632789Sahrens } 1633789Sahrens 16342468Sek110237 /* 163512383SJohn.Harres@Sun.COM * This provides a very minimal check whether a given string is likely a 163612383SJohn.Harres@Sun.COM * c#t#d# style string. Users of this are expected to do their own 163712383SJohn.Harres@Sun.COM * verification of the s# part. 163812383SJohn.Harres@Sun.COM */ 163912383SJohn.Harres@Sun.COM #define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1])) 164012383SJohn.Harres@Sun.COM 164112383SJohn.Harres@Sun.COM /* 164212383SJohn.Harres@Sun.COM * More elaborate version for ones which may start with "/dev/dsk/" 164312383SJohn.Harres@Sun.COM * and the like. 164412383SJohn.Harres@Sun.COM */ 164512383SJohn.Harres@Sun.COM static int 164612383SJohn.Harres@Sun.COM ctd_check_path(char *str) { 164712383SJohn.Harres@Sun.COM /* 164812383SJohn.Harres@Sun.COM * If it starts with a slash, check the last component. 164912383SJohn.Harres@Sun.COM */ 165012383SJohn.Harres@Sun.COM if (str && str[0] == '/') { 165112383SJohn.Harres@Sun.COM char *tmp = strrchr(str, '/'); 165212383SJohn.Harres@Sun.COM 165312383SJohn.Harres@Sun.COM /* 165412383SJohn.Harres@Sun.COM * If it ends in "/old", check the second-to-last 165512383SJohn.Harres@Sun.COM * component of the string instead. 165612383SJohn.Harres@Sun.COM */ 165712383SJohn.Harres@Sun.COM if (tmp != str && strcmp(tmp, "/old") == 0) { 165812383SJohn.Harres@Sun.COM for (tmp--; *tmp != '/'; tmp--) 165912383SJohn.Harres@Sun.COM ; 166012383SJohn.Harres@Sun.COM } 166112383SJohn.Harres@Sun.COM str = tmp + 1; 166212383SJohn.Harres@Sun.COM } 166312383SJohn.Harres@Sun.COM return (CTD_CHECK(str)); 166412383SJohn.Harres@Sun.COM } 166512383SJohn.Harres@Sun.COM 166612383SJohn.Harres@Sun.COM /* 16679816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 16689816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 16692468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 16702468Sek110237 * spare; but FALSE if its an INUSE spare. 16712468Sek110237 */ 16722082Seschrock static nvlist_t * 16739816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 16749816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 16751544Seschrock { 16761544Seschrock uint_t c, children; 16771544Seschrock nvlist_t **child; 16782082Seschrock nvlist_t *ret; 16797326SEric.Schrock@Sun.COM uint64_t is_log; 16809816SGeorge.Wilson@Sun.COM char *srchkey; 16819816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 16829816SGeorge.Wilson@Sun.COM 16839816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 16849816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 16859816SGeorge.Wilson@Sun.COM return (NULL); 16869816SGeorge.Wilson@Sun.COM 16879816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 16889816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 16899816SGeorge.Wilson@Sun.COM 16909816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 169113037SMark.Musante@Sun.COM case DATA_TYPE_UINT64: 16929816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 169313037SMark.Musante@Sun.COM uint64_t srchval, theguid; 169413037SMark.Musante@Sun.COM 169513037SMark.Musante@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 169613037SMark.Musante@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 169713037SMark.Musante@Sun.COM &theguid) == 0); 169813037SMark.Musante@Sun.COM if (theguid == srchval) 169913037SMark.Musante@Sun.COM return (nv); 17009816SGeorge.Wilson@Sun.COM } 17019816SGeorge.Wilson@Sun.COM break; 17029816SGeorge.Wilson@Sun.COM 17039816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 17049816SGeorge.Wilson@Sun.COM char *srchval, *val; 17059816SGeorge.Wilson@Sun.COM 17069816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 17079816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 17089816SGeorge.Wilson@Sun.COM break; 17099816SGeorge.Wilson@Sun.COM 17101544Seschrock /* 171112383SJohn.Harres@Sun.COM * Search for the requested value. Special cases: 171212383SJohn.Harres@Sun.COM * 171312383SJohn.Harres@Sun.COM * - ZPOOL_CONFIG_PATH for whole disk entries. These end in 171412383SJohn.Harres@Sun.COM * "s0" or "s0/old". The "s0" part is hidden from the user, 171512383SJohn.Harres@Sun.COM * but included in the string, so this matches around it. 171612383SJohn.Harres@Sun.COM * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 171712383SJohn.Harres@Sun.COM * 171810594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 17191544Seschrock */ 172012383SJohn.Harres@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && 172112383SJohn.Harres@Sun.COM ctd_check_path(val)) { 17229816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 17239816SGeorge.Wilson@Sun.COM 17249816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 17259816SGeorge.Wilson@Sun.COM &wholedisk); 17269816SGeorge.Wilson@Sun.COM if (wholedisk) { 172712383SJohn.Harres@Sun.COM int slen = strlen(srchval); 172812383SJohn.Harres@Sun.COM int vlen = strlen(val); 172912383SJohn.Harres@Sun.COM 173012383SJohn.Harres@Sun.COM if (slen != vlen - 2) 173112383SJohn.Harres@Sun.COM break; 173212383SJohn.Harres@Sun.COM 17339816SGeorge.Wilson@Sun.COM /* 173412383SJohn.Harres@Sun.COM * make_leaf_vdev() should only set 173512383SJohn.Harres@Sun.COM * wholedisk for ZPOOL_CONFIG_PATHs which 173612383SJohn.Harres@Sun.COM * will include "/dev/dsk/", giving plenty of 173712383SJohn.Harres@Sun.COM * room for the indices used next. 17389816SGeorge.Wilson@Sun.COM */ 173912383SJohn.Harres@Sun.COM ASSERT(vlen >= 6); 174012383SJohn.Harres@Sun.COM 174112383SJohn.Harres@Sun.COM /* 174212383SJohn.Harres@Sun.COM * strings identical except trailing "s0" 174312383SJohn.Harres@Sun.COM */ 174412383SJohn.Harres@Sun.COM if (strcmp(&val[vlen - 2], "s0") == 0 && 174512383SJohn.Harres@Sun.COM strncmp(srchval, val, slen) == 0) 17469816SGeorge.Wilson@Sun.COM return (nv); 174712383SJohn.Harres@Sun.COM 174812383SJohn.Harres@Sun.COM /* 174912383SJohn.Harres@Sun.COM * strings identical except trailing "s0/old" 175012383SJohn.Harres@Sun.COM */ 175112383SJohn.Harres@Sun.COM if (strcmp(&val[vlen - 6], "s0/old") == 0 && 175212383SJohn.Harres@Sun.COM strcmp(&srchval[slen - 4], "/old") == 0 && 175312383SJohn.Harres@Sun.COM strncmp(srchval, val, slen - 4) == 0) 175412383SJohn.Harres@Sun.COM return (nv); 175512383SJohn.Harres@Sun.COM 17569816SGeorge.Wilson@Sun.COM break; 17579816SGeorge.Wilson@Sun.COM } 175810594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 175910594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 176010594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 176110594SGeorge.Wilson@Sun.COM 176210594SGeorge.Wilson@Sun.COM /* 176310594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 176410594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 176510594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 176610594SGeorge.Wilson@Sun.COM */ 176710594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 176810594SGeorge.Wilson@Sun.COM return (NULL); 176910594SGeorge.Wilson@Sun.COM 177010594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 177110594SGeorge.Wilson@Sun.COM free(type); 177210594SGeorge.Wilson@Sun.COM break; 177310594SGeorge.Wilson@Sun.COM } 177410594SGeorge.Wilson@Sun.COM idx = p + 1; 177510594SGeorge.Wilson@Sun.COM *p = '\0'; 177610594SGeorge.Wilson@Sun.COM 177710594SGeorge.Wilson@Sun.COM /* 177810594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 177910594SGeorge.Wilson@Sun.COM */ 178010594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 178110594SGeorge.Wilson@Sun.COM free(type); 178210594SGeorge.Wilson@Sun.COM break; 178310594SGeorge.Wilson@Sun.COM } 178410594SGeorge.Wilson@Sun.COM 178510594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 178610594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 178710594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 178810594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 178910594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 179010594SGeorge.Wilson@Sun.COM &id) == 0); 179110594SGeorge.Wilson@Sun.COM 179210594SGeorge.Wilson@Sun.COM errno = 0; 179310594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 179410594SGeorge.Wilson@Sun.COM 179510594SGeorge.Wilson@Sun.COM free(type); 179610594SGeorge.Wilson@Sun.COM if (errno != 0) 179710594SGeorge.Wilson@Sun.COM return (NULL); 179810594SGeorge.Wilson@Sun.COM 179910594SGeorge.Wilson@Sun.COM /* 180010594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 180110594SGeorge.Wilson@Sun.COM */ 180210594SGeorge.Wilson@Sun.COM if (vdev_id == id) 180310594SGeorge.Wilson@Sun.COM return (nv); 18049816SGeorge.Wilson@Sun.COM } 18059816SGeorge.Wilson@Sun.COM 18069816SGeorge.Wilson@Sun.COM /* 18079816SGeorge.Wilson@Sun.COM * Common case 18089816SGeorge.Wilson@Sun.COM */ 18099816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 18102082Seschrock return (nv); 18119816SGeorge.Wilson@Sun.COM break; 18129816SGeorge.Wilson@Sun.COM } 18139816SGeorge.Wilson@Sun.COM 18149816SGeorge.Wilson@Sun.COM default: 18159816SGeorge.Wilson@Sun.COM break; 18161544Seschrock } 18171544Seschrock 18181544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 18191544Seschrock &child, &children) != 0) 18202082Seschrock return (NULL); 18211544Seschrock 18227326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 18239816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 18247326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 18257326SEric.Schrock@Sun.COM /* 18267326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 18277326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 18287326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 18297326SEric.Schrock@Sun.COM * 'log' is non-NULL). 18307326SEric.Schrock@Sun.COM */ 18317326SEric.Schrock@Sun.COM if (log != NULL && 18327326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 18337326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 18347326SEric.Schrock@Sun.COM is_log) { 18357326SEric.Schrock@Sun.COM *log = B_TRUE; 18367326SEric.Schrock@Sun.COM } 18371544Seschrock return (ret); 18387326SEric.Schrock@Sun.COM } 18397326SEric.Schrock@Sun.COM } 18401544Seschrock 18412082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 18422082Seschrock &child, &children) == 0) { 18432082Seschrock for (c = 0; c < children; c++) { 18449816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 18457326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 18462468Sek110237 *avail_spare = B_TRUE; 18472082Seschrock return (ret); 18482082Seschrock } 18492082Seschrock } 18502082Seschrock } 18512082Seschrock 18525450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 18535450Sbrendan &child, &children) == 0) { 18545450Sbrendan for (c = 0; c < children; c++) { 18559816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 18567326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 18575450Sbrendan *l2cache = B_TRUE; 18585450Sbrendan return (ret); 18595450Sbrendan } 18605450Sbrendan } 18615450Sbrendan } 18625450Sbrendan 18632082Seschrock return (NULL); 18641544Seschrock } 18651544Seschrock 18669816SGeorge.Wilson@Sun.COM /* 18679816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 18689816SGeorge.Wilson@Sun.COM * associated vdev. 18699816SGeorge.Wilson@Sun.COM */ 18709816SGeorge.Wilson@Sun.COM nvlist_t * 18719816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 18729816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 18739816SGeorge.Wilson@Sun.COM { 18749816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 18759816SGeorge.Wilson@Sun.COM 18769816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 18779816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 18789816SGeorge.Wilson@Sun.COM 18799816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18809816SGeorge.Wilson@Sun.COM &nvroot) == 0); 18819816SGeorge.Wilson@Sun.COM 18829816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 188313037SMark.Musante@Sun.COM *l2cache = B_FALSE; 188413044SMark.Musante@Sun.COM if (log != NULL) 188513044SMark.Musante@Sun.COM *log = B_FALSE; 18869816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 18879816SGeorge.Wilson@Sun.COM nvlist_free(search); 18889816SGeorge.Wilson@Sun.COM 18899816SGeorge.Wilson@Sun.COM return (ret); 18909816SGeorge.Wilson@Sun.COM } 18919816SGeorge.Wilson@Sun.COM 189210594SGeorge.Wilson@Sun.COM /* 189310594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 189410594SGeorge.Wilson@Sun.COM */ 189510594SGeorge.Wilson@Sun.COM boolean_t 189610594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 189710594SGeorge.Wilson@Sun.COM { 189810594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 189910594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 190010594SGeorge.Wilson@Sun.COM return (B_TRUE); 190110594SGeorge.Wilson@Sun.COM return (B_FALSE); 190210594SGeorge.Wilson@Sun.COM } 190310594SGeorge.Wilson@Sun.COM 19042082Seschrock nvlist_t * 19055450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 19067326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 19071544Seschrock { 19081544Seschrock char buf[MAXPATHLEN]; 19091544Seschrock char *end; 19109816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 19111544Seschrock uint64_t guid; 19121544Seschrock 19139816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 19149816SGeorge.Wilson@Sun.COM 19151613Seschrock guid = strtoull(path, &end, 10); 19161544Seschrock if (guid != 0 && *end == '\0') { 19179816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 191810594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 191910594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 19201544Seschrock } else if (path[0] != '/') { 19211544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 19229816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 19231544Seschrock } else { 19249816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 19251544Seschrock } 19261544Seschrock 19271544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 19281544Seschrock &nvroot) == 0); 19291544Seschrock 19302468Sek110237 *avail_spare = B_FALSE; 19315450Sbrendan *l2cache = B_FALSE; 19327326SEric.Schrock@Sun.COM if (log != NULL) 19337326SEric.Schrock@Sun.COM *log = B_FALSE; 19349816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 19359816SGeorge.Wilson@Sun.COM nvlist_free(search); 19369816SGeorge.Wilson@Sun.COM 19379816SGeorge.Wilson@Sun.COM return (ret); 19382468Sek110237 } 19392468Sek110237 19407656SSherry.Moore@Sun.COM static int 19417656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 19427656SSherry.Moore@Sun.COM { 19437656SSherry.Moore@Sun.COM uint64_t ival; 19447656SSherry.Moore@Sun.COM 19457656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 19467656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 19477656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 19487656SSherry.Moore@Sun.COM return (0); 19497656SSherry.Moore@Sun.COM 19507656SSherry.Moore@Sun.COM return (1); 19517656SSherry.Moore@Sun.COM } 19527656SSherry.Moore@Sun.COM 19537656SSherry.Moore@Sun.COM /* 19549790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 19557656SSherry.Moore@Sun.COM */ 19569160SSherry.Moore@Sun.COM static int 19579790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 19589160SSherry.Moore@Sun.COM size_t *bytes_written) 19597656SSherry.Moore@Sun.COM { 19609160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 19619160SSherry.Moore@Sun.COM char *tmppath; 19629160SSherry.Moore@Sun.COM const char *format; 19639160SSherry.Moore@Sun.COM 19649160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 19659160SSherry.Moore@Sun.COM &tmppath) != 0) 19669160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 19679160SSherry.Moore@Sun.COM 19689160SSherry.Moore@Sun.COM pos = *bytes_written; 19699160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 19709160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 19719160SSherry.Moore@Sun.COM 19729160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 19739160SSherry.Moore@Sun.COM *bytes_written += rsz; 19749160SSherry.Moore@Sun.COM 19759160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 19769160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 19779160SSherry.Moore@Sun.COM if (bytes_left != 0) { 19789160SSherry.Moore@Sun.COM physpath[pos] = 0; 19799160SSherry.Moore@Sun.COM } 19809160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 19819160SSherry.Moore@Sun.COM } 19829160SSherry.Moore@Sun.COM return (0); 19839160SSherry.Moore@Sun.COM } 19849160SSherry.Moore@Sun.COM 19859790SLin.Ling@Sun.COM static int 19869790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 19879790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 19889790SLin.Ling@Sun.COM { 19899790SLin.Ling@Sun.COM char *type; 19909790SLin.Ling@Sun.COM int ret; 19919790SLin.Ling@Sun.COM 19929790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 19939790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19949790SLin.Ling@Sun.COM 19959790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 19969790SLin.Ling@Sun.COM /* 19979790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 19989790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 19999790SLin.Ling@Sun.COM * spare device. 20009790SLin.Ling@Sun.COM */ 20019790SLin.Ling@Sun.COM if (is_spare) { 20029790SLin.Ling@Sun.COM uint64_t spare = 0; 20039790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 20049790SLin.Ling@Sun.COM &spare); 20059790SLin.Ling@Sun.COM if (!spare) 20069790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 20079790SLin.Ling@Sun.COM } 20089790SLin.Ling@Sun.COM 20099790SLin.Ling@Sun.COM if (vdev_online(nv)) { 20109790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 20119790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 20129790SLin.Ling@Sun.COM return (ret); 20139790SLin.Ling@Sun.COM } 20149790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 20159790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 20169790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 20179790SLin.Ling@Sun.COM nvlist_t **child; 20189790SLin.Ling@Sun.COM uint_t count; 20199790SLin.Ling@Sun.COM int i, ret; 20209790SLin.Ling@Sun.COM 20219790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 20229790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 20239790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 20249790SLin.Ling@Sun.COM 20259790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 20269790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 20279790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 20289790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 20299790SLin.Ling@Sun.COM return (ret); 20309790SLin.Ling@Sun.COM } 20319790SLin.Ling@Sun.COM } 20329790SLin.Ling@Sun.COM 20339790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 20349790SLin.Ling@Sun.COM } 20359790SLin.Ling@Sun.COM 20369160SSherry.Moore@Sun.COM /* 20379160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 20389160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 20399160SSherry.Moore@Sun.COM */ 20409160SSherry.Moore@Sun.COM static int 20419160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 20429160SSherry.Moore@Sun.COM { 20439160SSherry.Moore@Sun.COM size_t rsz; 20447656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 20457656SSherry.Moore@Sun.COM nvlist_t **child; 20467656SSherry.Moore@Sun.COM uint_t count; 20479160SSherry.Moore@Sun.COM char *type; 20489160SSherry.Moore@Sun.COM 20499160SSherry.Moore@Sun.COM rsz = 0; 20509160SSherry.Moore@Sun.COM 20519160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 20529160SSherry.Moore@Sun.COM &vdev_root) != 0) 20539160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 20549160SSherry.Moore@Sun.COM 20559160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 20569160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 20579160SSherry.Moore@Sun.COM &child, &count) != 0) 20589160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 20597656SSherry.Moore@Sun.COM 20607656SSherry.Moore@Sun.COM /* 20619160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 20629160SSherry.Moore@Sun.COM * a single top-level vdev. 20637656SSherry.Moore@Sun.COM */ 20649160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 20659160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 20669160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 20679160SSherry.Moore@Sun.COM 20689790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 20699790SLin.Ling@Sun.COM B_FALSE); 20707656SSherry.Moore@Sun.COM 20719160SSherry.Moore@Sun.COM /* No online devices */ 20729160SSherry.Moore@Sun.COM if (rsz == 0) 20739160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 20749160SSherry.Moore@Sun.COM 20757656SSherry.Moore@Sun.COM return (0); 20767656SSherry.Moore@Sun.COM } 20777656SSherry.Moore@Sun.COM 20782468Sek110237 /* 20799160SSherry.Moore@Sun.COM * Get phys_path for a root pool 20809160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 20819160SSherry.Moore@Sun.COM */ 20829160SSherry.Moore@Sun.COM int 20839160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 20849160SSherry.Moore@Sun.COM { 20859160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 20869160SSherry.Moore@Sun.COM phypath_size)); 20879160SSherry.Moore@Sun.COM } 20889160SSherry.Moore@Sun.COM 20899160SSherry.Moore@Sun.COM /* 20909816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 20919816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 20929816SGeorge.Wilson@Sun.COM */ 20939816SGeorge.Wilson@Sun.COM static int 20949816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 20959816SGeorge.Wilson@Sun.COM { 20969816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 20979816SGeorge.Wilson@Sun.COM char errbuf[1024]; 20989816SGeorge.Wilson@Sun.COM int fd, error; 20999816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 21009816SGeorge.Wilson@Sun.COM 21019816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 21029816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 21039816SGeorge.Wilson@Sun.COM return (-1); 21049816SGeorge.Wilson@Sun.COM 21059816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 21069816SGeorge.Wilson@Sun.COM 21079816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 21089816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 21099816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 21109816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 21119816SGeorge.Wilson@Sun.COM } 21129816SGeorge.Wilson@Sun.COM 21139816SGeorge.Wilson@Sun.COM /* 21149816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 21159816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 21169816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 21179816SGeorge.Wilson@Sun.COM */ 21189816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 21199816SGeorge.Wilson@Sun.COM (void) close(fd); 21209816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 21219816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 21229816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 21239816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 21249816SGeorge.Wilson@Sun.COM } 21259816SGeorge.Wilson@Sun.COM return (0); 21269816SGeorge.Wilson@Sun.COM } 21279816SGeorge.Wilson@Sun.COM 21289816SGeorge.Wilson@Sun.COM /* 21294451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 21304451Seschrock * ZFS_ONLINE_* flags. 2131789Sahrens */ 2132789Sahrens int 21334451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 21344451Seschrock vdev_state_t *newstate) 2135789Sahrens { 2136789Sahrens zfs_cmd_t zc = { 0 }; 2137789Sahrens char msg[1024]; 21382082Seschrock nvlist_t *tgt; 21399816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 21402082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2141789Sahrens 21429816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 21439816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 21449816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 21459816SGeorge.Wilson@Sun.COM } else { 21469816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 21479816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 21489816SGeorge.Wilson@Sun.COM } 2149789Sahrens 21501544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21517326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 21529816SGeorge.Wilson@Sun.COM &islog)) == NULL) 21532082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2154789Sahrens 21552468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 21562468Sek110237 215710817SEric.Schrock@Sun.COM if (avail_spare) 21582082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21592082Seschrock 21609816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 21619816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 21629816SGeorge.Wilson@Sun.COM char *pathname = NULL; 21639816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 21649816SGeorge.Wilson@Sun.COM 21659816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 21669816SGeorge.Wilson@Sun.COM &wholedisk); 21679816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 21689816SGeorge.Wilson@Sun.COM &pathname) == 0); 21699816SGeorge.Wilson@Sun.COM 21709816SGeorge.Wilson@Sun.COM /* 21719816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 21729816SGeorge.Wilson@Sun.COM */ 21739816SGeorge.Wilson@Sun.COM if (l2cache) { 21749816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21759816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 21769816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 21779816SGeorge.Wilson@Sun.COM } 21789816SGeorge.Wilson@Sun.COM 21799816SGeorge.Wilson@Sun.COM if (wholedisk) { 21809816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 218113037SMark.Musante@Sun.COM (void) zpool_relabel_disk(hdl, pathname); 21829816SGeorge.Wilson@Sun.COM } 21839816SGeorge.Wilson@Sun.COM } 21849816SGeorge.Wilson@Sun.COM 21854451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 21864451Seschrock zc.zc_obj = flags; 21874451Seschrock 218813037SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) { 218911422SMark.Musante@Sun.COM if (errno == EINVAL) { 219011422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split " 219111422SMark.Musante@Sun.COM "from this pool into a new one. Use '%s' " 219211422SMark.Musante@Sun.COM "instead"), "zpool detach"); 219311422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg)); 219411422SMark.Musante@Sun.COM } 21954451Seschrock return (zpool_standard_error(hdl, errno, msg)); 219611422SMark.Musante@Sun.COM } 21974451Seschrock 21984451Seschrock *newstate = zc.zc_cookie; 21994451Seschrock return (0); 2200789Sahrens } 2201789Sahrens 2202789Sahrens /* 2203789Sahrens * Take the specified vdev offline 2204789Sahrens */ 2205789Sahrens int 22064451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2207789Sahrens { 2208789Sahrens zfs_cmd_t zc = { 0 }; 2209789Sahrens char msg[1024]; 22102082Seschrock nvlist_t *tgt; 22115450Sbrendan boolean_t avail_spare, l2cache; 22122082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2213789Sahrens 22141544Seschrock (void) snprintf(msg, sizeof (msg), 22151544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 22161544Seschrock 2217789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22187326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22197326SEric.Schrock@Sun.COM NULL)) == NULL) 22202082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22212082Seschrock 22222468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22232468Sek110237 222410817SEric.Schrock@Sun.COM if (avail_spare) 22252082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22262082Seschrock 22274451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 22284451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 22291485Slling 223013037SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2231789Sahrens return (0); 2232789Sahrens 2233789Sahrens switch (errno) { 22342082Seschrock case EBUSY: 2235789Sahrens 2236789Sahrens /* 2237789Sahrens * There are no other replicas of this device. 2238789Sahrens */ 22392082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 22402082Seschrock 22419701SGeorge.Wilson@Sun.COM case EEXIST: 22429701SGeorge.Wilson@Sun.COM /* 22439701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 22449701SGeorge.Wilson@Sun.COM */ 22459701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 22469701SGeorge.Wilson@Sun.COM 22472082Seschrock default: 22482082Seschrock return (zpool_standard_error(hdl, errno, msg)); 22492082Seschrock } 22502082Seschrock } 2251789Sahrens 22522082Seschrock /* 22534451Seschrock * Mark the given vdev faulted. 22544451Seschrock */ 22554451Seschrock int 225610817SEric.Schrock@Sun.COM zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 22574451Seschrock { 22584451Seschrock zfs_cmd_t zc = { 0 }; 22594451Seschrock char msg[1024]; 22604451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22614451Seschrock 22624451Seschrock (void) snprintf(msg, sizeof (msg), 22634451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 22644451Seschrock 22654451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22664451Seschrock zc.zc_guid = guid; 22674451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 226810817SEric.Schrock@Sun.COM zc.zc_obj = aux; 22694451Seschrock 227013037SMark.Musante@Sun.COM if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 22714451Seschrock return (0); 22724451Seschrock 22734451Seschrock switch (errno) { 22744451Seschrock case EBUSY: 22754451Seschrock 22764451Seschrock /* 22774451Seschrock * There are no other replicas of this device. 22784451Seschrock */ 22794451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 22804451Seschrock 22814451Seschrock default: 22824451Seschrock return (zpool_standard_error(hdl, errno, msg)); 22834451Seschrock } 22844451Seschrock 22854451Seschrock } 22864451Seschrock 22874451Seschrock /* 22884451Seschrock * Mark the given vdev degraded. 22894451Seschrock */ 22904451Seschrock int 229110817SEric.Schrock@Sun.COM zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 22924451Seschrock { 22934451Seschrock zfs_cmd_t zc = { 0 }; 22944451Seschrock char msg[1024]; 22954451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22964451Seschrock 22974451Seschrock (void) snprintf(msg, sizeof (msg), 22984451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 22994451Seschrock 23004451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23014451Seschrock zc.zc_guid = guid; 23024451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 230310817SEric.Schrock@Sun.COM zc.zc_obj = aux; 23044451Seschrock 230513037SMark.Musante@Sun.COM if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 23064451Seschrock return (0); 23074451Seschrock 23084451Seschrock return (zpool_standard_error(hdl, errno, msg)); 23094451Seschrock } 23104451Seschrock 23114451Seschrock /* 23122082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 23132082Seschrock * a hot spare. 23142082Seschrock */ 23152082Seschrock static boolean_t 23162082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 23172082Seschrock { 23182082Seschrock nvlist_t **child; 23192082Seschrock uint_t c, children; 23202082Seschrock char *type; 23212082Seschrock 23222082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 23232082Seschrock &children) == 0) { 23242082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 23252082Seschrock &type) == 0); 23262082Seschrock 23272082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 23282082Seschrock children == 2 && child[which] == tgt) 23292082Seschrock return (B_TRUE); 23302082Seschrock 23312082Seschrock for (c = 0; c < children; c++) 23322082Seschrock if (is_replacing_spare(child[c], tgt, which)) 23332082Seschrock return (B_TRUE); 2334789Sahrens } 23352082Seschrock 23362082Seschrock return (B_FALSE); 2337789Sahrens } 2338789Sahrens 2339789Sahrens /* 2340789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 23414527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2342789Sahrens */ 2343789Sahrens int 2344789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2345789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2346789Sahrens { 2347789Sahrens zfs_cmd_t zc = { 0 }; 2348789Sahrens char msg[1024]; 2349789Sahrens int ret; 23502082Seschrock nvlist_t *tgt; 23517326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 23527326SEric.Schrock@Sun.COM uint64_t val; 235313037SMark.Musante@Sun.COM char *newname; 23542082Seschrock nvlist_t **child; 23552082Seschrock uint_t children; 23562082Seschrock nvlist_t *config_root; 23572082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23587965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2359789Sahrens 23601544Seschrock if (replacing) 23611544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 23621544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 23631544Seschrock else 23641544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 23651544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 23661544Seschrock 23677965SGeorge.Wilson@Sun.COM /* 23687965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 23697965SGeorge.Wilson@Sun.COM * EFI labeled device. 23707965SGeorge.Wilson@Sun.COM */ 23717965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 23727965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23737965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 23747965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 23757965SGeorge.Wilson@Sun.COM } 23767965SGeorge.Wilson@Sun.COM 2377789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23787326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 23797326SEric.Schrock@Sun.COM &islog)) == 0) 23802082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23812082Seschrock 23822468Sek110237 if (avail_spare) 23832082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 23842082Seschrock 23855450Sbrendan if (l2cache) 23865450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 23875450Sbrendan 23882082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 23892082Seschrock zc.zc_cookie = replacing; 23902082Seschrock 23912082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 23922082Seschrock &child, &children) != 0 || children != 1) { 23932082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23942082Seschrock "new device must be a single disk")); 23952082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 23961544Seschrock } 23972082Seschrock 23982082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 23992082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 24002082Seschrock 240110594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 24027041Seschrock return (-1); 24037041Seschrock 24042082Seschrock /* 24052082Seschrock * If the target is a hot spare that has been swapped in, we can only 24062082Seschrock * replace it with another hot spare. 24072082Seschrock */ 24082082Seschrock if (replacing && 24092082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 24107326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 24117326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 24127326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 24132082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24142082Seschrock "can only be replaced by another hot spare")); 24157041Seschrock free(newname); 24162082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 24172082Seschrock } 24182082Seschrock 24197041Seschrock free(newname); 24207041Seschrock 24215094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 24222082Seschrock return (-1); 2423789Sahrens 242413037SMark.Musante@Sun.COM ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2425789Sahrens 24262676Seschrock zcmd_free_nvlists(&zc); 2427789Sahrens 24287965SGeorge.Wilson@Sun.COM if (ret == 0) { 24297965SGeorge.Wilson@Sun.COM if (rootpool) { 24307965SGeorge.Wilson@Sun.COM /* 24319790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 24329790SLin.Ling@Sun.COM * booting up a half-baked vdev. 24339790SLin.Ling@Sun.COM */ 24349790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 24359790SLin.Ling@Sun.COM "sure to wait until resilver is done " 24369790SLin.Ling@Sun.COM "before rebooting.\n")); 24377965SGeorge.Wilson@Sun.COM } 2438789Sahrens return (0); 24397965SGeorge.Wilson@Sun.COM } 2440789Sahrens 2441789Sahrens switch (errno) { 24421544Seschrock case ENOTSUP: 2443789Sahrens /* 2444789Sahrens * Can't attach to or replace this type of vdev. 2445789Sahrens */ 24464527Sperrin if (replacing) { 244713037SMark.Musante@Sun.COM uint64_t version = zpool_get_prop_int(zhp, 244813037SMark.Musante@Sun.COM ZPOOL_PROP_VERSION, NULL); 244913037SMark.Musante@Sun.COM 24507326SEric.Schrock@Sun.COM if (islog) 24514527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24524527Sperrin "cannot replace a log with a spare")); 245313037SMark.Musante@Sun.COM else if (version >= SPA_VERSION_MULTI_REPLACE) 245413037SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 245513037SMark.Musante@Sun.COM "already in replacing/spare config; wait " 245613037SMark.Musante@Sun.COM "for completion or use 'zpool detach'")); 24574527Sperrin else 24584527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24594527Sperrin "cannot replace a replacing device")); 24604527Sperrin } else { 24612082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24622082Seschrock "can only attach to mirrors and top-level " 24632082Seschrock "disks")); 24644527Sperrin } 24652082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2466789Sahrens break; 2467789Sahrens 24681544Seschrock case EINVAL: 2469789Sahrens /* 2470789Sahrens * The new device must be a single disk. 2471789Sahrens */ 24722082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24732082Seschrock "new device must be a single disk")); 24742082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2475789Sahrens break; 2476789Sahrens 24771544Seschrock case EBUSY: 24782082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 24792082Seschrock new_disk); 24802082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2481789Sahrens break; 2482789Sahrens 24831544Seschrock case EOVERFLOW: 2484789Sahrens /* 2485789Sahrens * The new device is too small. 2486789Sahrens */ 24872082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24882082Seschrock "device is too small")); 24892082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2490789Sahrens break; 2491789Sahrens 24921544Seschrock case EDOM: 2493789Sahrens /* 2494789Sahrens * The new device has a different alignment requirement. 2495789Sahrens */ 24962082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24972082Seschrock "devices have different sector alignment")); 24982082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2499789Sahrens break; 2500789Sahrens 25011544Seschrock case ENAMETOOLONG: 2502789Sahrens /* 2503789Sahrens * The resulting top-level vdev spec won't fit in the label. 2504789Sahrens */ 25052082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2506789Sahrens break; 2507789Sahrens 25081544Seschrock default: 25092082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2510789Sahrens } 2511789Sahrens 25122082Seschrock return (-1); 2513789Sahrens } 2514789Sahrens 2515789Sahrens /* 2516789Sahrens * Detach the specified device. 2517789Sahrens */ 2518789Sahrens int 2519789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2520789Sahrens { 2521789Sahrens zfs_cmd_t zc = { 0 }; 2522789Sahrens char msg[1024]; 25232082Seschrock nvlist_t *tgt; 25245450Sbrendan boolean_t avail_spare, l2cache; 25252082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2526789Sahrens 25271544Seschrock (void) snprintf(msg, sizeof (msg), 25281544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 25291544Seschrock 2530789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25317326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 25327326SEric.Schrock@Sun.COM NULL)) == 0) 25332082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2534789Sahrens 25352468Sek110237 if (avail_spare) 25362082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 25372082Seschrock 25385450Sbrendan if (l2cache) 25395450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 25405450Sbrendan 25412082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 25422082Seschrock 25434543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2544789Sahrens return (0); 2545789Sahrens 2546789Sahrens switch (errno) { 2547789Sahrens 25481544Seschrock case ENOTSUP: 2549789Sahrens /* 2550789Sahrens * Can't detach from this type of vdev. 2551789Sahrens */ 25522082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 25532082Seschrock "applicable to mirror and replacing vdevs")); 255413037SMark.Musante@Sun.COM (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2555789Sahrens break; 2556789Sahrens 25571544Seschrock case EBUSY: 2558789Sahrens /* 2559789Sahrens * There are no other replicas of this device. 2560789Sahrens */ 25612082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2562789Sahrens break; 2563789Sahrens 25641544Seschrock default: 25652082Seschrock (void) zpool_standard_error(hdl, errno, msg); 25661544Seschrock } 25671544Seschrock 25682082Seschrock return (-1); 25692082Seschrock } 25702082Seschrock 25712082Seschrock /* 257211422SMark.Musante@Sun.COM * Find a mirror vdev in the source nvlist. 257311422SMark.Musante@Sun.COM * 257411422SMark.Musante@Sun.COM * The mchild array contains a list of disks in one of the top-level mirrors 257511422SMark.Musante@Sun.COM * of the source pool. The schild array contains a list of disks that the 257611422SMark.Musante@Sun.COM * user specified on the command line. We loop over the mchild array to 257711422SMark.Musante@Sun.COM * see if any entry in the schild array matches. 257811422SMark.Musante@Sun.COM * 257911422SMark.Musante@Sun.COM * If a disk in the mchild array is found in the schild array, we return 258011422SMark.Musante@Sun.COM * the index of that entry. Otherwise we return -1. 258111422SMark.Musante@Sun.COM */ 258211422SMark.Musante@Sun.COM static int 258311422SMark.Musante@Sun.COM find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren, 258411422SMark.Musante@Sun.COM nvlist_t **schild, uint_t schildren) 258511422SMark.Musante@Sun.COM { 258611422SMark.Musante@Sun.COM uint_t mc; 258711422SMark.Musante@Sun.COM 258811422SMark.Musante@Sun.COM for (mc = 0; mc < mchildren; mc++) { 258911422SMark.Musante@Sun.COM uint_t sc; 259011422SMark.Musante@Sun.COM char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp, 259111422SMark.Musante@Sun.COM mchild[mc], B_FALSE); 259211422SMark.Musante@Sun.COM 259311422SMark.Musante@Sun.COM for (sc = 0; sc < schildren; sc++) { 259411422SMark.Musante@Sun.COM char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp, 259511422SMark.Musante@Sun.COM schild[sc], B_FALSE); 259611422SMark.Musante@Sun.COM boolean_t result = (strcmp(mpath, spath) == 0); 259711422SMark.Musante@Sun.COM 259811422SMark.Musante@Sun.COM free(spath); 259911422SMark.Musante@Sun.COM if (result) { 260011422SMark.Musante@Sun.COM free(mpath); 260111422SMark.Musante@Sun.COM return (mc); 260211422SMark.Musante@Sun.COM } 260311422SMark.Musante@Sun.COM } 260411422SMark.Musante@Sun.COM 260511422SMark.Musante@Sun.COM free(mpath); 260611422SMark.Musante@Sun.COM } 260711422SMark.Musante@Sun.COM 260811422SMark.Musante@Sun.COM return (-1); 260911422SMark.Musante@Sun.COM } 261011422SMark.Musante@Sun.COM 261111422SMark.Musante@Sun.COM /* 261211422SMark.Musante@Sun.COM * Split a mirror pool. If newroot points to null, then a new nvlist 261311422SMark.Musante@Sun.COM * is generated and it is the responsibility of the caller to free it. 261411422SMark.Musante@Sun.COM */ 261511422SMark.Musante@Sun.COM int 261611422SMark.Musante@Sun.COM zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot, 261711422SMark.Musante@Sun.COM nvlist_t *props, splitflags_t flags) 261811422SMark.Musante@Sun.COM { 261911422SMark.Musante@Sun.COM zfs_cmd_t zc = { 0 }; 262011422SMark.Musante@Sun.COM char msg[1024]; 262111422SMark.Musante@Sun.COM nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL; 262211422SMark.Musante@Sun.COM nvlist_t **varray = NULL, *zc_props = NULL; 262311422SMark.Musante@Sun.COM uint_t c, children, newchildren, lastlog = 0, vcount, found = 0; 262411422SMark.Musante@Sun.COM libzfs_handle_t *hdl = zhp->zpool_hdl; 262511422SMark.Musante@Sun.COM uint64_t vers; 262611422SMark.Musante@Sun.COM boolean_t freelist = B_FALSE, memory_err = B_TRUE; 262711422SMark.Musante@Sun.COM int retval = 0; 262811422SMark.Musante@Sun.COM 262911422SMark.Musante@Sun.COM (void) snprintf(msg, sizeof (msg), 263011422SMark.Musante@Sun.COM dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name); 263111422SMark.Musante@Sun.COM 263211422SMark.Musante@Sun.COM if (!zpool_name_valid(hdl, B_FALSE, newname)) 263311422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 263411422SMark.Musante@Sun.COM 263511422SMark.Musante@Sun.COM if ((config = zpool_get_config(zhp, NULL)) == NULL) { 263611422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Internal error: unable to " 263711422SMark.Musante@Sun.COM "retrieve pool configuration\n")); 263811422SMark.Musante@Sun.COM return (-1); 263911422SMark.Musante@Sun.COM } 264011422SMark.Musante@Sun.COM 264111422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) 264211422SMark.Musante@Sun.COM == 0); 264311422SMark.Musante@Sun.COM verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0); 264411422SMark.Musante@Sun.COM 264511422SMark.Musante@Sun.COM if (props) { 2646*13049SGeorge.Wilson@Sun.COM prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 264711422SMark.Musante@Sun.COM if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name, 2648*13049SGeorge.Wilson@Sun.COM props, vers, flags, msg)) == NULL) 264911422SMark.Musante@Sun.COM return (-1); 265011422SMark.Musante@Sun.COM } 265111422SMark.Musante@Sun.COM 265211422SMark.Musante@Sun.COM if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, 265311422SMark.Musante@Sun.COM &children) != 0) { 265411422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 265511422SMark.Musante@Sun.COM "Source pool is missing vdev tree")); 265611422SMark.Musante@Sun.COM if (zc_props) 265711422SMark.Musante@Sun.COM nvlist_free(zc_props); 265811422SMark.Musante@Sun.COM return (-1); 265911422SMark.Musante@Sun.COM } 266011422SMark.Musante@Sun.COM 266111422SMark.Musante@Sun.COM varray = zfs_alloc(hdl, children * sizeof (nvlist_t *)); 266211422SMark.Musante@Sun.COM vcount = 0; 266311422SMark.Musante@Sun.COM 266411422SMark.Musante@Sun.COM if (*newroot == NULL || 266511422SMark.Musante@Sun.COM nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, 266611422SMark.Musante@Sun.COM &newchild, &newchildren) != 0) 266711422SMark.Musante@Sun.COM newchildren = 0; 266811422SMark.Musante@Sun.COM 266911422SMark.Musante@Sun.COM for (c = 0; c < children; c++) { 267011422SMark.Musante@Sun.COM uint64_t is_log = B_FALSE, is_hole = B_FALSE; 267111422SMark.Musante@Sun.COM char *type; 267211422SMark.Musante@Sun.COM nvlist_t **mchild, *vdev; 267311422SMark.Musante@Sun.COM uint_t mchildren; 267411422SMark.Musante@Sun.COM int entry; 267511422SMark.Musante@Sun.COM 267611422SMark.Musante@Sun.COM /* 267711422SMark.Musante@Sun.COM * Unlike cache & spares, slogs are stored in the 267811422SMark.Musante@Sun.COM * ZPOOL_CONFIG_CHILDREN array. We filter them out here. 267911422SMark.Musante@Sun.COM */ 268011422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 268111422SMark.Musante@Sun.COM &is_log); 268211422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 268311422SMark.Musante@Sun.COM &is_hole); 268411422SMark.Musante@Sun.COM if (is_log || is_hole) { 268511422SMark.Musante@Sun.COM /* 268611422SMark.Musante@Sun.COM * Create a hole vdev and put it in the config. 268711422SMark.Musante@Sun.COM */ 268811422SMark.Musante@Sun.COM if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0) 268911422SMark.Musante@Sun.COM goto out; 269011422SMark.Musante@Sun.COM if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, 269111422SMark.Musante@Sun.COM VDEV_TYPE_HOLE) != 0) 269211422SMark.Musante@Sun.COM goto out; 269311422SMark.Musante@Sun.COM if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE, 269411422SMark.Musante@Sun.COM 1) != 0) 269511422SMark.Musante@Sun.COM goto out; 269611422SMark.Musante@Sun.COM if (lastlog == 0) 269711422SMark.Musante@Sun.COM lastlog = vcount; 269811422SMark.Musante@Sun.COM varray[vcount++] = vdev; 269911422SMark.Musante@Sun.COM continue; 270011422SMark.Musante@Sun.COM } 270111422SMark.Musante@Sun.COM lastlog = 0; 270211422SMark.Musante@Sun.COM verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type) 270311422SMark.Musante@Sun.COM == 0); 270411422SMark.Musante@Sun.COM if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 270511422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 270611422SMark.Musante@Sun.COM "Source pool must be composed only of mirrors\n")); 270711422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 270811422SMark.Musante@Sun.COM goto out; 270911422SMark.Musante@Sun.COM } 271011422SMark.Musante@Sun.COM 271111422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist_array(child[c], 271211422SMark.Musante@Sun.COM ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0); 271311422SMark.Musante@Sun.COM 271411422SMark.Musante@Sun.COM /* find or add an entry for this top-level vdev */ 271511422SMark.Musante@Sun.COM if (newchildren > 0 && 271611422SMark.Musante@Sun.COM (entry = find_vdev_entry(zhp, mchild, mchildren, 271711422SMark.Musante@Sun.COM newchild, newchildren)) >= 0) { 271811422SMark.Musante@Sun.COM /* We found a disk that the user specified. */ 271911422SMark.Musante@Sun.COM vdev = mchild[entry]; 272011422SMark.Musante@Sun.COM ++found; 272111422SMark.Musante@Sun.COM } else { 272211422SMark.Musante@Sun.COM /* User didn't specify a disk for this vdev. */ 272311422SMark.Musante@Sun.COM vdev = mchild[mchildren - 1]; 272411422SMark.Musante@Sun.COM } 272511422SMark.Musante@Sun.COM 272611422SMark.Musante@Sun.COM if (nvlist_dup(vdev, &varray[vcount++], 0) != 0) 272711422SMark.Musante@Sun.COM goto out; 272811422SMark.Musante@Sun.COM } 272911422SMark.Musante@Sun.COM 273011422SMark.Musante@Sun.COM /* did we find every disk the user specified? */ 273111422SMark.Musante@Sun.COM if (found != newchildren) { 273211422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must " 273311422SMark.Musante@Sun.COM "include at most one disk from each mirror")); 273411422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 273511422SMark.Musante@Sun.COM goto out; 273611422SMark.Musante@Sun.COM } 273711422SMark.Musante@Sun.COM 273811422SMark.Musante@Sun.COM /* Prepare the nvlist for populating. */ 273911422SMark.Musante@Sun.COM if (*newroot == NULL) { 274011422SMark.Musante@Sun.COM if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0) 274111422SMark.Musante@Sun.COM goto out; 274211422SMark.Musante@Sun.COM freelist = B_TRUE; 274311422SMark.Musante@Sun.COM if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE, 274411422SMark.Musante@Sun.COM VDEV_TYPE_ROOT) != 0) 274511422SMark.Musante@Sun.COM goto out; 274611422SMark.Musante@Sun.COM } else { 274711422SMark.Musante@Sun.COM verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0); 274811422SMark.Musante@Sun.COM } 274911422SMark.Musante@Sun.COM 275011422SMark.Musante@Sun.COM /* Add all the children we found */ 275111422SMark.Musante@Sun.COM if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray, 275211422SMark.Musante@Sun.COM lastlog == 0 ? vcount : lastlog) != 0) 275311422SMark.Musante@Sun.COM goto out; 275411422SMark.Musante@Sun.COM 275511422SMark.Musante@Sun.COM /* 275611422SMark.Musante@Sun.COM * If we're just doing a dry run, exit now with success. 275711422SMark.Musante@Sun.COM */ 275811422SMark.Musante@Sun.COM if (flags.dryrun) { 275911422SMark.Musante@Sun.COM memory_err = B_FALSE; 276011422SMark.Musante@Sun.COM freelist = B_FALSE; 276111422SMark.Musante@Sun.COM goto out; 276211422SMark.Musante@Sun.COM } 276311422SMark.Musante@Sun.COM 276411422SMark.Musante@Sun.COM /* now build up the config list & call the ioctl */ 276511422SMark.Musante@Sun.COM if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0) 276611422SMark.Musante@Sun.COM goto out; 276711422SMark.Musante@Sun.COM 276811422SMark.Musante@Sun.COM if (nvlist_add_nvlist(newconfig, 276911422SMark.Musante@Sun.COM ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 || 277011422SMark.Musante@Sun.COM nvlist_add_string(newconfig, 277111422SMark.Musante@Sun.COM ZPOOL_CONFIG_POOL_NAME, newname) != 0 || 277211422SMark.Musante@Sun.COM nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0) 277311422SMark.Musante@Sun.COM goto out; 277411422SMark.Musante@Sun.COM 277511422SMark.Musante@Sun.COM /* 277611422SMark.Musante@Sun.COM * The new pool is automatically part of the namespace unless we 277711422SMark.Musante@Sun.COM * explicitly export it. 277811422SMark.Musante@Sun.COM */ 277911422SMark.Musante@Sun.COM if (!flags.import) 278011422SMark.Musante@Sun.COM zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT; 278111422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 278211422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string)); 278311422SMark.Musante@Sun.COM if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0) 278411422SMark.Musante@Sun.COM goto out; 278511422SMark.Musante@Sun.COM if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 278611422SMark.Musante@Sun.COM goto out; 278711422SMark.Musante@Sun.COM 278811422SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) { 278911422SMark.Musante@Sun.COM retval = zpool_standard_error(hdl, errno, msg); 279011422SMark.Musante@Sun.COM goto out; 279111422SMark.Musante@Sun.COM } 279211422SMark.Musante@Sun.COM 279311422SMark.Musante@Sun.COM freelist = B_FALSE; 279411422SMark.Musante@Sun.COM memory_err = B_FALSE; 279511422SMark.Musante@Sun.COM 279611422SMark.Musante@Sun.COM out: 279711422SMark.Musante@Sun.COM if (varray != NULL) { 279811422SMark.Musante@Sun.COM int v; 279911422SMark.Musante@Sun.COM 280011422SMark.Musante@Sun.COM for (v = 0; v < vcount; v++) 280111422SMark.Musante@Sun.COM nvlist_free(varray[v]); 280211422SMark.Musante@Sun.COM free(varray); 280311422SMark.Musante@Sun.COM } 280411422SMark.Musante@Sun.COM zcmd_free_nvlists(&zc); 280511422SMark.Musante@Sun.COM if (zc_props) 280611422SMark.Musante@Sun.COM nvlist_free(zc_props); 280711422SMark.Musante@Sun.COM if (newconfig) 280811422SMark.Musante@Sun.COM nvlist_free(newconfig); 280911422SMark.Musante@Sun.COM if (freelist) { 281011422SMark.Musante@Sun.COM nvlist_free(*newroot); 281111422SMark.Musante@Sun.COM *newroot = NULL; 281211422SMark.Musante@Sun.COM } 281311422SMark.Musante@Sun.COM 281411422SMark.Musante@Sun.COM if (retval != 0) 281511422SMark.Musante@Sun.COM return (retval); 281611422SMark.Musante@Sun.COM 281711422SMark.Musante@Sun.COM if (memory_err) 281811422SMark.Musante@Sun.COM return (no_memory(hdl)); 281911422SMark.Musante@Sun.COM 282011422SMark.Musante@Sun.COM return (0); 282111422SMark.Musante@Sun.COM } 282211422SMark.Musante@Sun.COM 282311422SMark.Musante@Sun.COM /* 28245450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 28255450Sbrendan * and level 2 cache devices. 28262082Seschrock */ 28272082Seschrock int 28282082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 28292082Seschrock { 28302082Seschrock zfs_cmd_t zc = { 0 }; 28312082Seschrock char msg[1024]; 28322082Seschrock nvlist_t *tgt; 283310594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 28342082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 283510594SGeorge.Wilson@Sun.COM uint64_t version; 28362082Seschrock 28372082Seschrock (void) snprintf(msg, sizeof (msg), 28382082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 28392082Seschrock 28402082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28417326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 284210594SGeorge.Wilson@Sun.COM &islog)) == 0) 28432082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 284410594SGeorge.Wilson@Sun.COM /* 284510594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 284610594SGeorge.Wilson@Sun.COM */ 284710594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 28482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 284910594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 285010594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 28512082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 28522082Seschrock } 28532082Seschrock 285410594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 285510594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 285610594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 285710594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 285810594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 285910594SGeorge.Wilson@Sun.COM } 286010594SGeorge.Wilson@Sun.COM 28612082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 28622082Seschrock 28634543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 28642082Seschrock return (0); 28652082Seschrock 28662082Seschrock return (zpool_standard_error(hdl, errno, msg)); 28671544Seschrock } 28681544Seschrock 28691544Seschrock /* 28701544Seschrock * Clear the errors for the pool, or the particular device if specified. 28711544Seschrock */ 28721544Seschrock int 287310921STim.Haley@Sun.COM zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 28741544Seschrock { 28751544Seschrock zfs_cmd_t zc = { 0 }; 28761544Seschrock char msg[1024]; 28772082Seschrock nvlist_t *tgt; 287810921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 28795450Sbrendan boolean_t avail_spare, l2cache; 28802082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 288110921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 288212949SGeorge.Wilson@Sun.COM int error; 28831544Seschrock 28841544Seschrock if (path) 28851544Seschrock (void) snprintf(msg, sizeof (msg), 28861544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 28872676Seschrock path); 28881544Seschrock else 28891544Seschrock (void) snprintf(msg, sizeof (msg), 28901544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 28911544Seschrock zhp->zpool_name); 28921544Seschrock 28931544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28942082Seschrock if (path) { 28955450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 28967326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 28972082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 28982082Seschrock 28995450Sbrendan /* 29005450Sbrendan * Don't allow error clearing for hot spares. Do allow 29015450Sbrendan * error clearing for l2cache devices. 29025450Sbrendan */ 29032468Sek110237 if (avail_spare) 29042082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 29052082Seschrock 29062082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 29072082Seschrock &zc.zc_guid) == 0); 29081544Seschrock } 29091544Seschrock 291010921STim.Haley@Sun.COM zpool_get_rewind_policy(rewindnvl, &policy); 291110921STim.Haley@Sun.COM zc.zc_cookie = policy.zrp_request; 291210921STim.Haley@Sun.COM 291312974SGeorge.Wilson@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0) 291410921STim.Haley@Sun.COM return (-1); 291510921STim.Haley@Sun.COM 291613037SMark.Musante@Sun.COM if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0) 291710921STim.Haley@Sun.COM return (-1); 291810921STim.Haley@Sun.COM 291912949SGeorge.Wilson@Sun.COM while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 && 292012949SGeorge.Wilson@Sun.COM errno == ENOMEM) { 292112949SGeorge.Wilson@Sun.COM if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 292212949SGeorge.Wilson@Sun.COM zcmd_free_nvlists(&zc); 292312949SGeorge.Wilson@Sun.COM return (-1); 292412949SGeorge.Wilson@Sun.COM } 292512949SGeorge.Wilson@Sun.COM } 292612949SGeorge.Wilson@Sun.COM 292712949SGeorge.Wilson@Sun.COM if (!error || ((policy.zrp_request & ZPOOL_TRY_REWIND) && 292810921STim.Haley@Sun.COM errno != EPERM && errno != EACCES)) { 292910921STim.Haley@Sun.COM if (policy.zrp_request & 293010921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 293110921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 293210921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, zc.zc_name, 293310921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 293410921STim.Haley@Sun.COM nvi); 293510921STim.Haley@Sun.COM nvlist_free(nvi); 293610921STim.Haley@Sun.COM } 293710921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 29381544Seschrock return (0); 293910921STim.Haley@Sun.COM } 294010921STim.Haley@Sun.COM 294110921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 29422082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2943789Sahrens } 2944789Sahrens 29453126Sahl /* 29464451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 29474451Seschrock */ 29484451Seschrock int 29494451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 29504451Seschrock { 29514451Seschrock zfs_cmd_t zc = { 0 }; 29524451Seschrock char msg[1024]; 29534451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 29544451Seschrock 29554451Seschrock (void) snprintf(msg, sizeof (msg), 29564451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 29574451Seschrock guid); 29584451Seschrock 29594451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29604451Seschrock zc.zc_guid = guid; 296112441SVictor.Latushkin@Sun.COM zc.zc_cookie = ZPOOL_NO_REWIND; 29624451Seschrock 29634451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 29644451Seschrock return (0); 29654451Seschrock 29664451Seschrock return (zpool_standard_error(hdl, errno, msg)); 29674451Seschrock } 29684451Seschrock 29694451Seschrock /* 29701354Seschrock * Convert from a devid string to a path. 29711354Seschrock */ 29721354Seschrock static char * 29731354Seschrock devid_to_path(char *devid_str) 29741354Seschrock { 29751354Seschrock ddi_devid_t devid; 29761354Seschrock char *minor; 29771354Seschrock char *path; 29781354Seschrock devid_nmlist_t *list = NULL; 29791354Seschrock int ret; 29801354Seschrock 29811354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 29821354Seschrock return (NULL); 29831354Seschrock 29841354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 29851354Seschrock 29861354Seschrock devid_str_free(minor); 29871354Seschrock devid_free(devid); 29881354Seschrock 29891354Seschrock if (ret != 0) 29901354Seschrock return (NULL); 29911354Seschrock 29922082Seschrock if ((path = strdup(list[0].devname)) == NULL) 29932082Seschrock return (NULL); 29942082Seschrock 29951354Seschrock devid_free_nmlist(list); 29961354Seschrock 29971354Seschrock return (path); 29981354Seschrock } 29991354Seschrock 30001354Seschrock /* 30011354Seschrock * Convert from a path to a devid string. 30021354Seschrock */ 30031354Seschrock static char * 30041354Seschrock path_to_devid(const char *path) 30051354Seschrock { 30061354Seschrock int fd; 30071354Seschrock ddi_devid_t devid; 30081354Seschrock char *minor, *ret; 30091354Seschrock 30101354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 30111354Seschrock return (NULL); 30121354Seschrock 30131354Seschrock minor = NULL; 30141354Seschrock ret = NULL; 30151354Seschrock if (devid_get(fd, &devid) == 0) { 30161354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 30171354Seschrock ret = devid_str_encode(devid, minor); 30181354Seschrock if (minor != NULL) 30191354Seschrock devid_str_free(minor); 30201354Seschrock devid_free(devid); 30211354Seschrock } 30221354Seschrock (void) close(fd); 30231354Seschrock 30241354Seschrock return (ret); 30251354Seschrock } 30261354Seschrock 30271354Seschrock /* 30281354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 30291354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 30301354Seschrock * type 'zpool status', and we'll display the correct information anyway. 30311354Seschrock */ 30321354Seschrock static void 30331354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 30341354Seschrock { 30351354Seschrock zfs_cmd_t zc = { 0 }; 30361354Seschrock 30371354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 30382676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 30391354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 30401544Seschrock &zc.zc_guid) == 0); 30411354Seschrock 30422082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 30431354Seschrock } 30441354Seschrock 30451354Seschrock /* 30461354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 30471354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 30481354Seschrock * We also check if this is a whole disk, in which case we strip off the 30491354Seschrock * trailing 's0' slice name. 30501354Seschrock * 30511354Seschrock * This routine is also responsible for identifying when disks have been 30521354Seschrock * reconfigured in a new location. The kernel will have opened the device by 30531354Seschrock * devid, but the path will still refer to the old location. To catch this, we 30541354Seschrock * first do a path -> devid translation (which is fast for the common case). If 30551354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 30561354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 30571354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 30581354Seschrock * of these checks. 30591354Seschrock */ 30601354Seschrock char * 306110594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 306210594SGeorge.Wilson@Sun.COM boolean_t verbose) 30631354Seschrock { 30641354Seschrock char *path, *devid; 30651544Seschrock uint64_t value; 30661544Seschrock char buf[64]; 30674451Seschrock vdev_stat_t *vs; 30684451Seschrock uint_t vsc; 30691354Seschrock 30701544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 30711544Seschrock &value) == 0) { 30721544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 30731544Seschrock &value) == 0); 30742856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 30752856Snd150628 (u_longlong_t)value); 30761544Seschrock path = buf; 30771544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 30781354Seschrock 30794451Seschrock /* 30804451Seschrock * If the device is dead (faulted, offline, etc) then don't 30814451Seschrock * bother opening it. Otherwise we may be forcing the user to 30824451Seschrock * open a misbehaving device, which can have undesirable 30834451Seschrock * effects. 30844451Seschrock */ 308512296SLin.Ling@Sun.COM if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 30864451Seschrock (uint64_t **)&vs, &vsc) != 0 || 30874451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 30884451Seschrock zhp != NULL && 30891354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 30901354Seschrock /* 30911354Seschrock * Determine if the current path is correct. 30921354Seschrock */ 30931354Seschrock char *newdevid = path_to_devid(path); 30941354Seschrock 30951354Seschrock if (newdevid == NULL || 30961354Seschrock strcmp(devid, newdevid) != 0) { 30971354Seschrock char *newpath; 30981354Seschrock 30991354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 31001354Seschrock /* 31011354Seschrock * Update the path appropriately. 31021354Seschrock */ 31031354Seschrock set_path(zhp, nv, newpath); 31042082Seschrock if (nvlist_add_string(nv, 31052082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 31062082Seschrock verify(nvlist_lookup_string(nv, 31072082Seschrock ZPOOL_CONFIG_PATH, 31082082Seschrock &path) == 0); 31091354Seschrock free(newpath); 31101354Seschrock } 31111354Seschrock } 31121354Seschrock 31132082Seschrock if (newdevid) 31142082Seschrock devid_str_free(newdevid); 31151354Seschrock } 31161354Seschrock 31171354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 31181354Seschrock path += 9; 31191354Seschrock 31201354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 31211544Seschrock &value) == 0 && value) { 312212383SJohn.Harres@Sun.COM int pathlen = strlen(path); 31232082Seschrock char *tmp = zfs_strdup(hdl, path); 312412383SJohn.Harres@Sun.COM 312512383SJohn.Harres@Sun.COM /* 312612383SJohn.Harres@Sun.COM * If it starts with c#, and ends with "s0", chop 312712383SJohn.Harres@Sun.COM * the "s0" off, or if it ends with "s0/old", remove 312812383SJohn.Harres@Sun.COM * the "s0" from the middle. 312912383SJohn.Harres@Sun.COM */ 313012383SJohn.Harres@Sun.COM if (CTD_CHECK(tmp)) { 313112383SJohn.Harres@Sun.COM if (strcmp(&tmp[pathlen - 2], "s0") == 0) { 313212383SJohn.Harres@Sun.COM tmp[pathlen - 2] = '\0'; 313312383SJohn.Harres@Sun.COM } else if (pathlen > 6 && 313412383SJohn.Harres@Sun.COM strcmp(&tmp[pathlen - 6], "s0/old") == 0) { 313512383SJohn.Harres@Sun.COM (void) strcpy(&tmp[pathlen - 6], 313612383SJohn.Harres@Sun.COM "/old"); 313712383SJohn.Harres@Sun.COM } 313812383SJohn.Harres@Sun.COM } 31391354Seschrock return (tmp); 31401354Seschrock } 31411354Seschrock } else { 31421354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 31432082Seschrock 31442082Seschrock /* 31452082Seschrock * If it's a raidz device, we need to stick in the parity level. 31462082Seschrock */ 31472082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 31482082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 31492082Seschrock &value) == 0); 31502082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 31512856Snd150628 (u_longlong_t)value); 31522082Seschrock path = buf; 31532082Seschrock } 315410594SGeorge.Wilson@Sun.COM 315510594SGeorge.Wilson@Sun.COM /* 315610594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 315710594SGeorge.Wilson@Sun.COM * naming convention. 315810594SGeorge.Wilson@Sun.COM */ 315910594SGeorge.Wilson@Sun.COM if (verbose) { 316010594SGeorge.Wilson@Sun.COM uint64_t id; 316110594SGeorge.Wilson@Sun.COM 316210594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 316310594SGeorge.Wilson@Sun.COM &id) == 0); 316410594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 316510594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 316610594SGeorge.Wilson@Sun.COM path = buf; 316710594SGeorge.Wilson@Sun.COM } 31681354Seschrock } 31691354Seschrock 31702082Seschrock return (zfs_strdup(hdl, path)); 31711354Seschrock } 31721544Seschrock 31731544Seschrock static int 31741544Seschrock zbookmark_compare(const void *a, const void *b) 31751544Seschrock { 31761544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 31771544Seschrock } 31781544Seschrock 31791544Seschrock /* 31801544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 31811544Seschrock * caller. 31821544Seschrock */ 31831544Seschrock int 31843444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 31851544Seschrock { 31861544Seschrock zfs_cmd_t zc = { 0 }; 31871544Seschrock uint64_t count; 31882676Seschrock zbookmark_t *zb = NULL; 31893444Sek110237 int i; 31901544Seschrock 31911544Seschrock /* 31921544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 31931544Seschrock * has increased, allocate more space and continue until we get the 31941544Seschrock * entire list. 31951544Seschrock */ 31961544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 31971544Seschrock &count) == 0); 31984820Sek110237 if (count == 0) 31994820Sek110237 return (0); 32002676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 32012856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 32022082Seschrock return (-1); 32032676Seschrock zc.zc_nvlist_dst_size = count; 32041544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 32051544Seschrock for (;;) { 32062082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 32072082Seschrock &zc) != 0) { 32082676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 32091544Seschrock if (errno == ENOMEM) { 32103823Svb160487 count = zc.zc_nvlist_dst_size; 32112676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 32123823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 32133823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 32142082Seschrock return (-1); 32151544Seschrock } else { 32161544Seschrock return (-1); 32171544Seschrock } 32181544Seschrock } else { 32191544Seschrock break; 32201544Seschrock } 32211544Seschrock } 32221544Seschrock 32231544Seschrock /* 32241544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 32251544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 32262676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 32271544Seschrock * _not_ copied as part of the process. So we point the start of our 32281544Seschrock * array appropriate and decrement the total number of elements. 32291544Seschrock */ 32302676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 32312676Seschrock zc.zc_nvlist_dst_size; 32322676Seschrock count -= zc.zc_nvlist_dst_size; 32331544Seschrock 32341544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 32351544Seschrock 32363444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 32371544Seschrock 32381544Seschrock /* 32393444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 32401544Seschrock */ 32411544Seschrock for (i = 0; i < count; i++) { 32421544Seschrock nvlist_t *nv; 32431544Seschrock 32443700Sek110237 /* ignoring zb_blkid and zb_level for now */ 32453700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 32463700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 32471544Seschrock continue; 32481544Seschrock 32493444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 32503444Sek110237 goto nomem; 32513444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 32523444Sek110237 zb[i].zb_objset) != 0) { 32533444Sek110237 nvlist_free(nv); 32542082Seschrock goto nomem; 32553444Sek110237 } 32563444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 32573444Sek110237 zb[i].zb_object) != 0) { 32583444Sek110237 nvlist_free(nv); 32593444Sek110237 goto nomem; 32601544Seschrock } 32613444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 32623444Sek110237 nvlist_free(nv); 32633444Sek110237 goto nomem; 32643444Sek110237 } 32653444Sek110237 nvlist_free(nv); 32661544Seschrock } 32671544Seschrock 32683265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 32691544Seschrock return (0); 32702082Seschrock 32712082Seschrock nomem: 32722676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 32732082Seschrock return (no_memory(zhp->zpool_hdl)); 32741544Seschrock } 32751760Seschrock 32761760Seschrock /* 32771760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 32781760Seschrock */ 32791760Seschrock int 32805094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 32811760Seschrock { 32821760Seschrock zfs_cmd_t zc = { 0 }; 32832082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 32841760Seschrock 32851760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 32865094Slling zc.zc_cookie = new_version; 32875094Slling 32884543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 32893237Slling return (zpool_standard_error_fmt(hdl, errno, 32902082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 32912082Seschrock zhp->zpool_name)); 32921760Seschrock return (0); 32931760Seschrock } 32942926Sek110237 32954988Sek110237 void 32964988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 32974988Sek110237 char *history_str) 32984988Sek110237 { 32994988Sek110237 int i; 33004988Sek110237 33014988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 33024988Sek110237 for (i = 1; i < argc; i++) { 33034988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 33044988Sek110237 HIS_MAX_RECORD_LEN) 33054988Sek110237 break; 33064988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 33074988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 33084988Sek110237 } 33094988Sek110237 } 33104988Sek110237 33112926Sek110237 /* 33124988Sek110237 * Stage command history for logging. 33132926Sek110237 */ 33144988Sek110237 int 33154988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 33162926Sek110237 { 33174988Sek110237 if (history_str == NULL) 33184988Sek110237 return (EINVAL); 33194988Sek110237 33204988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 33214988Sek110237 return (EINVAL); 33222926Sek110237 33234715Sek110237 if (hdl->libzfs_log_str != NULL) 33244543Smarks free(hdl->libzfs_log_str); 33252926Sek110237 33264988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 33274988Sek110237 return (no_memory(hdl)); 33284543Smarks 33294988Sek110237 return (0); 33302926Sek110237 } 33312926Sek110237 33322926Sek110237 /* 33332926Sek110237 * Perform ioctl to get some command history of a pool. 33342926Sek110237 * 33352926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 33362926Sek110237 * logical offset of the history buffer to start reading from. 33372926Sek110237 * 33382926Sek110237 * Upon return, 'off' is the next logical offset to read from and 33392926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 33402926Sek110237 */ 33412926Sek110237 static int 33422926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 33432926Sek110237 { 33442926Sek110237 zfs_cmd_t zc = { 0 }; 33452926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 33462926Sek110237 33472926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 33482926Sek110237 33492926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 33502926Sek110237 zc.zc_history_len = *len; 33512926Sek110237 zc.zc_history_offset = *off; 33522926Sek110237 33532926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 33542926Sek110237 switch (errno) { 33552926Sek110237 case EPERM: 33563237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 33573237Slling dgettext(TEXT_DOMAIN, 33582926Sek110237 "cannot show history for pool '%s'"), 33592926Sek110237 zhp->zpool_name)); 33602926Sek110237 case ENOENT: 33613237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 33622926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 33632926Sek110237 "'%s'"), zhp->zpool_name)); 33643863Sek110237 case ENOTSUP: 33653863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 33663863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 33673863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 33682926Sek110237 default: 33693237Slling return (zpool_standard_error_fmt(hdl, errno, 33702926Sek110237 dgettext(TEXT_DOMAIN, 33712926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 33722926Sek110237 } 33732926Sek110237 } 33742926Sek110237 33752926Sek110237 *len = zc.zc_history_len; 33762926Sek110237 *off = zc.zc_history_offset; 33772926Sek110237 33782926Sek110237 return (0); 33792926Sek110237 } 33802926Sek110237 33812926Sek110237 /* 33822926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 33832926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 33842926Sek110237 * processed as there wasn't a complete record. 33852926Sek110237 */ 338610685SGeorge.Wilson@Sun.COM int 33872926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 33882926Sek110237 nvlist_t ***records, uint_t *numrecords) 33892926Sek110237 { 33902926Sek110237 uint64_t reclen; 33912926Sek110237 nvlist_t *nv; 33922926Sek110237 int i; 33932926Sek110237 33942926Sek110237 while (bytes_read > sizeof (reclen)) { 33952926Sek110237 33962926Sek110237 /* get length of packed record (stored as little endian) */ 33972926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 33982926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 33992926Sek110237 34002926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 34012926Sek110237 break; 34022926Sek110237 34032926Sek110237 /* unpack record */ 34042926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 34052926Sek110237 return (ENOMEM); 34062926Sek110237 bytes_read -= sizeof (reclen) + reclen; 34072926Sek110237 buf += sizeof (reclen) + reclen; 34082926Sek110237 34092926Sek110237 /* add record to nvlist array */ 34102926Sek110237 (*numrecords)++; 34112926Sek110237 if (ISP2(*numrecords + 1)) { 34122926Sek110237 *records = realloc(*records, 34132926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 34142926Sek110237 } 34152926Sek110237 (*records)[*numrecords - 1] = nv; 34162926Sek110237 } 34172926Sek110237 34182926Sek110237 *leftover = bytes_read; 34192926Sek110237 return (0); 34202926Sek110237 } 34212926Sek110237 34222926Sek110237 #define HIS_BUF_LEN (128*1024) 34232926Sek110237 34242926Sek110237 /* 34252926Sek110237 * Retrieve the command history of a pool. 34262926Sek110237 */ 34272926Sek110237 int 34282926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 34292926Sek110237 { 34302926Sek110237 char buf[HIS_BUF_LEN]; 34312926Sek110237 uint64_t off = 0; 34322926Sek110237 nvlist_t **records = NULL; 34332926Sek110237 uint_t numrecords = 0; 34342926Sek110237 int err, i; 34352926Sek110237 34362926Sek110237 do { 34372926Sek110237 uint64_t bytes_read = sizeof (buf); 34382926Sek110237 uint64_t leftover; 34392926Sek110237 34402926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 34412926Sek110237 break; 34422926Sek110237 34432926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 34442926Sek110237 if (!bytes_read) 34452926Sek110237 break; 34462926Sek110237 34472926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 34482926Sek110237 &leftover, &records, &numrecords)) != 0) 34492926Sek110237 break; 34502926Sek110237 off -= leftover; 34512926Sek110237 34522926Sek110237 /* CONSTCOND */ 34532926Sek110237 } while (1); 34542926Sek110237 34552926Sek110237 if (!err) { 34562926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 34572926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 34582926Sek110237 records, numrecords) == 0); 34592926Sek110237 } 34602926Sek110237 for (i = 0; i < numrecords; i++) 34612926Sek110237 nvlist_free(records[i]); 34622926Sek110237 free(records); 34632926Sek110237 34642926Sek110237 return (err); 34652926Sek110237 } 34663444Sek110237 34673444Sek110237 void 34683444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 34693444Sek110237 char *pathname, size_t len) 34703444Sek110237 { 34713444Sek110237 zfs_cmd_t zc = { 0 }; 34723444Sek110237 boolean_t mounted = B_FALSE; 34733444Sek110237 char *mntpnt = NULL; 34743444Sek110237 char dsname[MAXNAMELEN]; 34753444Sek110237 34763444Sek110237 if (dsobj == 0) { 34773444Sek110237 /* special case for the MOS */ 34783444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 34793444Sek110237 return; 34803444Sek110237 } 34813444Sek110237 34823444Sek110237 /* get the dataset's name */ 34833444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 34843444Sek110237 zc.zc_obj = dsobj; 34853444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 34863444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 34873444Sek110237 /* just write out a path of two object numbers */ 34883444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 34893444Sek110237 dsobj, obj); 34903444Sek110237 return; 34913444Sek110237 } 34923444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 34933444Sek110237 34943444Sek110237 /* find out if the dataset is mounted */ 34953444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 34963444Sek110237 34973444Sek110237 /* get the corrupted object's path */ 34983444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 34993444Sek110237 zc.zc_obj = obj; 35003444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 35013444Sek110237 &zc) == 0) { 35023444Sek110237 if (mounted) { 35033444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 35043444Sek110237 zc.zc_value); 35053444Sek110237 } else { 35063444Sek110237 (void) snprintf(pathname, len, "%s:%s", 35073444Sek110237 dsname, zc.zc_value); 35083444Sek110237 } 35093444Sek110237 } else { 35103444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 35113444Sek110237 } 35123444Sek110237 free(mntpnt); 35133444Sek110237 } 35143912Slling 35154276Staylor /* 35167042Sgw25295 * Read the EFI label from the config, if a label does not exist then 35177042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 35187042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 35197042Sgw25295 * partition. 35207042Sgw25295 */ 35217042Sgw25295 static int 35227042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 35237042Sgw25295 { 35247042Sgw25295 char *path; 35257042Sgw25295 int fd; 35267042Sgw25295 char diskname[MAXPATHLEN]; 35277042Sgw25295 int err = -1; 35287042Sgw25295 35297042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 35307042Sgw25295 return (err); 35317042Sgw25295 35327042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 35337042Sgw25295 strrchr(path, '/')); 35347042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 35357042Sgw25295 struct dk_gpt *vtoc; 35367042Sgw25295 35377042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 35387042Sgw25295 if (sb != NULL) 35397042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 35407042Sgw25295 efi_free(vtoc); 35417042Sgw25295 } 35427042Sgw25295 (void) close(fd); 35437042Sgw25295 } 35447042Sgw25295 return (err); 35457042Sgw25295 } 35467042Sgw25295 35477042Sgw25295 /* 35484276Staylor * determine where a partition starts on a disk in the current 35494276Staylor * configuration 35504276Staylor */ 35514276Staylor static diskaddr_t 35524276Staylor find_start_block(nvlist_t *config) 35534276Staylor { 35544276Staylor nvlist_t **child; 35554276Staylor uint_t c, children; 35564276Staylor diskaddr_t sb = MAXOFFSET_T; 35574276Staylor uint64_t wholedisk; 35584276Staylor 35594276Staylor if (nvlist_lookup_nvlist_array(config, 35604276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 35614276Staylor if (nvlist_lookup_uint64(config, 35624276Staylor ZPOOL_CONFIG_WHOLE_DISK, 35634276Staylor &wholedisk) != 0 || !wholedisk) { 35644276Staylor return (MAXOFFSET_T); 35654276Staylor } 35667042Sgw25295 if (read_efi_label(config, &sb) < 0) 35677042Sgw25295 sb = MAXOFFSET_T; 35684276Staylor return (sb); 35694276Staylor } 35704276Staylor 35714276Staylor for (c = 0; c < children; c++) { 35724276Staylor sb = find_start_block(child[c]); 35734276Staylor if (sb != MAXOFFSET_T) { 35744276Staylor return (sb); 35754276Staylor } 35764276Staylor } 35774276Staylor return (MAXOFFSET_T); 35784276Staylor } 35794276Staylor 35804276Staylor /* 35814276Staylor * Label an individual disk. The name provided is the short name, 35824276Staylor * stripped of any leading /dev path. 35834276Staylor */ 35844276Staylor int 35854276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 35864276Staylor { 35874276Staylor char path[MAXPATHLEN]; 35884276Staylor struct dk_gpt *vtoc; 35894276Staylor int fd; 35904276Staylor size_t resv = EFI_MIN_RESV_SIZE; 35914276Staylor uint64_t slice_size; 35924276Staylor diskaddr_t start_block; 35934276Staylor char errbuf[1024]; 35944276Staylor 35956289Smmusante /* prepare an error message just in case */ 35966289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 35976289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 35986289Smmusante 35994276Staylor if (zhp) { 36004276Staylor nvlist_t *nvroot; 36014276Staylor 36027965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 36037965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36047965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 36057965SGeorge.Wilson@Sun.COM "pools.")); 36067965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 36077965SGeorge.Wilson@Sun.COM } 36087965SGeorge.Wilson@Sun.COM 36094276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 36104276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 36114276Staylor 36124276Staylor if (zhp->zpool_start_block == 0) 36134276Staylor start_block = find_start_block(nvroot); 36144276Staylor else 36154276Staylor start_block = zhp->zpool_start_block; 36164276Staylor zhp->zpool_start_block = start_block; 36174276Staylor } else { 36184276Staylor /* new pool */ 36194276Staylor start_block = NEW_START_BLOCK; 36204276Staylor } 36214276Staylor 36224276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 36234276Staylor BACKUP_SLICE); 36244276Staylor 36254276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 36264276Staylor /* 36274276Staylor * This shouldn't happen. We've long since verified that this 36284276Staylor * is a valid device. 36294276Staylor */ 36306289Smmusante zfs_error_aux(hdl, 36316289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 36324276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 36334276Staylor } 36344276Staylor 36354276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 36364276Staylor /* 36374276Staylor * The only way this can fail is if we run out of memory, or we 36384276Staylor * were unable to read the disk's capacity 36394276Staylor */ 36404276Staylor if (errno == ENOMEM) 36414276Staylor (void) no_memory(hdl); 36424276Staylor 36434276Staylor (void) close(fd); 36446289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36456289Smmusante "unable to read disk capacity"), name); 36464276Staylor 36474276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 36484276Staylor } 36494276Staylor 36504276Staylor slice_size = vtoc->efi_last_u_lba + 1; 36514276Staylor slice_size -= EFI_MIN_RESV_SIZE; 36524276Staylor if (start_block == MAXOFFSET_T) 36534276Staylor start_block = NEW_START_BLOCK; 36544276Staylor slice_size -= start_block; 36554276Staylor 36564276Staylor vtoc->efi_parts[0].p_start = start_block; 36574276Staylor vtoc->efi_parts[0].p_size = slice_size; 36584276Staylor 36594276Staylor /* 36604276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 36614276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 36624276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 36634276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 36644276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 36654276Staylor * can get, in the absence of V_OTHER. 36664276Staylor */ 36674276Staylor vtoc->efi_parts[0].p_tag = V_USR; 36684276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 36694276Staylor 36704276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 36714276Staylor vtoc->efi_parts[8].p_size = resv; 36724276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 36734276Staylor 36744276Staylor if (efi_write(fd, vtoc) != 0) { 36754276Staylor /* 36764276Staylor * Some block drivers (like pcata) may not support EFI 36774276Staylor * GPT labels. Print out a helpful error message dir- 36784276Staylor * ecting the user to manually label the disk and give 36794276Staylor * a specific slice. 36804276Staylor */ 36814276Staylor (void) close(fd); 36824276Staylor efi_free(vtoc); 36834276Staylor 36844276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36856289Smmusante "try using fdisk(1M) and then provide a specific slice")); 36864276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 36874276Staylor } 36884276Staylor 36894276Staylor (void) close(fd); 36904276Staylor efi_free(vtoc); 36914276Staylor return (0); 36924276Staylor } 36936423Sgw25295 36946423Sgw25295 static boolean_t 36956423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 36966423Sgw25295 { 36976423Sgw25295 char *type; 36986423Sgw25295 nvlist_t **child; 36996423Sgw25295 uint_t children, c; 37006423Sgw25295 37016423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 37026423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 37036423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 37046423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 370510594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 37066423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 37076423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37086423Sgw25295 "vdev type '%s' is not supported"), type); 37096423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 37106423Sgw25295 return (B_FALSE); 37116423Sgw25295 } 37126423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 37136423Sgw25295 &child, &children) == 0) { 37146423Sgw25295 for (c = 0; c < children; c++) { 37156423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 37166423Sgw25295 return (B_FALSE); 37176423Sgw25295 } 37186423Sgw25295 } 37196423Sgw25295 return (B_TRUE); 37206423Sgw25295 } 37216423Sgw25295 37226423Sgw25295 /* 37236423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 37246423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 37256423Sgw25295 */ 37266423Sgw25295 int 37276423Sgw25295 zvol_check_dump_config(char *arg) 37286423Sgw25295 { 37296423Sgw25295 zpool_handle_t *zhp = NULL; 37306423Sgw25295 nvlist_t *config, *nvroot; 37316423Sgw25295 char *p, *volname; 37326423Sgw25295 nvlist_t **top; 37336423Sgw25295 uint_t toplevels; 37346423Sgw25295 libzfs_handle_t *hdl; 37356423Sgw25295 char errbuf[1024]; 37366423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 37376423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 37386423Sgw25295 int ret = 1; 37396423Sgw25295 37406423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 37416423Sgw25295 return (-1); 37426423Sgw25295 } 37436423Sgw25295 37446423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 37456423Sgw25295 "dump is not supported on device '%s'"), arg); 37466423Sgw25295 37476423Sgw25295 if ((hdl = libzfs_init()) == NULL) 37486423Sgw25295 return (1); 37496423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 37506423Sgw25295 37516423Sgw25295 volname = arg + pathlen; 37526423Sgw25295 37536423Sgw25295 /* check the configuration of the pool */ 37546423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 37556423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37566423Sgw25295 "malformed dataset name")); 37576423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 37586423Sgw25295 return (1); 37596423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 37606423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37616423Sgw25295 "dataset name is too long")); 37626423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 37636423Sgw25295 return (1); 37646423Sgw25295 } else { 37656423Sgw25295 (void) strncpy(poolname, volname, p - volname); 37666423Sgw25295 poolname[p - volname] = '\0'; 37676423Sgw25295 } 37686423Sgw25295 37696423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 37706423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37716423Sgw25295 "could not open pool '%s'"), poolname); 37726423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 37736423Sgw25295 goto out; 37746423Sgw25295 } 37756423Sgw25295 config = zpool_get_config(zhp, NULL); 37766423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 37776423Sgw25295 &nvroot) != 0) { 37786423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37796423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 37806423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 37816423Sgw25295 goto out; 37826423Sgw25295 } 37836423Sgw25295 37846423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 37856423Sgw25295 &top, &toplevels) == 0); 37866423Sgw25295 if (toplevels != 1) { 37876423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37886423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 37896423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 37906423Sgw25295 goto out; 37916423Sgw25295 } 37926423Sgw25295 37936423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 37946423Sgw25295 goto out; 37956423Sgw25295 } 37966423Sgw25295 ret = 0; 37976423Sgw25295 37986423Sgw25295 out: 37996423Sgw25295 if (zhp) 38006423Sgw25295 zpool_close(zhp); 38016423Sgw25295 libzfs_fini(hdl); 38026423Sgw25295 return (ret); 38036423Sgw25295 } 3804