1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 238525SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #include <ctype.h> 28789Sahrens #include <errno.h> 29789Sahrens #include <devid.h> 30789Sahrens #include <fcntl.h> 31789Sahrens #include <libintl.h> 32789Sahrens #include <stdio.h> 33789Sahrens #include <stdlib.h> 343126Sahl #include <strings.h> 35789Sahrens #include <unistd.h> 364276Staylor #include <sys/efi_partition.h> 374276Staylor #include <sys/vtoc.h> 38789Sahrens #include <sys/zfs_ioctl.h> 399816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 40789Sahrens 41789Sahrens #include "zfs_namecheck.h" 423912Slling #include "zfs_prop.h" 43789Sahrens #include "libzfs_impl.h" 44789Sahrens 457042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 465094Slling 477965SGeorge.Wilson@Sun.COM #if defined(__i386) || defined(__amd64) 487965SGeorge.Wilson@Sun.COM #define BOOTCMD "installgrub(1M)" 497965SGeorge.Wilson@Sun.COM #else 507965SGeorge.Wilson@Sun.COM #define BOOTCMD "installboot(1M)" 517965SGeorge.Wilson@Sun.COM #endif 527965SGeorge.Wilson@Sun.COM 539816SGeorge.Wilson@Sun.COM #define DISK_ROOT "/dev/dsk" 549816SGeorge.Wilson@Sun.COM #define RDISK_ROOT "/dev/rdsk" 559816SGeorge.Wilson@Sun.COM #define BACKUP_SLICE "s2" 569816SGeorge.Wilson@Sun.COM 575094Slling /* 585094Slling * ==================================================================== 595094Slling * zpool property functions 605094Slling * ==================================================================== 615094Slling */ 625094Slling 635094Slling static int 645094Slling zpool_get_all_props(zpool_handle_t *zhp) 655094Slling { 665094Slling zfs_cmd_t zc = { 0 }; 675094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 685094Slling 695094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 705094Slling 715094Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 725094Slling return (-1); 735094Slling 745094Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 755094Slling if (errno == ENOMEM) { 765094Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 775094Slling zcmd_free_nvlists(&zc); 785094Slling return (-1); 795094Slling } 805094Slling } else { 815094Slling zcmd_free_nvlists(&zc); 825094Slling return (-1); 835094Slling } 845094Slling } 855094Slling 865094Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 875094Slling zcmd_free_nvlists(&zc); 885094Slling return (-1); 895094Slling } 905094Slling 915094Slling zcmd_free_nvlists(&zc); 925094Slling 935094Slling return (0); 945094Slling } 955094Slling 965094Slling static int 975094Slling zpool_props_refresh(zpool_handle_t *zhp) 985094Slling { 995094Slling nvlist_t *old_props; 1005094Slling 1015094Slling old_props = zhp->zpool_props; 1025094Slling 1035094Slling if (zpool_get_all_props(zhp) != 0) 1045094Slling return (-1); 1055094Slling 1065094Slling nvlist_free(old_props); 1075094Slling return (0); 1085094Slling } 1095094Slling 1105094Slling static char * 1115094Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 1125094Slling zprop_source_t *src) 1135094Slling { 1145094Slling nvlist_t *nv, *nvl; 1155094Slling uint64_t ival; 1165094Slling char *value; 1175094Slling zprop_source_t source; 1185094Slling 1195094Slling nvl = zhp->zpool_props; 1205094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1215094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 1225094Slling source = ival; 1235094Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 1245094Slling } else { 1255094Slling source = ZPROP_SRC_DEFAULT; 1265094Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 1275094Slling value = "-"; 1285094Slling } 1295094Slling 1305094Slling if (src) 1315094Slling *src = source; 1325094Slling 1335094Slling return (value); 1345094Slling } 1355094Slling 1365094Slling uint64_t 1375094Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 1385094Slling { 1395094Slling nvlist_t *nv, *nvl; 1405094Slling uint64_t value; 1415094Slling zprop_source_t source; 1425094Slling 1437294Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 1447294Sperrin /* 1457294Sperrin * zpool_get_all_props() has most likely failed because 1467294Sperrin * the pool is faulted, but if all we need is the top level 1477294Sperrin * vdev's guid then get it from the zhp config nvlist. 1487294Sperrin */ 1497294Sperrin if ((prop == ZPOOL_PROP_GUID) && 1507294Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 1517294Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 1527294Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 1537294Sperrin == 0)) { 1547294Sperrin return (value); 1557294Sperrin } 1565094Slling return (zpool_prop_default_numeric(prop)); 1577294Sperrin } 1585094Slling 1595094Slling nvl = zhp->zpool_props; 1605094Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 1615094Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 1625094Slling source = value; 1635094Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 1645094Slling } else { 1655094Slling source = ZPROP_SRC_DEFAULT; 1665094Slling value = zpool_prop_default_numeric(prop); 1675094Slling } 1685094Slling 1695094Slling if (src) 1705094Slling *src = source; 1715094Slling 1725094Slling return (value); 1735094Slling } 1745094Slling 1755094Slling /* 1765094Slling * Map VDEV STATE to printed strings. 1775094Slling */ 1785094Slling char * 1795094Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 1805094Slling { 1815094Slling switch (state) { 1825094Slling case VDEV_STATE_CLOSED: 1835094Slling case VDEV_STATE_OFFLINE: 1845094Slling return (gettext("OFFLINE")); 1855094Slling case VDEV_STATE_REMOVED: 1865094Slling return (gettext("REMOVED")); 1875094Slling case VDEV_STATE_CANT_OPEN: 1887294Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 1895094Slling return (gettext("FAULTED")); 1905094Slling else 1915094Slling return (gettext("UNAVAIL")); 1925094Slling case VDEV_STATE_FAULTED: 1935094Slling return (gettext("FAULTED")); 1945094Slling case VDEV_STATE_DEGRADED: 1955094Slling return (gettext("DEGRADED")); 1965094Slling case VDEV_STATE_HEALTHY: 1975094Slling return (gettext("ONLINE")); 1985094Slling } 1995094Slling 2005094Slling return (gettext("UNKNOWN")); 2015094Slling } 2025094Slling 2035094Slling /* 2045094Slling * Get a zpool property value for 'prop' and return the value in 2055094Slling * a pre-allocated buffer. 2065094Slling */ 2075094Slling int 2085094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2095094Slling zprop_source_t *srctype) 2105094Slling { 2115094Slling uint64_t intval; 2125094Slling const char *strval; 2135094Slling zprop_source_t src = ZPROP_SRC_NONE; 2145094Slling nvlist_t *nvroot; 2155094Slling vdev_stat_t *vs; 2165094Slling uint_t vsc; 2175094Slling 2185094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2198525SEric.Schrock@Sun.COM switch (prop) { 2208525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2215094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2228525SEric.Schrock@Sun.COM break; 2238525SEric.Schrock@Sun.COM 2248525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2255094Slling (void) strlcpy(buf, "FAULTED", len); 2268525SEric.Schrock@Sun.COM break; 2278525SEric.Schrock@Sun.COM 2288525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2298525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2308525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2318525SEric.Schrock@Sun.COM break; 2328525SEric.Schrock@Sun.COM 2338525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2348525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2358525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2368525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2378525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2388525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2398525SEric.Schrock@Sun.COM len); 2408525SEric.Schrock@Sun.COM if (srctype != NULL) 2418525SEric.Schrock@Sun.COM *srctype = src; 2428525SEric.Schrock@Sun.COM return (0); 2438525SEric.Schrock@Sun.COM } 2448525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2458525SEric.Schrock@Sun.COM default: 2465094Slling (void) strlcpy(buf, "-", len); 2478525SEric.Schrock@Sun.COM break; 2488525SEric.Schrock@Sun.COM } 2498525SEric.Schrock@Sun.COM 2508525SEric.Schrock@Sun.COM if (srctype != NULL) 2518525SEric.Schrock@Sun.COM *srctype = src; 2525094Slling return (0); 2535094Slling } 2545094Slling 2555094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2565094Slling prop != ZPOOL_PROP_NAME) 2575094Slling return (-1); 2585094Slling 2595094Slling switch (zpool_prop_get_type(prop)) { 2605094Slling case PROP_TYPE_STRING: 2615094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 2625094Slling len); 2635094Slling break; 2645094Slling 2655094Slling case PROP_TYPE_NUMBER: 2665094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2675094Slling 2685094Slling switch (prop) { 2695094Slling case ZPOOL_PROP_SIZE: 2705094Slling case ZPOOL_PROP_USED: 2715094Slling case ZPOOL_PROP_AVAILABLE: 2725094Slling (void) zfs_nicenum(intval, buf, len); 2735094Slling break; 2745094Slling 2755094Slling case ZPOOL_PROP_CAPACITY: 2765094Slling (void) snprintf(buf, len, "%llu%%", 2775094Slling (u_longlong_t)intval); 2785094Slling break; 2795094Slling 2805094Slling case ZPOOL_PROP_HEALTH: 2815094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 2825094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2835094Slling verify(nvlist_lookup_uint64_array(nvroot, 2845094Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 2855094Slling 2865094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 2875094Slling vs->vs_aux), len); 2885094Slling break; 2895094Slling default: 2905094Slling (void) snprintf(buf, len, "%llu", intval); 2915094Slling } 2925094Slling break; 2935094Slling 2945094Slling case PROP_TYPE_INDEX: 2955094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2965094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 2975094Slling != 0) 2985094Slling return (-1); 2995094Slling (void) strlcpy(buf, strval, len); 3005094Slling break; 3015094Slling 3025094Slling default: 3035094Slling abort(); 3045094Slling } 3055094Slling 3065094Slling if (srctype) 3075094Slling *srctype = src; 3085094Slling 3095094Slling return (0); 3105094Slling } 3115094Slling 3125094Slling /* 3135094Slling * Check if the bootfs name has the same pool name as it is set to. 3145094Slling * Assuming bootfs is a valid dataset name. 3155094Slling */ 3165094Slling static boolean_t 3175094Slling bootfs_name_valid(const char *pool, char *bootfs) 3185094Slling { 3195094Slling int len = strlen(pool); 3205094Slling 3217300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3225094Slling return (B_FALSE); 3235094Slling 3245094Slling if (strncmp(pool, bootfs, len) == 0 && 3255094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3265094Slling return (B_TRUE); 3275094Slling 3285094Slling return (B_FALSE); 3295094Slling } 3305094Slling 3315094Slling /* 3327042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3337042Sgw25295 * an EFI label. 3347042Sgw25295 */ 3357042Sgw25295 static boolean_t 3367042Sgw25295 pool_uses_efi(nvlist_t *config) 3377042Sgw25295 { 3387042Sgw25295 nvlist_t **child; 3397042Sgw25295 uint_t c, children; 3407042Sgw25295 3417042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3427042Sgw25295 &child, &children) != 0) 3437042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3447042Sgw25295 3457042Sgw25295 for (c = 0; c < children; c++) { 3467042Sgw25295 if (pool_uses_efi(child[c])) 3477042Sgw25295 return (B_TRUE); 3487042Sgw25295 } 3497042Sgw25295 return (B_FALSE); 3507042Sgw25295 } 3517042Sgw25295 3527965SGeorge.Wilson@Sun.COM static boolean_t 3537965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3547965SGeorge.Wilson@Sun.COM { 3557965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3567965SGeorge.Wilson@Sun.COM 3577965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 3587965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 3597965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 3607965SGeorge.Wilson@Sun.COM } 3617965SGeorge.Wilson@Sun.COM 3627965SGeorge.Wilson@Sun.COM 3637042Sgw25295 /* 3645094Slling * Given an nvlist of zpool properties to be set, validate that they are 3655094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 3665094Slling * specified as strings. 3675094Slling */ 3685094Slling static nvlist_t * 3697184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 3705094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 3715094Slling { 3725094Slling nvpair_t *elem; 3735094Slling nvlist_t *retprops; 3745094Slling zpool_prop_t prop; 3755094Slling char *strval; 3765094Slling uint64_t intval; 3775363Seschrock char *slash; 3785363Seschrock struct stat64 statbuf; 3797042Sgw25295 zpool_handle_t *zhp; 3807042Sgw25295 nvlist_t *nvroot; 3815094Slling 3825094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 3835094Slling (void) no_memory(hdl); 3845094Slling return (NULL); 3855094Slling } 3865094Slling 3875094Slling elem = NULL; 3885094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 3895094Slling const char *propname = nvpair_name(elem); 3905094Slling 3915094Slling /* 3925094Slling * Make sure this property is valid and applies to this type. 3935094Slling */ 3945094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 3955094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3965094Slling "invalid property '%s'"), propname); 3975094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 3985094Slling goto error; 3995094Slling } 4005094Slling 4015094Slling if (zpool_prop_readonly(prop)) { 4025094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4035094Slling "is readonly"), propname); 4045094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4055094Slling goto error; 4065094Slling } 4075094Slling 4085094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4095094Slling &strval, &intval, errbuf) != 0) 4105094Slling goto error; 4115094Slling 4125094Slling /* 4135094Slling * Perform additional checking for specific properties. 4145094Slling */ 4155094Slling switch (prop) { 4165094Slling case ZPOOL_PROP_VERSION: 4175094Slling if (intval < version || intval > SPA_VERSION) { 4185094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4195094Slling "property '%s' number %d is invalid."), 4205094Slling propname, intval); 4215094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4225094Slling goto error; 4235094Slling } 4245094Slling break; 4255094Slling 4265094Slling case ZPOOL_PROP_BOOTFS: 4275094Slling if (create_or_import) { 4285094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4295094Slling "property '%s' cannot be set at creation " 4305094Slling "or import time"), propname); 4315094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4325094Slling goto error; 4335094Slling } 4345094Slling 4355094Slling if (version < SPA_VERSION_BOOTFS) { 4365094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4375094Slling "pool must be upgraded to support " 4385094Slling "'%s' property"), propname); 4395094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4405094Slling goto error; 4415094Slling } 4425094Slling 4435094Slling /* 4445094Slling * bootfs property value has to be a dataset name and 4455094Slling * the dataset has to be in the same pool as it sets to. 4465094Slling */ 4475094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4485094Slling strval)) { 4495094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4505094Slling "is an invalid name"), strval); 4515094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4525094Slling goto error; 4535094Slling } 4547042Sgw25295 4557042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4567042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4577042Sgw25295 "could not open pool '%s'"), poolname); 4587042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4597042Sgw25295 goto error; 4607042Sgw25295 } 4617042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 4627042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 4637042Sgw25295 4647042Sgw25295 /* 4657042Sgw25295 * bootfs property cannot be set on a disk which has 4667042Sgw25295 * been EFI labeled. 4677042Sgw25295 */ 4687042Sgw25295 if (pool_uses_efi(nvroot)) { 4697042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4707042Sgw25295 "property '%s' not supported on " 4717042Sgw25295 "EFI labeled devices"), propname); 4727042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 4737042Sgw25295 zpool_close(zhp); 4747042Sgw25295 goto error; 4757042Sgw25295 } 4767042Sgw25295 zpool_close(zhp); 4775094Slling break; 4785094Slling 4795094Slling case ZPOOL_PROP_ALTROOT: 4805094Slling if (!create_or_import) { 4815094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4825094Slling "property '%s' can only be set during pool " 4835094Slling "creation or import"), propname); 4845094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4855094Slling goto error; 4865094Slling } 4875094Slling 4885094Slling if (strval[0] != '/') { 4895094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4905094Slling "bad alternate root '%s'"), strval); 4915094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 4925094Slling goto error; 4935094Slling } 4945094Slling break; 4955363Seschrock 4965363Seschrock case ZPOOL_PROP_CACHEFILE: 4975363Seschrock if (strval[0] == '\0') 4985363Seschrock break; 4995363Seschrock 5005363Seschrock if (strcmp(strval, "none") == 0) 5015363Seschrock break; 5025363Seschrock 5035363Seschrock if (strval[0] != '/') { 5045363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5055363Seschrock "property '%s' must be empty, an " 5065363Seschrock "absolute path, or 'none'"), propname); 5075363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5085363Seschrock goto error; 5095363Seschrock } 5105363Seschrock 5115363Seschrock slash = strrchr(strval, '/'); 5125363Seschrock 5135363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5145363Seschrock strcmp(slash, "/..") == 0) { 5155363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5165363Seschrock "'%s' is not a valid file"), strval); 5175363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5185363Seschrock goto error; 5195363Seschrock } 5205363Seschrock 5215363Seschrock *slash = '\0'; 5225363Seschrock 5235621Seschrock if (strval[0] != '\0' && 5245621Seschrock (stat64(strval, &statbuf) != 0 || 5255621Seschrock !S_ISDIR(statbuf.st_mode))) { 5265363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5275363Seschrock "'%s' is not a valid directory"), 5285363Seschrock strval); 5295363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5305363Seschrock goto error; 5315363Seschrock } 5325363Seschrock 5335363Seschrock *slash = '/'; 5345363Seschrock break; 5355094Slling } 5365094Slling } 5375094Slling 5385094Slling return (retprops); 5395094Slling error: 5405094Slling nvlist_free(retprops); 5415094Slling return (NULL); 5425094Slling } 5435094Slling 5445094Slling /* 5455094Slling * Set zpool property : propname=propval. 5465094Slling */ 5475094Slling int 5485094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5495094Slling { 5505094Slling zfs_cmd_t zc = { 0 }; 5515094Slling int ret = -1; 5525094Slling char errbuf[1024]; 5535094Slling nvlist_t *nvl = NULL; 5545094Slling nvlist_t *realprops; 5555094Slling uint64_t version; 5565094Slling 5575094Slling (void) snprintf(errbuf, sizeof (errbuf), 5585094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 5595094Slling zhp->zpool_name); 5605094Slling 5615094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5625094Slling return (no_memory(zhp->zpool_hdl)); 5635094Slling 5645094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 5655094Slling nvlist_free(nvl); 5665094Slling return (no_memory(zhp->zpool_hdl)); 5675094Slling } 5685094Slling 5695094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5707184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 5715094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 5725094Slling nvlist_free(nvl); 5735094Slling return (-1); 5745094Slling } 5755094Slling 5765094Slling nvlist_free(nvl); 5775094Slling nvl = realprops; 5785094Slling 5795094Slling /* 5805094Slling * Execute the corresponding ioctl() to set this property. 5815094Slling */ 5825094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 5835094Slling 5845094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 5855094Slling nvlist_free(nvl); 5865094Slling return (-1); 5875094Slling } 5885094Slling 5895094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 5905094Slling 5915094Slling zcmd_free_nvlists(&zc); 5925094Slling nvlist_free(nvl); 5935094Slling 5945094Slling if (ret) 5955094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 5965094Slling else 5975094Slling (void) zpool_props_refresh(zhp); 5985094Slling 5995094Slling return (ret); 6005094Slling } 6015094Slling 6025094Slling int 6035094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6045094Slling { 6055094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6065094Slling zprop_list_t *entry; 6075094Slling char buf[ZFS_MAXPROPLEN]; 6085094Slling 6095094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6105094Slling return (-1); 6115094Slling 6125094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6135094Slling 6145094Slling if (entry->pl_fixed) 6155094Slling continue; 6165094Slling 6175094Slling if (entry->pl_prop != ZPROP_INVAL && 6185094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6195094Slling NULL) == 0) { 6205094Slling if (strlen(buf) > entry->pl_width) 6215094Slling entry->pl_width = strlen(buf); 6225094Slling } 6235094Slling } 6245094Slling 6255094Slling return (0); 6265094Slling } 6275094Slling 6285094Slling 629789Sahrens /* 6309816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6319816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6329816SGeorge.Wilson@Sun.COM */ 6339816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6349816SGeorge.Wilson@Sun.COM 6359816SGeorge.Wilson@Sun.COM /* 636789Sahrens * Validate the given pool name, optionally putting an extended error message in 637789Sahrens * 'buf'. 638789Sahrens */ 6396423Sgw25295 boolean_t 6402082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 641789Sahrens { 642789Sahrens namecheck_err_t why; 643789Sahrens char what; 6441773Seschrock int ret; 645789Sahrens 6461773Seschrock ret = pool_namecheck(pool, &why, &what); 6471773Seschrock 6481773Seschrock /* 6491773Seschrock * The rules for reserved pool names were extended at a later point. 6501773Seschrock * But we need to support users with existing pools that may now be 6511773Seschrock * invalid. So we only check for this expanded set of names during a 6521773Seschrock * create (or import), and only in userland. 6531773Seschrock */ 6541773Seschrock if (ret == 0 && !isopen && 6551773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6561773Seschrock strncmp(pool, "raidz", 5) == 0 || 6574527Sperrin strncmp(pool, "spare", 5) == 0 || 6584527Sperrin strcmp(pool, "log") == 0)) { 6596423Sgw25295 if (hdl != NULL) 6606423Sgw25295 zfs_error_aux(hdl, 6616423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 6622082Seschrock return (B_FALSE); 6631773Seschrock } 6641773Seschrock 6651773Seschrock 6661773Seschrock if (ret != 0) { 6672082Seschrock if (hdl != NULL) { 668789Sahrens switch (why) { 6691003Slling case NAME_ERR_TOOLONG: 6702082Seschrock zfs_error_aux(hdl, 6711003Slling dgettext(TEXT_DOMAIN, "name is too long")); 6721003Slling break; 6731003Slling 674789Sahrens case NAME_ERR_INVALCHAR: 6752082Seschrock zfs_error_aux(hdl, 676789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 677789Sahrens "'%c' in pool name"), what); 678789Sahrens break; 679789Sahrens 680789Sahrens case NAME_ERR_NOLETTER: 6812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6822082Seschrock "name must begin with a letter")); 683789Sahrens break; 684789Sahrens 685789Sahrens case NAME_ERR_RESERVED: 6862082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6872082Seschrock "name is reserved")); 688789Sahrens break; 689789Sahrens 690789Sahrens case NAME_ERR_DISKLIKE: 6912082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6922082Seschrock "pool name is reserved")); 693789Sahrens break; 6942856Snd150628 6952856Snd150628 case NAME_ERR_LEADING_SLASH: 6962856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6972856Snd150628 "leading slash in name")); 6982856Snd150628 break; 6992856Snd150628 7002856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7012856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7022856Snd150628 "empty component in name")); 7032856Snd150628 break; 7042856Snd150628 7052856Snd150628 case NAME_ERR_TRAILING_SLASH: 7062856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7072856Snd150628 "trailing slash in name")); 7082856Snd150628 break; 7092856Snd150628 7102856Snd150628 case NAME_ERR_MULTIPLE_AT: 7112856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7122856Snd150628 "multiple '@' delimiters in name")); 7132856Snd150628 break; 7142856Snd150628 715789Sahrens } 716789Sahrens } 7172082Seschrock return (B_FALSE); 718789Sahrens } 719789Sahrens 7202082Seschrock return (B_TRUE); 721789Sahrens } 722789Sahrens 723789Sahrens /* 724789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 725789Sahrens * state. 726789Sahrens */ 727789Sahrens zpool_handle_t * 7282082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 729789Sahrens { 730789Sahrens zpool_handle_t *zhp; 7312142Seschrock boolean_t missing; 732789Sahrens 733789Sahrens /* 734789Sahrens * Make sure the pool name is valid. 735789Sahrens */ 7362082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7373237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7382082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7392082Seschrock pool); 740789Sahrens return (NULL); 741789Sahrens } 742789Sahrens 7432082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7442082Seschrock return (NULL); 745789Sahrens 7462082Seschrock zhp->zpool_hdl = hdl; 747789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 748789Sahrens 7492142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7502142Seschrock zpool_close(zhp); 7512142Seschrock return (NULL); 7522142Seschrock } 7532142Seschrock 7542142Seschrock if (missing) { 7555094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7563237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 7575094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 7582142Seschrock zpool_close(zhp); 7592142Seschrock return (NULL); 760789Sahrens } 761789Sahrens 762789Sahrens return (zhp); 763789Sahrens } 764789Sahrens 765789Sahrens /* 766789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 767789Sahrens * the configuration cache may be out of date). 768789Sahrens */ 7692142Seschrock int 7702142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 771789Sahrens { 772789Sahrens zpool_handle_t *zhp; 7732142Seschrock boolean_t missing; 774789Sahrens 7752142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7762142Seschrock return (-1); 777789Sahrens 7782082Seschrock zhp->zpool_hdl = hdl; 779789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 780789Sahrens 7812142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7822142Seschrock zpool_close(zhp); 7832142Seschrock return (-1); 784789Sahrens } 785789Sahrens 7862142Seschrock if (missing) { 7872142Seschrock zpool_close(zhp); 7882142Seschrock *ret = NULL; 7892142Seschrock return (0); 7902142Seschrock } 7912142Seschrock 7922142Seschrock *ret = zhp; 7932142Seschrock return (0); 794789Sahrens } 795789Sahrens 796789Sahrens /* 797789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 798789Sahrens * state. 799789Sahrens */ 800789Sahrens zpool_handle_t * 8012082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 802789Sahrens { 803789Sahrens zpool_handle_t *zhp; 804789Sahrens 8052082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 806789Sahrens return (NULL); 807789Sahrens 808789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8093237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8102082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 811789Sahrens zpool_close(zhp); 812789Sahrens return (NULL); 813789Sahrens } 814789Sahrens 815789Sahrens return (zhp); 816789Sahrens } 817789Sahrens 818789Sahrens /* 819789Sahrens * Close the handle. Simply frees the memory associated with the handle. 820789Sahrens */ 821789Sahrens void 822789Sahrens zpool_close(zpool_handle_t *zhp) 823789Sahrens { 824789Sahrens if (zhp->zpool_config) 825789Sahrens nvlist_free(zhp->zpool_config); 826952Seschrock if (zhp->zpool_old_config) 827952Seschrock nvlist_free(zhp->zpool_old_config); 8283912Slling if (zhp->zpool_props) 8293912Slling nvlist_free(zhp->zpool_props); 830789Sahrens free(zhp); 831789Sahrens } 832789Sahrens 833789Sahrens /* 834789Sahrens * Return the name of the pool. 835789Sahrens */ 836789Sahrens const char * 837789Sahrens zpool_get_name(zpool_handle_t *zhp) 838789Sahrens { 839789Sahrens return (zhp->zpool_name); 840789Sahrens } 841789Sahrens 842789Sahrens 843789Sahrens /* 844789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 845789Sahrens */ 846789Sahrens int 847789Sahrens zpool_get_state(zpool_handle_t *zhp) 848789Sahrens { 849789Sahrens return (zhp->zpool_state); 850789Sahrens } 851789Sahrens 852789Sahrens /* 853789Sahrens * Create the named pool, using the provided vdev list. It is assumed 854789Sahrens * that the consumer has already validated the contents of the nvlist, so we 855789Sahrens * don't have to worry about error semantics. 856789Sahrens */ 857789Sahrens int 8582082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8597184Stimh nvlist_t *props, nvlist_t *fsprops) 860789Sahrens { 861789Sahrens zfs_cmd_t zc = { 0 }; 8627184Stimh nvlist_t *zc_fsprops = NULL; 8637184Stimh nvlist_t *zc_props = NULL; 8642082Seschrock char msg[1024]; 8655094Slling char *altroot; 8667184Stimh int ret = -1; 8672082Seschrock 8682082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 8692082Seschrock "cannot create '%s'"), pool); 870789Sahrens 8712082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 8722082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 8732082Seschrock 8745320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 8755320Slling return (-1); 8765320Slling 8777184Stimh if (props) { 8787184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8797184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8807184Stimh goto create_failed; 8817184Stimh } 8825320Slling } 883789Sahrens 8847184Stimh if (fsprops) { 8857184Stimh uint64_t zoned; 8867184Stimh char *zonestr; 8877184Stimh 8887184Stimh zoned = ((nvlist_lookup_string(fsprops, 8897184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8907184Stimh strcmp(zonestr, "on") == 0); 8917184Stimh 8927184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 8937184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 8947184Stimh goto create_failed; 8957184Stimh } 8967184Stimh if (!zc_props && 8977184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 8987184Stimh goto create_failed; 8997184Stimh } 9007184Stimh if (nvlist_add_nvlist(zc_props, 9017184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9027184Stimh goto create_failed; 9037184Stimh } 9047184Stimh } 9057184Stimh 9067184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9077184Stimh goto create_failed; 9087184Stimh 909789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 910789Sahrens 9117184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9125320Slling 9132676Seschrock zcmd_free_nvlists(&zc); 9147184Stimh nvlist_free(zc_props); 9157184Stimh nvlist_free(zc_fsprops); 9162082Seschrock 917789Sahrens switch (errno) { 918789Sahrens case EBUSY: 919789Sahrens /* 920789Sahrens * This can happen if the user has specified the same 921789Sahrens * device multiple times. We can't reliably detect this 922789Sahrens * until we try to add it and see we already have a 923789Sahrens * label. 924789Sahrens */ 9252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9262082Seschrock "one or more vdevs refer to the same device")); 9272082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 928789Sahrens 929789Sahrens case EOVERFLOW: 930789Sahrens /* 9312082Seschrock * This occurs when one of the devices is below 932789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 933789Sahrens * device was the problem device since there's no 934789Sahrens * reliable way to determine device size from userland. 935789Sahrens */ 936789Sahrens { 937789Sahrens char buf[64]; 938789Sahrens 939789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 940789Sahrens 9412082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9422082Seschrock "one or more devices is less than the " 9432082Seschrock "minimum size (%s)"), buf); 944789Sahrens } 9452082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 946789Sahrens 947789Sahrens case ENOSPC: 9482082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9492082Seschrock "one or more devices is out of space")); 9502082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 951789Sahrens 9525450Sbrendan case ENOTBLK: 9535450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9545450Sbrendan "cache device must be a disk or disk slice")); 9555450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9565450Sbrendan 957789Sahrens default: 9582082Seschrock return (zpool_standard_error(hdl, errno, msg)); 959789Sahrens } 960789Sahrens } 961789Sahrens 962789Sahrens /* 963789Sahrens * If this is an alternate root pool, then we automatically set the 9642676Seschrock * mountpoint of the root dataset to be '/'. 965789Sahrens */ 9665094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 9675094Slling &altroot) == 0) { 968789Sahrens zfs_handle_t *zhp; 969789Sahrens 9705094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 9712676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 9722676Seschrock "/") == 0); 973789Sahrens 974789Sahrens zfs_close(zhp); 975789Sahrens } 976789Sahrens 9777184Stimh create_failed: 9785320Slling zcmd_free_nvlists(&zc); 9797184Stimh nvlist_free(zc_props); 9807184Stimh nvlist_free(zc_fsprops); 9817184Stimh return (ret); 982789Sahrens } 983789Sahrens 984789Sahrens /* 985789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 986789Sahrens * datasets left in the pool. 987789Sahrens */ 988789Sahrens int 989789Sahrens zpool_destroy(zpool_handle_t *zhp) 990789Sahrens { 991789Sahrens zfs_cmd_t zc = { 0 }; 992789Sahrens zfs_handle_t *zfp = NULL; 9932082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 9942082Seschrock char msg[1024]; 995789Sahrens 996789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 9972082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 9982082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 999789Sahrens return (-1); 1000789Sahrens 1001789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1002789Sahrens 10034543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10042082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10052082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1006789Sahrens 10072082Seschrock if (errno == EROFS) { 10082082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10092082Seschrock "one or more devices is read only")); 10102082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10112082Seschrock } else { 10122082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1013789Sahrens } 1014789Sahrens 1015789Sahrens if (zfp) 1016789Sahrens zfs_close(zfp); 1017789Sahrens return (-1); 1018789Sahrens } 1019789Sahrens 1020789Sahrens if (zfp) { 1021789Sahrens remove_mountpoint(zfp); 1022789Sahrens zfs_close(zfp); 1023789Sahrens } 1024789Sahrens 1025789Sahrens return (0); 1026789Sahrens } 1027789Sahrens 1028789Sahrens /* 1029789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1030789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1031789Sahrens */ 1032789Sahrens int 1033789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1034789Sahrens { 10352676Seschrock zfs_cmd_t zc = { 0 }; 10362082Seschrock int ret; 10372082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10382082Seschrock char msg[1024]; 10395450Sbrendan nvlist_t **spares, **l2cache; 10405450Sbrendan uint_t nspares, nl2cache; 10412082Seschrock 10422082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10432082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10442082Seschrock 10455450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10465450Sbrendan SPA_VERSION_SPARES && 10472082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10482082Seschrock &spares, &nspares) == 0) { 10492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10502082Seschrock "upgraded to add hot spares")); 10512082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10522082Seschrock } 1053789Sahrens 10547965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10557965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10567965SGeorge.Wilson@Sun.COM uint64_t s; 10577965SGeorge.Wilson@Sun.COM 10587965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 10597965SGeorge.Wilson@Sun.COM char *path; 10607965SGeorge.Wilson@Sun.COM 10617965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 10627965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 10637965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10647965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 10657965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 10667965SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s])); 10677965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 10687965SGeorge.Wilson@Sun.COM } 10697965SGeorge.Wilson@Sun.COM } 10707965SGeorge.Wilson@Sun.COM } 10717965SGeorge.Wilson@Sun.COM 10725450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10735450Sbrendan SPA_VERSION_L2CACHE && 10745450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 10755450Sbrendan &l2cache, &nl2cache) == 0) { 10765450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10775450Sbrendan "upgraded to add cache devices")); 10785450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10795450Sbrendan } 10805450Sbrendan 10815094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 10822082Seschrock return (-1); 1083789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1084789Sahrens 10854543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1086789Sahrens switch (errno) { 1087789Sahrens case EBUSY: 1088789Sahrens /* 1089789Sahrens * This can happen if the user has specified the same 1090789Sahrens * device multiple times. We can't reliably detect this 1091789Sahrens * until we try to add it and see we already have a 1092789Sahrens * label. 1093789Sahrens */ 10942082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10952082Seschrock "one or more vdevs refer to the same device")); 10962082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1097789Sahrens break; 1098789Sahrens 1099789Sahrens case EOVERFLOW: 1100789Sahrens /* 1101789Sahrens * This occurrs when one of the devices is below 1102789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1103789Sahrens * device was the problem device since there's no 1104789Sahrens * reliable way to determine device size from userland. 1105789Sahrens */ 1106789Sahrens { 1107789Sahrens char buf[64]; 1108789Sahrens 1109789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1110789Sahrens 11112082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11122082Seschrock "device is less than the minimum " 11132082Seschrock "size (%s)"), buf); 1114789Sahrens } 11152082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11162082Seschrock break; 11172082Seschrock 11182082Seschrock case ENOTSUP: 11192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11204527Sperrin "pool must be upgraded to add these vdevs")); 11212082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1122789Sahrens break; 1123789Sahrens 11243912Slling case EDOM: 11253912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11264527Sperrin "root pool can not have multiple vdevs" 11274527Sperrin " or separate logs")); 11283912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11293912Slling break; 11303912Slling 11315450Sbrendan case ENOTBLK: 11325450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11335450Sbrendan "cache device must be a disk or disk slice")); 11345450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11355450Sbrendan break; 11365450Sbrendan 1137789Sahrens default: 11382082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1139789Sahrens } 1140789Sahrens 11412082Seschrock ret = -1; 11422082Seschrock } else { 11432082Seschrock ret = 0; 1144789Sahrens } 1145789Sahrens 11462676Seschrock zcmd_free_nvlists(&zc); 1147789Sahrens 11482082Seschrock return (ret); 1149789Sahrens } 1150789Sahrens 1151789Sahrens /* 1152789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1153789Sahrens * mounted datasets in the pool. 1154789Sahrens */ 1155789Sahrens int 11568211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1157789Sahrens { 1158789Sahrens zfs_cmd_t zc = { 0 }; 11597214Slling char msg[1024]; 1160789Sahrens 11617214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 11627214Slling "cannot export '%s'"), zhp->zpool_name); 11637214Slling 1164789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 11657214Slling zc.zc_cookie = force; 11668211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 11677214Slling 11687214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 11697214Slling switch (errno) { 11707214Slling case EXDEV: 11717214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 11727214Slling "use '-f' to override the following errors:\n" 11737214Slling "'%s' has an active shared spare which could be" 11747214Slling " used by other pools once '%s' is exported."), 11757214Slling zhp->zpool_name, zhp->zpool_name); 11767214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 11777214Slling msg)); 11787214Slling default: 11797214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 11807214Slling msg)); 11817214Slling } 11827214Slling } 11837214Slling 1184789Sahrens return (0); 1185789Sahrens } 1186789Sahrens 11878211SGeorge.Wilson@Sun.COM int 11888211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 11898211SGeorge.Wilson@Sun.COM { 11908211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 11918211SGeorge.Wilson@Sun.COM } 11928211SGeorge.Wilson@Sun.COM 11938211SGeorge.Wilson@Sun.COM int 11948211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 11958211SGeorge.Wilson@Sun.COM { 11968211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 11978211SGeorge.Wilson@Sun.COM } 11988211SGeorge.Wilson@Sun.COM 1199789Sahrens /* 12005094Slling * zpool_import() is a contracted interface. Should be kept the same 12015094Slling * if possible. 12025094Slling * 12035094Slling * Applications should use zpool_import_props() to import a pool with 12045094Slling * new properties value to be set. 1205789Sahrens */ 1206789Sahrens int 12072082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12085094Slling char *altroot) 12095094Slling { 12105094Slling nvlist_t *props = NULL; 12115094Slling int ret; 12125094Slling 12135094Slling if (altroot != NULL) { 12145094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 12155094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12165094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12175094Slling newname)); 12185094Slling } 12195094Slling 12205094Slling if (nvlist_add_string(props, 12218084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 12228084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 12238084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 12245094Slling nvlist_free(props); 12255094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 12265094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12275094Slling newname)); 12285094Slling } 12295094Slling } 12305094Slling 12316643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 12325094Slling if (props) 12335094Slling nvlist_free(props); 12345094Slling return (ret); 12355094Slling } 12365094Slling 12375094Slling /* 12385094Slling * Import the given pool using the known configuration and a list of 12395094Slling * properties to be set. The configuration should have come from 12405094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 12415094Slling * is imported with a different name. 12425094Slling */ 12435094Slling int 12445094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 12456643Seschrock nvlist_t *props, boolean_t importfaulted) 1246789Sahrens { 12472676Seschrock zfs_cmd_t zc = { 0 }; 1248789Sahrens char *thename; 1249789Sahrens char *origname; 1250789Sahrens int ret; 12515094Slling char errbuf[1024]; 1252789Sahrens 1253789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1254789Sahrens &origname) == 0); 1255789Sahrens 12565094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 12575094Slling "cannot import pool '%s'"), origname); 12585094Slling 1259789Sahrens if (newname != NULL) { 12602082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 12613237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 12622082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 12632082Seschrock newname)); 1264789Sahrens thename = (char *)newname; 1265789Sahrens } else { 1266789Sahrens thename = origname; 1267789Sahrens } 1268789Sahrens 12695094Slling if (props) { 12705094Slling uint64_t version; 12715094Slling 12725094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 12735094Slling &version) == 0); 12745094Slling 12757184Stimh if ((props = zpool_valid_proplist(hdl, origname, 12765320Slling props, version, B_TRUE, errbuf)) == NULL) { 12775094Slling return (-1); 12785320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 12795320Slling nvlist_free(props); 12805094Slling return (-1); 12815320Slling } 12825094Slling } 1283789Sahrens 1284789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1285789Sahrens 1286789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 12871544Seschrock &zc.zc_guid) == 0); 1288789Sahrens 12895320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 12905320Slling nvlist_free(props); 12912082Seschrock return (-1); 12925320Slling } 1293789Sahrens 12946643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1295789Sahrens ret = 0; 12964543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1297789Sahrens char desc[1024]; 1298789Sahrens if (newname == NULL) 1299789Sahrens (void) snprintf(desc, sizeof (desc), 1300789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1301789Sahrens thename); 1302789Sahrens else 1303789Sahrens (void) snprintf(desc, sizeof (desc), 1304789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1305789Sahrens origname, thename); 1306789Sahrens 1307789Sahrens switch (errno) { 13081544Seschrock case ENOTSUP: 13091544Seschrock /* 13101544Seschrock * Unsupported version. 13111544Seschrock */ 13122082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 13131544Seschrock break; 13141544Seschrock 13152174Seschrock case EINVAL: 13162174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 13172174Seschrock break; 13182174Seschrock 1319789Sahrens default: 13202082Seschrock (void) zpool_standard_error(hdl, errno, desc); 1321789Sahrens } 1322789Sahrens 1323789Sahrens ret = -1; 1324789Sahrens } else { 1325789Sahrens zpool_handle_t *zhp; 13264543Smarks 1327789Sahrens /* 1328789Sahrens * This should never fail, but play it safe anyway. 1329789Sahrens */ 1330*10588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 13312142Seschrock ret = -1; 1332*10588SEric.Taylor@Sun.COM else if (zhp != NULL) 1333789Sahrens zpool_close(zhp); 1334789Sahrens } 1335789Sahrens 13362676Seschrock zcmd_free_nvlists(&zc); 13375320Slling nvlist_free(props); 13385320Slling 1339789Sahrens return (ret); 1340789Sahrens } 1341789Sahrens 1342789Sahrens /* 1343789Sahrens * Scrub the pool. 1344789Sahrens */ 1345789Sahrens int 1346789Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1347789Sahrens { 1348789Sahrens zfs_cmd_t zc = { 0 }; 1349789Sahrens char msg[1024]; 13502082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1351789Sahrens 1352789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1353789Sahrens zc.zc_cookie = type; 1354789Sahrens 13554543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1356789Sahrens return (0); 1357789Sahrens 1358789Sahrens (void) snprintf(msg, sizeof (msg), 1359789Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1360789Sahrens 13612082Seschrock if (errno == EBUSY) 13622082Seschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 13632082Seschrock else 13642082Seschrock return (zpool_standard_error(hdl, errno, msg)); 1365789Sahrens } 1366789Sahrens 13672468Sek110237 /* 13689816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 13699816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 13702468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 13712468Sek110237 * spare; but FALSE if its an INUSE spare. 13722468Sek110237 */ 13732082Seschrock static nvlist_t * 13749816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 13759816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 13761544Seschrock { 13771544Seschrock uint_t c, children; 13781544Seschrock nvlist_t **child; 13792082Seschrock nvlist_t *ret; 13807326SEric.Schrock@Sun.COM uint64_t is_log; 13819816SGeorge.Wilson@Sun.COM char *srchkey; 13829816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 13839816SGeorge.Wilson@Sun.COM 13849816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 13859816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 13869816SGeorge.Wilson@Sun.COM return (NULL); 13879816SGeorge.Wilson@Sun.COM 13889816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 13899816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 13909816SGeorge.Wilson@Sun.COM 13919816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 13929816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 13939816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 13949816SGeorge.Wilson@Sun.COM 13959816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 13969816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 13979816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 13989816SGeorge.Wilson@Sun.COM &present) == 0) { 13999816SGeorge.Wilson@Sun.COM /* 14009816SGeorge.Wilson@Sun.COM * If the device has never been present since 14019816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 14029816SGeorge.Wilson@Sun.COM * vdev is by GUID. 14039816SGeorge.Wilson@Sun.COM */ 14049816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 14059816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 14069816SGeorge.Wilson@Sun.COM if (theguid == srchval) 14079816SGeorge.Wilson@Sun.COM return (nv); 14089816SGeorge.Wilson@Sun.COM } 14099816SGeorge.Wilson@Sun.COM } 14109816SGeorge.Wilson@Sun.COM break; 14119816SGeorge.Wilson@Sun.COM } 14129816SGeorge.Wilson@Sun.COM 14139816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 14149816SGeorge.Wilson@Sun.COM char *srchval, *val; 14159816SGeorge.Wilson@Sun.COM 14169816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 14179816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 14189816SGeorge.Wilson@Sun.COM break; 14199816SGeorge.Wilson@Sun.COM 14201544Seschrock /* 14219816SGeorge.Wilson@Sun.COM * Search for the requested value. We special case the search 14229816SGeorge.Wilson@Sun.COM * for ZPOOL_CONFIG_PATH when it's a wholedisk. Otherwise, 14239816SGeorge.Wilson@Sun.COM * all other searches are simple string compares. 14241544Seschrock */ 14259816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 14269816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 14279816SGeorge.Wilson@Sun.COM 14289816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 14299816SGeorge.Wilson@Sun.COM &wholedisk); 14309816SGeorge.Wilson@Sun.COM if (wholedisk) { 14319816SGeorge.Wilson@Sun.COM /* 14329816SGeorge.Wilson@Sun.COM * For whole disks, the internal path has 's0', 14339816SGeorge.Wilson@Sun.COM * but the path passed in by the user doesn't. 14349816SGeorge.Wilson@Sun.COM */ 14359816SGeorge.Wilson@Sun.COM if (strlen(srchval) == strlen(val) - 2 && 14369816SGeorge.Wilson@Sun.COM strncmp(srchval, val, strlen(srchval)) == 0) 14379816SGeorge.Wilson@Sun.COM return (nv); 14389816SGeorge.Wilson@Sun.COM break; 14399816SGeorge.Wilson@Sun.COM } 14409816SGeorge.Wilson@Sun.COM } 14419816SGeorge.Wilson@Sun.COM 14429816SGeorge.Wilson@Sun.COM /* 14439816SGeorge.Wilson@Sun.COM * Common case 14449816SGeorge.Wilson@Sun.COM */ 14459816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 14462082Seschrock return (nv); 14479816SGeorge.Wilson@Sun.COM break; 14489816SGeorge.Wilson@Sun.COM } 14499816SGeorge.Wilson@Sun.COM 14509816SGeorge.Wilson@Sun.COM default: 14519816SGeorge.Wilson@Sun.COM break; 14521544Seschrock } 14531544Seschrock 14541544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 14551544Seschrock &child, &children) != 0) 14562082Seschrock return (NULL); 14571544Seschrock 14587326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 14599816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 14607326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 14617326SEric.Schrock@Sun.COM /* 14627326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 14637326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 14647326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 14657326SEric.Schrock@Sun.COM * 'log' is non-NULL). 14667326SEric.Schrock@Sun.COM */ 14677326SEric.Schrock@Sun.COM if (log != NULL && 14687326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 14697326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 14707326SEric.Schrock@Sun.COM is_log) { 14717326SEric.Schrock@Sun.COM *log = B_TRUE; 14727326SEric.Schrock@Sun.COM } 14731544Seschrock return (ret); 14747326SEric.Schrock@Sun.COM } 14757326SEric.Schrock@Sun.COM } 14761544Seschrock 14772082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 14782082Seschrock &child, &children) == 0) { 14792082Seschrock for (c = 0; c < children; c++) { 14809816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 14817326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 14822468Sek110237 *avail_spare = B_TRUE; 14832082Seschrock return (ret); 14842082Seschrock } 14852082Seschrock } 14862082Seschrock } 14872082Seschrock 14885450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 14895450Sbrendan &child, &children) == 0) { 14905450Sbrendan for (c = 0; c < children; c++) { 14919816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 14927326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 14935450Sbrendan *l2cache = B_TRUE; 14945450Sbrendan return (ret); 14955450Sbrendan } 14965450Sbrendan } 14975450Sbrendan } 14985450Sbrendan 14992082Seschrock return (NULL); 15001544Seschrock } 15011544Seschrock 15029816SGeorge.Wilson@Sun.COM /* 15039816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 15049816SGeorge.Wilson@Sun.COM * associated vdev. 15059816SGeorge.Wilson@Sun.COM */ 15069816SGeorge.Wilson@Sun.COM nvlist_t * 15079816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 15089816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 15099816SGeorge.Wilson@Sun.COM { 15109816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 15119816SGeorge.Wilson@Sun.COM 15129816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15139816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 15149816SGeorge.Wilson@Sun.COM 15159816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 15169816SGeorge.Wilson@Sun.COM &nvroot) == 0); 15179816SGeorge.Wilson@Sun.COM 15189816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 15199816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 15209816SGeorge.Wilson@Sun.COM nvlist_free(search); 15219816SGeorge.Wilson@Sun.COM 15229816SGeorge.Wilson@Sun.COM return (ret); 15239816SGeorge.Wilson@Sun.COM } 15249816SGeorge.Wilson@Sun.COM 15252082Seschrock nvlist_t * 15265450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 15277326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 15281544Seschrock { 15291544Seschrock char buf[MAXPATHLEN]; 15301544Seschrock char *end; 15319816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 15321544Seschrock uint64_t guid; 15331544Seschrock 15349816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 15359816SGeorge.Wilson@Sun.COM 15361613Seschrock guid = strtoull(path, &end, 10); 15371544Seschrock if (guid != 0 && *end == '\0') { 15389816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 15391544Seschrock } else if (path[0] != '/') { 15401544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 15419816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 15421544Seschrock } else { 15439816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 15441544Seschrock } 15451544Seschrock 15461544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 15471544Seschrock &nvroot) == 0); 15481544Seschrock 15492468Sek110237 *avail_spare = B_FALSE; 15505450Sbrendan *l2cache = B_FALSE; 15517326SEric.Schrock@Sun.COM if (log != NULL) 15527326SEric.Schrock@Sun.COM *log = B_FALSE; 15539816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 15549816SGeorge.Wilson@Sun.COM nvlist_free(search); 15559816SGeorge.Wilson@Sun.COM 15569816SGeorge.Wilson@Sun.COM return (ret); 15572468Sek110237 } 15582468Sek110237 15597656SSherry.Moore@Sun.COM static int 15607656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 15617656SSherry.Moore@Sun.COM { 15627656SSherry.Moore@Sun.COM uint64_t ival; 15637656SSherry.Moore@Sun.COM 15647656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 15657656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 15667656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 15677656SSherry.Moore@Sun.COM return (0); 15687656SSherry.Moore@Sun.COM 15697656SSherry.Moore@Sun.COM return (1); 15707656SSherry.Moore@Sun.COM } 15717656SSherry.Moore@Sun.COM 15727656SSherry.Moore@Sun.COM /* 15739790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 15747656SSherry.Moore@Sun.COM */ 15759160SSherry.Moore@Sun.COM static int 15769790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 15779160SSherry.Moore@Sun.COM size_t *bytes_written) 15787656SSherry.Moore@Sun.COM { 15799160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 15809160SSherry.Moore@Sun.COM char *tmppath; 15819160SSherry.Moore@Sun.COM const char *format; 15829160SSherry.Moore@Sun.COM 15839160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 15849160SSherry.Moore@Sun.COM &tmppath) != 0) 15859160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 15869160SSherry.Moore@Sun.COM 15879160SSherry.Moore@Sun.COM pos = *bytes_written; 15889160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 15899160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 15909160SSherry.Moore@Sun.COM 15919160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 15929160SSherry.Moore@Sun.COM *bytes_written += rsz; 15939160SSherry.Moore@Sun.COM 15949160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 15959160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 15969160SSherry.Moore@Sun.COM if (bytes_left != 0) { 15979160SSherry.Moore@Sun.COM physpath[pos] = 0; 15989160SSherry.Moore@Sun.COM } 15999160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 16009160SSherry.Moore@Sun.COM } 16019160SSherry.Moore@Sun.COM return (0); 16029160SSherry.Moore@Sun.COM } 16039160SSherry.Moore@Sun.COM 16049790SLin.Ling@Sun.COM static int 16059790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 16069790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 16079790SLin.Ling@Sun.COM { 16089790SLin.Ling@Sun.COM char *type; 16099790SLin.Ling@Sun.COM int ret; 16109790SLin.Ling@Sun.COM 16119790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 16129790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16139790SLin.Ling@Sun.COM 16149790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 16159790SLin.Ling@Sun.COM /* 16169790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 16179790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 16189790SLin.Ling@Sun.COM * spare device. 16199790SLin.Ling@Sun.COM */ 16209790SLin.Ling@Sun.COM if (is_spare) { 16219790SLin.Ling@Sun.COM uint64_t spare = 0; 16229790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 16239790SLin.Ling@Sun.COM &spare); 16249790SLin.Ling@Sun.COM if (!spare) 16259790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16269790SLin.Ling@Sun.COM } 16279790SLin.Ling@Sun.COM 16289790SLin.Ling@Sun.COM if (vdev_online(nv)) { 16299790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 16309790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 16319790SLin.Ling@Sun.COM return (ret); 16329790SLin.Ling@Sun.COM } 16339790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 16349790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 16359790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 16369790SLin.Ling@Sun.COM nvlist_t **child; 16379790SLin.Ling@Sun.COM uint_t count; 16389790SLin.Ling@Sun.COM int i, ret; 16399790SLin.Ling@Sun.COM 16409790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 16419790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 16429790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 16439790SLin.Ling@Sun.COM 16449790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 16459790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 16469790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 16479790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 16489790SLin.Ling@Sun.COM return (ret); 16499790SLin.Ling@Sun.COM } 16509790SLin.Ling@Sun.COM } 16519790SLin.Ling@Sun.COM 16529790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 16539790SLin.Ling@Sun.COM } 16549790SLin.Ling@Sun.COM 16559160SSherry.Moore@Sun.COM /* 16569160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 16579160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 16589160SSherry.Moore@Sun.COM */ 16599160SSherry.Moore@Sun.COM static int 16609160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 16619160SSherry.Moore@Sun.COM { 16629160SSherry.Moore@Sun.COM size_t rsz; 16637656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 16647656SSherry.Moore@Sun.COM nvlist_t **child; 16657656SSherry.Moore@Sun.COM uint_t count; 16669160SSherry.Moore@Sun.COM char *type; 16679160SSherry.Moore@Sun.COM 16689160SSherry.Moore@Sun.COM rsz = 0; 16699160SSherry.Moore@Sun.COM 16709160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 16719160SSherry.Moore@Sun.COM &vdev_root) != 0) 16729160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 16739160SSherry.Moore@Sun.COM 16749160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 16759160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 16769160SSherry.Moore@Sun.COM &child, &count) != 0) 16779160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 16787656SSherry.Moore@Sun.COM 16797656SSherry.Moore@Sun.COM /* 16809160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 16819160SSherry.Moore@Sun.COM * a single top-level vdev. 16827656SSherry.Moore@Sun.COM */ 16839160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 16849160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 16859160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 16869160SSherry.Moore@Sun.COM 16879790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 16889790SLin.Ling@Sun.COM B_FALSE); 16897656SSherry.Moore@Sun.COM 16909160SSherry.Moore@Sun.COM /* No online devices */ 16919160SSherry.Moore@Sun.COM if (rsz == 0) 16929160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 16939160SSherry.Moore@Sun.COM 16947656SSherry.Moore@Sun.COM return (0); 16957656SSherry.Moore@Sun.COM } 16967656SSherry.Moore@Sun.COM 16972468Sek110237 /* 16989160SSherry.Moore@Sun.COM * Get phys_path for a root pool 16999160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 17009160SSherry.Moore@Sun.COM */ 17019160SSherry.Moore@Sun.COM int 17029160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 17039160SSherry.Moore@Sun.COM { 17049160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 17059160SSherry.Moore@Sun.COM phypath_size)); 17069160SSherry.Moore@Sun.COM } 17079160SSherry.Moore@Sun.COM 17089160SSherry.Moore@Sun.COM /* 17095450Sbrendan * Returns TRUE if the given guid corresponds to the given type. 17105450Sbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 17115450Sbrendan * devices. 17122468Sek110237 */ 17132468Sek110237 static boolean_t 17145450Sbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 17152468Sek110237 { 17165450Sbrendan uint64_t target_guid; 17172468Sek110237 nvlist_t *nvroot; 17185450Sbrendan nvlist_t **list; 17195450Sbrendan uint_t count; 17202468Sek110237 int i; 17212468Sek110237 17222468Sek110237 verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 17232468Sek110237 &nvroot) == 0); 17245450Sbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 17255450Sbrendan for (i = 0; i < count; i++) { 17265450Sbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 17275450Sbrendan &target_guid) == 0); 17285450Sbrendan if (guid == target_guid) 17292468Sek110237 return (B_TRUE); 17302468Sek110237 } 17312468Sek110237 } 17322468Sek110237 17332468Sek110237 return (B_FALSE); 17341544Seschrock } 17351544Seschrock 1736789Sahrens /* 17379816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 17389816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 17399816SGeorge.Wilson@Sun.COM */ 17409816SGeorge.Wilson@Sun.COM static int 17419816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 17429816SGeorge.Wilson@Sun.COM { 17439816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 17449816SGeorge.Wilson@Sun.COM char errbuf[1024]; 17459816SGeorge.Wilson@Sun.COM int fd, error; 17469816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 17479816SGeorge.Wilson@Sun.COM 17489816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 17499816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 17509816SGeorge.Wilson@Sun.COM return (-1); 17519816SGeorge.Wilson@Sun.COM 17529816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 17539816SGeorge.Wilson@Sun.COM 17549816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 17559816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 17569816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 17579816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 17589816SGeorge.Wilson@Sun.COM } 17599816SGeorge.Wilson@Sun.COM 17609816SGeorge.Wilson@Sun.COM /* 17619816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 17629816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 17639816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 17649816SGeorge.Wilson@Sun.COM */ 17659816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 17669816SGeorge.Wilson@Sun.COM (void) close(fd); 17679816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 17689816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 17699816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 17709816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 17719816SGeorge.Wilson@Sun.COM } 17729816SGeorge.Wilson@Sun.COM return (0); 17739816SGeorge.Wilson@Sun.COM } 17749816SGeorge.Wilson@Sun.COM 17759816SGeorge.Wilson@Sun.COM /* 17764451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 17774451Seschrock * ZFS_ONLINE_* flags. 1778789Sahrens */ 1779789Sahrens int 17804451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 17814451Seschrock vdev_state_t *newstate) 1782789Sahrens { 1783789Sahrens zfs_cmd_t zc = { 0 }; 1784789Sahrens char msg[1024]; 17852082Seschrock nvlist_t *tgt; 17869816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 17872082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1788789Sahrens 17899816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 17909816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 17919816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 17929816SGeorge.Wilson@Sun.COM } else { 17939816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 17949816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 17959816SGeorge.Wilson@Sun.COM } 1796789Sahrens 17971544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 17987326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 17999816SGeorge.Wilson@Sun.COM &islog)) == NULL) 18002082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1801789Sahrens 18022468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 18032468Sek110237 18045450Sbrendan if (avail_spare || 18055450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 18062082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 18072082Seschrock 18089816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 18099816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 18109816SGeorge.Wilson@Sun.COM char *pathname = NULL; 18119816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 18129816SGeorge.Wilson@Sun.COM 18139816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 18149816SGeorge.Wilson@Sun.COM &wholedisk); 18159816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 18169816SGeorge.Wilson@Sun.COM &pathname) == 0); 18179816SGeorge.Wilson@Sun.COM 18189816SGeorge.Wilson@Sun.COM /* 18199816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 18209816SGeorge.Wilson@Sun.COM */ 18219816SGeorge.Wilson@Sun.COM if (l2cache) { 18229816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18239816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 18249816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 18259816SGeorge.Wilson@Sun.COM } 18269816SGeorge.Wilson@Sun.COM 18279816SGeorge.Wilson@Sun.COM if (wholedisk) { 18289816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 18299816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 18309816SGeorge.Wilson@Sun.COM } 18319816SGeorge.Wilson@Sun.COM } 18329816SGeorge.Wilson@Sun.COM 18334451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 18344451Seschrock zc.zc_obj = flags; 18354451Seschrock 18364543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 18374451Seschrock return (zpool_standard_error(hdl, errno, msg)); 18384451Seschrock 18394451Seschrock *newstate = zc.zc_cookie; 18404451Seschrock return (0); 1841789Sahrens } 1842789Sahrens 1843789Sahrens /* 1844789Sahrens * Take the specified vdev offline 1845789Sahrens */ 1846789Sahrens int 18474451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1848789Sahrens { 1849789Sahrens zfs_cmd_t zc = { 0 }; 1850789Sahrens char msg[1024]; 18512082Seschrock nvlist_t *tgt; 18525450Sbrendan boolean_t avail_spare, l2cache; 18532082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1854789Sahrens 18551544Seschrock (void) snprintf(msg, sizeof (msg), 18561544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 18571544Seschrock 1858789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 18597326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 18607326SEric.Schrock@Sun.COM NULL)) == NULL) 18612082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 18622082Seschrock 18632468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 18642468Sek110237 18655450Sbrendan if (avail_spare || 18665450Sbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 18672082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 18682082Seschrock 18694451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 18704451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 18711485Slling 18724543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1873789Sahrens return (0); 1874789Sahrens 1875789Sahrens switch (errno) { 18762082Seschrock case EBUSY: 1877789Sahrens 1878789Sahrens /* 1879789Sahrens * There are no other replicas of this device. 1880789Sahrens */ 18812082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 18822082Seschrock 18839701SGeorge.Wilson@Sun.COM case EEXIST: 18849701SGeorge.Wilson@Sun.COM /* 18859701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 18869701SGeorge.Wilson@Sun.COM */ 18879701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 18889701SGeorge.Wilson@Sun.COM 18892082Seschrock default: 18902082Seschrock return (zpool_standard_error(hdl, errno, msg)); 18912082Seschrock } 18922082Seschrock } 1893789Sahrens 18942082Seschrock /* 18954451Seschrock * Mark the given vdev faulted. 18964451Seschrock */ 18974451Seschrock int 18984451Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 18994451Seschrock { 19004451Seschrock zfs_cmd_t zc = { 0 }; 19014451Seschrock char msg[1024]; 19024451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19034451Seschrock 19044451Seschrock (void) snprintf(msg, sizeof (msg), 19054451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 19064451Seschrock 19074451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19084451Seschrock zc.zc_guid = guid; 19094451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 19104451Seschrock 19114451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19124451Seschrock return (0); 19134451Seschrock 19144451Seschrock switch (errno) { 19154451Seschrock case EBUSY: 19164451Seschrock 19174451Seschrock /* 19184451Seschrock * There are no other replicas of this device. 19194451Seschrock */ 19204451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 19214451Seschrock 19224451Seschrock default: 19234451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19244451Seschrock } 19254451Seschrock 19264451Seschrock } 19274451Seschrock 19284451Seschrock /* 19294451Seschrock * Mark the given vdev degraded. 19304451Seschrock */ 19314451Seschrock int 19324451Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 19334451Seschrock { 19344451Seschrock zfs_cmd_t zc = { 0 }; 19354451Seschrock char msg[1024]; 19364451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19374451Seschrock 19384451Seschrock (void) snprintf(msg, sizeof (msg), 19394451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 19404451Seschrock 19414451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19424451Seschrock zc.zc_guid = guid; 19434451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 19444451Seschrock 19454451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19464451Seschrock return (0); 19474451Seschrock 19484451Seschrock return (zpool_standard_error(hdl, errno, msg)); 19494451Seschrock } 19504451Seschrock 19514451Seschrock /* 19522082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 19532082Seschrock * a hot spare. 19542082Seschrock */ 19552082Seschrock static boolean_t 19562082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 19572082Seschrock { 19582082Seschrock nvlist_t **child; 19592082Seschrock uint_t c, children; 19602082Seschrock char *type; 19612082Seschrock 19622082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 19632082Seschrock &children) == 0) { 19642082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 19652082Seschrock &type) == 0); 19662082Seschrock 19672082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 19682082Seschrock children == 2 && child[which] == tgt) 19692082Seschrock return (B_TRUE); 19702082Seschrock 19712082Seschrock for (c = 0; c < children; c++) 19722082Seschrock if (is_replacing_spare(child[c], tgt, which)) 19732082Seschrock return (B_TRUE); 1974789Sahrens } 19752082Seschrock 19762082Seschrock return (B_FALSE); 1977789Sahrens } 1978789Sahrens 1979789Sahrens /* 1980789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 19814527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 1982789Sahrens */ 1983789Sahrens int 1984789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 1985789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 1986789Sahrens { 1987789Sahrens zfs_cmd_t zc = { 0 }; 1988789Sahrens char msg[1024]; 1989789Sahrens int ret; 19902082Seschrock nvlist_t *tgt; 19917326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 19927326SEric.Schrock@Sun.COM uint64_t val; 19937041Seschrock char *path, *newname; 19942082Seschrock nvlist_t **child; 19952082Seschrock uint_t children; 19962082Seschrock nvlist_t *config_root; 19972082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19987965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 1999789Sahrens 20001544Seschrock if (replacing) 20011544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20021544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 20031544Seschrock else 20041544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 20051544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 20061544Seschrock 20077965SGeorge.Wilson@Sun.COM /* 20087965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 20097965SGeorge.Wilson@Sun.COM * EFI labeled device. 20107965SGeorge.Wilson@Sun.COM */ 20117965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 20127965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20137965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 20147965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 20157965SGeorge.Wilson@Sun.COM } 20167965SGeorge.Wilson@Sun.COM 2017789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20187326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 20197326SEric.Schrock@Sun.COM &islog)) == 0) 20202082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 20212082Seschrock 20222468Sek110237 if (avail_spare) 20232082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20242082Seschrock 20255450Sbrendan if (l2cache) 20265450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 20275450Sbrendan 20282082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20292082Seschrock zc.zc_cookie = replacing; 20302082Seschrock 20312082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 20322082Seschrock &child, &children) != 0 || children != 1) { 20332082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20342082Seschrock "new device must be a single disk")); 20352082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 20361544Seschrock } 20372082Seschrock 20382082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 20392082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 20402082Seschrock 20417041Seschrock if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL) 20427041Seschrock return (-1); 20437041Seschrock 20442082Seschrock /* 20452082Seschrock * If the target is a hot spare that has been swapped in, we can only 20462082Seschrock * replace it with another hot spare. 20472082Seschrock */ 20482082Seschrock if (replacing && 20492082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 20507326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 20517326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 20527326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 20532082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20542082Seschrock "can only be replaced by another hot spare")); 20557041Seschrock free(newname); 20562082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 20572082Seschrock } 20582082Seschrock 20592082Seschrock /* 20602082Seschrock * If we are attempting to replace a spare, it canot be applied to an 20612082Seschrock * already spared device. 20622082Seschrock */ 20632082Seschrock if (replacing && 20642082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 20657326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 20667326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 20677326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 20682082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20692082Seschrock "device has already been replaced with a spare")); 20707041Seschrock free(newname); 20712082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 20722082Seschrock } 2073789Sahrens 20747041Seschrock free(newname); 20757041Seschrock 20765094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 20772082Seschrock return (-1); 2078789Sahrens 20794543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2080789Sahrens 20812676Seschrock zcmd_free_nvlists(&zc); 2082789Sahrens 20837965SGeorge.Wilson@Sun.COM if (ret == 0) { 20847965SGeorge.Wilson@Sun.COM if (rootpool) { 20857965SGeorge.Wilson@Sun.COM /* 20867965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 20877965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 20887965SGeorge.Wilson@Sun.COM * newly attached disk. 20897965SGeorge.Wilson@Sun.COM */ 20907965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 20917965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 20927965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 20939790SLin.Ling@Sun.COM 20949790SLin.Ling@Sun.COM /* 20959790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 20969790SLin.Ling@Sun.COM * booting up a half-baked vdev. 20979790SLin.Ling@Sun.COM */ 20989790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 20999790SLin.Ling@Sun.COM "sure to wait until resilver is done " 21009790SLin.Ling@Sun.COM "before rebooting.\n")); 21017965SGeorge.Wilson@Sun.COM } 2102789Sahrens return (0); 21037965SGeorge.Wilson@Sun.COM } 2104789Sahrens 2105789Sahrens switch (errno) { 21061544Seschrock case ENOTSUP: 2107789Sahrens /* 2108789Sahrens * Can't attach to or replace this type of vdev. 2109789Sahrens */ 21104527Sperrin if (replacing) { 21117326SEric.Schrock@Sun.COM if (islog) 21124527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21134527Sperrin "cannot replace a log with a spare")); 21144527Sperrin else 21154527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21164527Sperrin "cannot replace a replacing device")); 21174527Sperrin } else { 21182082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21192082Seschrock "can only attach to mirrors and top-level " 21202082Seschrock "disks")); 21214527Sperrin } 21222082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2123789Sahrens break; 2124789Sahrens 21251544Seschrock case EINVAL: 2126789Sahrens /* 2127789Sahrens * The new device must be a single disk. 2128789Sahrens */ 21292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21302082Seschrock "new device must be a single disk")); 21312082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2132789Sahrens break; 2133789Sahrens 21341544Seschrock case EBUSY: 21352082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 21362082Seschrock new_disk); 21372082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2138789Sahrens break; 2139789Sahrens 21401544Seschrock case EOVERFLOW: 2141789Sahrens /* 2142789Sahrens * The new device is too small. 2143789Sahrens */ 21442082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21452082Seschrock "device is too small")); 21462082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2147789Sahrens break; 2148789Sahrens 21491544Seschrock case EDOM: 2150789Sahrens /* 2151789Sahrens * The new device has a different alignment requirement. 2152789Sahrens */ 21532082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21542082Seschrock "devices have different sector alignment")); 21552082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2156789Sahrens break; 2157789Sahrens 21581544Seschrock case ENAMETOOLONG: 2159789Sahrens /* 2160789Sahrens * The resulting top-level vdev spec won't fit in the label. 2161789Sahrens */ 21622082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2163789Sahrens break; 2164789Sahrens 21651544Seschrock default: 21662082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2167789Sahrens } 2168789Sahrens 21692082Seschrock return (-1); 2170789Sahrens } 2171789Sahrens 2172789Sahrens /* 2173789Sahrens * Detach the specified device. 2174789Sahrens */ 2175789Sahrens int 2176789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2177789Sahrens { 2178789Sahrens zfs_cmd_t zc = { 0 }; 2179789Sahrens char msg[1024]; 21802082Seschrock nvlist_t *tgt; 21815450Sbrendan boolean_t avail_spare, l2cache; 21822082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2183789Sahrens 21841544Seschrock (void) snprintf(msg, sizeof (msg), 21851544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 21861544Seschrock 2187789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21887326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 21897326SEric.Schrock@Sun.COM NULL)) == 0) 21902082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2191789Sahrens 21922468Sek110237 if (avail_spare) 21932082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21942082Seschrock 21955450Sbrendan if (l2cache) 21965450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 21975450Sbrendan 21982082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 21992082Seschrock 22004543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2201789Sahrens return (0); 2202789Sahrens 2203789Sahrens switch (errno) { 2204789Sahrens 22051544Seschrock case ENOTSUP: 2206789Sahrens /* 2207789Sahrens * Can't detach from this type of vdev. 2208789Sahrens */ 22092082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 22102082Seschrock "applicable to mirror and replacing vdevs")); 22112082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2212789Sahrens break; 2213789Sahrens 22141544Seschrock case EBUSY: 2215789Sahrens /* 2216789Sahrens * There are no other replicas of this device. 2217789Sahrens */ 22182082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2219789Sahrens break; 2220789Sahrens 22211544Seschrock default: 22222082Seschrock (void) zpool_standard_error(hdl, errno, msg); 22231544Seschrock } 22241544Seschrock 22252082Seschrock return (-1); 22262082Seschrock } 22272082Seschrock 22282082Seschrock /* 22295450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 22305450Sbrendan * and level 2 cache devices. 22312082Seschrock */ 22322082Seschrock int 22332082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 22342082Seschrock { 22352082Seschrock zfs_cmd_t zc = { 0 }; 22362082Seschrock char msg[1024]; 22372082Seschrock nvlist_t *tgt; 22385450Sbrendan boolean_t avail_spare, l2cache; 22392082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22402082Seschrock 22412082Seschrock (void) snprintf(msg, sizeof (msg), 22422082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 22432082Seschrock 22442082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22457326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 22467326SEric.Schrock@Sun.COM NULL)) == 0) 22472082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22482082Seschrock 22495450Sbrendan if (!avail_spare && !l2cache) { 22502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 22515450Sbrendan "only inactive hot spares or cache devices " 22525450Sbrendan "can be removed")); 22532082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22542082Seschrock } 22552082Seschrock 22562082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 22572082Seschrock 22584543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 22592082Seschrock return (0); 22602082Seschrock 22612082Seschrock return (zpool_standard_error(hdl, errno, msg)); 22621544Seschrock } 22631544Seschrock 22641544Seschrock /* 22651544Seschrock * Clear the errors for the pool, or the particular device if specified. 22661544Seschrock */ 22671544Seschrock int 22681544Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 22691544Seschrock { 22701544Seschrock zfs_cmd_t zc = { 0 }; 22711544Seschrock char msg[1024]; 22722082Seschrock nvlist_t *tgt; 22735450Sbrendan boolean_t avail_spare, l2cache; 22742082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22751544Seschrock 22761544Seschrock if (path) 22771544Seschrock (void) snprintf(msg, sizeof (msg), 22781544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 22792676Seschrock path); 22801544Seschrock else 22811544Seschrock (void) snprintf(msg, sizeof (msg), 22821544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 22831544Seschrock zhp->zpool_name); 22841544Seschrock 22851544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22862082Seschrock if (path) { 22875450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 22887326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 22892082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 22902082Seschrock 22915450Sbrendan /* 22925450Sbrendan * Don't allow error clearing for hot spares. Do allow 22935450Sbrendan * error clearing for l2cache devices. 22945450Sbrendan */ 22952468Sek110237 if (avail_spare) 22962082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 22972082Seschrock 22982082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 22992082Seschrock &zc.zc_guid) == 0); 23001544Seschrock } 23011544Seschrock 23024543Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 23031544Seschrock return (0); 23041544Seschrock 23052082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2306789Sahrens } 2307789Sahrens 23083126Sahl /* 23094451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 23104451Seschrock */ 23114451Seschrock int 23124451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 23134451Seschrock { 23144451Seschrock zfs_cmd_t zc = { 0 }; 23154451Seschrock char msg[1024]; 23164451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23174451Seschrock 23184451Seschrock (void) snprintf(msg, sizeof (msg), 23194451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 23204451Seschrock guid); 23214451Seschrock 23224451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23234451Seschrock zc.zc_guid = guid; 23244451Seschrock 23254451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 23264451Seschrock return (0); 23274451Seschrock 23284451Seschrock return (zpool_standard_error(hdl, errno, msg)); 23294451Seschrock } 23304451Seschrock 23314451Seschrock /* 23321354Seschrock * Convert from a devid string to a path. 23331354Seschrock */ 23341354Seschrock static char * 23351354Seschrock devid_to_path(char *devid_str) 23361354Seschrock { 23371354Seschrock ddi_devid_t devid; 23381354Seschrock char *minor; 23391354Seschrock char *path; 23401354Seschrock devid_nmlist_t *list = NULL; 23411354Seschrock int ret; 23421354Seschrock 23431354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 23441354Seschrock return (NULL); 23451354Seschrock 23461354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 23471354Seschrock 23481354Seschrock devid_str_free(minor); 23491354Seschrock devid_free(devid); 23501354Seschrock 23511354Seschrock if (ret != 0) 23521354Seschrock return (NULL); 23531354Seschrock 23542082Seschrock if ((path = strdup(list[0].devname)) == NULL) 23552082Seschrock return (NULL); 23562082Seschrock 23571354Seschrock devid_free_nmlist(list); 23581354Seschrock 23591354Seschrock return (path); 23601354Seschrock } 23611354Seschrock 23621354Seschrock /* 23631354Seschrock * Convert from a path to a devid string. 23641354Seschrock */ 23651354Seschrock static char * 23661354Seschrock path_to_devid(const char *path) 23671354Seschrock { 23681354Seschrock int fd; 23691354Seschrock ddi_devid_t devid; 23701354Seschrock char *minor, *ret; 23711354Seschrock 23721354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 23731354Seschrock return (NULL); 23741354Seschrock 23751354Seschrock minor = NULL; 23761354Seschrock ret = NULL; 23771354Seschrock if (devid_get(fd, &devid) == 0) { 23781354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 23791354Seschrock ret = devid_str_encode(devid, minor); 23801354Seschrock if (minor != NULL) 23811354Seschrock devid_str_free(minor); 23821354Seschrock devid_free(devid); 23831354Seschrock } 23841354Seschrock (void) close(fd); 23851354Seschrock 23861354Seschrock return (ret); 23871354Seschrock } 23881354Seschrock 23891354Seschrock /* 23901354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 23911354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 23921354Seschrock * type 'zpool status', and we'll display the correct information anyway. 23931354Seschrock */ 23941354Seschrock static void 23951354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 23961354Seschrock { 23971354Seschrock zfs_cmd_t zc = { 0 }; 23981354Seschrock 23991354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24002676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 24011354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 24021544Seschrock &zc.zc_guid) == 0); 24031354Seschrock 24042082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 24051354Seschrock } 24061354Seschrock 24071354Seschrock /* 24081354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 24091354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 24101354Seschrock * We also check if this is a whole disk, in which case we strip off the 24111354Seschrock * trailing 's0' slice name. 24121354Seschrock * 24131354Seschrock * This routine is also responsible for identifying when disks have been 24141354Seschrock * reconfigured in a new location. The kernel will have opened the device by 24151354Seschrock * devid, but the path will still refer to the old location. To catch this, we 24161354Seschrock * first do a path -> devid translation (which is fast for the common case). If 24171354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 24181354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 24191354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 24201354Seschrock * of these checks. 24211354Seschrock */ 24221354Seschrock char * 24232082Seschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 24241354Seschrock { 24251354Seschrock char *path, *devid; 24261544Seschrock uint64_t value; 24271544Seschrock char buf[64]; 24284451Seschrock vdev_stat_t *vs; 24294451Seschrock uint_t vsc; 24301354Seschrock 24311544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 24321544Seschrock &value) == 0) { 24331544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 24341544Seschrock &value) == 0); 24352856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 24362856Snd150628 (u_longlong_t)value); 24371544Seschrock path = buf; 24381544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 24391354Seschrock 24404451Seschrock /* 24414451Seschrock * If the device is dead (faulted, offline, etc) then don't 24424451Seschrock * bother opening it. Otherwise we may be forcing the user to 24434451Seschrock * open a misbehaving device, which can have undesirable 24444451Seschrock * effects. 24454451Seschrock */ 24464451Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 24474451Seschrock (uint64_t **)&vs, &vsc) != 0 || 24484451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 24494451Seschrock zhp != NULL && 24501354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 24511354Seschrock /* 24521354Seschrock * Determine if the current path is correct. 24531354Seschrock */ 24541354Seschrock char *newdevid = path_to_devid(path); 24551354Seschrock 24561354Seschrock if (newdevid == NULL || 24571354Seschrock strcmp(devid, newdevid) != 0) { 24581354Seschrock char *newpath; 24591354Seschrock 24601354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 24611354Seschrock /* 24621354Seschrock * Update the path appropriately. 24631354Seschrock */ 24641354Seschrock set_path(zhp, nv, newpath); 24652082Seschrock if (nvlist_add_string(nv, 24662082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 24672082Seschrock verify(nvlist_lookup_string(nv, 24682082Seschrock ZPOOL_CONFIG_PATH, 24692082Seschrock &path) == 0); 24701354Seschrock free(newpath); 24711354Seschrock } 24721354Seschrock } 24731354Seschrock 24742082Seschrock if (newdevid) 24752082Seschrock devid_str_free(newdevid); 24761354Seschrock } 24771354Seschrock 24781354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 24791354Seschrock path += 9; 24801354Seschrock 24811354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 24821544Seschrock &value) == 0 && value) { 24832082Seschrock char *tmp = zfs_strdup(hdl, path); 24842082Seschrock if (tmp == NULL) 24852082Seschrock return (NULL); 24861354Seschrock tmp[strlen(path) - 2] = '\0'; 24871354Seschrock return (tmp); 24881354Seschrock } 24891354Seschrock } else { 24901354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 24912082Seschrock 24922082Seschrock /* 24932082Seschrock * If it's a raidz device, we need to stick in the parity level. 24942082Seschrock */ 24952082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 24962082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 24972082Seschrock &value) == 0); 24982082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 24992856Snd150628 (u_longlong_t)value); 25002082Seschrock path = buf; 25012082Seschrock } 25021354Seschrock } 25031354Seschrock 25042082Seschrock return (zfs_strdup(hdl, path)); 25051354Seschrock } 25061544Seschrock 25071544Seschrock static int 25081544Seschrock zbookmark_compare(const void *a, const void *b) 25091544Seschrock { 25101544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 25111544Seschrock } 25121544Seschrock 25131544Seschrock /* 25141544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 25151544Seschrock * caller. 25161544Seschrock */ 25171544Seschrock int 25183444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 25191544Seschrock { 25201544Seschrock zfs_cmd_t zc = { 0 }; 25211544Seschrock uint64_t count; 25222676Seschrock zbookmark_t *zb = NULL; 25233444Sek110237 int i; 25241544Seschrock 25251544Seschrock /* 25261544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 25271544Seschrock * has increased, allocate more space and continue until we get the 25281544Seschrock * entire list. 25291544Seschrock */ 25301544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 25311544Seschrock &count) == 0); 25324820Sek110237 if (count == 0) 25334820Sek110237 return (0); 25342676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 25352856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 25362082Seschrock return (-1); 25372676Seschrock zc.zc_nvlist_dst_size = count; 25381544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 25391544Seschrock for (;;) { 25402082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 25412082Seschrock &zc) != 0) { 25422676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 25431544Seschrock if (errno == ENOMEM) { 25443823Svb160487 count = zc.zc_nvlist_dst_size; 25452676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 25463823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 25473823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 25482082Seschrock return (-1); 25491544Seschrock } else { 25501544Seschrock return (-1); 25511544Seschrock } 25521544Seschrock } else { 25531544Seschrock break; 25541544Seschrock } 25551544Seschrock } 25561544Seschrock 25571544Seschrock /* 25581544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 25591544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 25602676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 25611544Seschrock * _not_ copied as part of the process. So we point the start of our 25621544Seschrock * array appropriate and decrement the total number of elements. 25631544Seschrock */ 25642676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 25652676Seschrock zc.zc_nvlist_dst_size; 25662676Seschrock count -= zc.zc_nvlist_dst_size; 25671544Seschrock 25681544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 25691544Seschrock 25703444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 25711544Seschrock 25721544Seschrock /* 25733444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 25741544Seschrock */ 25751544Seschrock for (i = 0; i < count; i++) { 25761544Seschrock nvlist_t *nv; 25771544Seschrock 25783700Sek110237 /* ignoring zb_blkid and zb_level for now */ 25793700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 25803700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 25811544Seschrock continue; 25821544Seschrock 25833444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 25843444Sek110237 goto nomem; 25853444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 25863444Sek110237 zb[i].zb_objset) != 0) { 25873444Sek110237 nvlist_free(nv); 25882082Seschrock goto nomem; 25893444Sek110237 } 25903444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 25913444Sek110237 zb[i].zb_object) != 0) { 25923444Sek110237 nvlist_free(nv); 25933444Sek110237 goto nomem; 25941544Seschrock } 25953444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 25963444Sek110237 nvlist_free(nv); 25973444Sek110237 goto nomem; 25983444Sek110237 } 25993444Sek110237 nvlist_free(nv); 26001544Seschrock } 26011544Seschrock 26023265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 26031544Seschrock return (0); 26042082Seschrock 26052082Seschrock nomem: 26062676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 26072082Seschrock return (no_memory(zhp->zpool_hdl)); 26081544Seschrock } 26091760Seschrock 26101760Seschrock /* 26111760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 26121760Seschrock */ 26131760Seschrock int 26145094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 26151760Seschrock { 26161760Seschrock zfs_cmd_t zc = { 0 }; 26172082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 26181760Seschrock 26191760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 26205094Slling zc.zc_cookie = new_version; 26215094Slling 26224543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 26233237Slling return (zpool_standard_error_fmt(hdl, errno, 26242082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 26252082Seschrock zhp->zpool_name)); 26261760Seschrock return (0); 26271760Seschrock } 26282926Sek110237 26294988Sek110237 void 26304988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 26314988Sek110237 char *history_str) 26324988Sek110237 { 26334988Sek110237 int i; 26344988Sek110237 26354988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 26364988Sek110237 for (i = 1; i < argc; i++) { 26374988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 26384988Sek110237 HIS_MAX_RECORD_LEN) 26394988Sek110237 break; 26404988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 26414988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 26424988Sek110237 } 26434988Sek110237 } 26444988Sek110237 26452926Sek110237 /* 26464988Sek110237 * Stage command history for logging. 26472926Sek110237 */ 26484988Sek110237 int 26494988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 26502926Sek110237 { 26514988Sek110237 if (history_str == NULL) 26524988Sek110237 return (EINVAL); 26534988Sek110237 26544988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 26554988Sek110237 return (EINVAL); 26562926Sek110237 26574715Sek110237 if (hdl->libzfs_log_str != NULL) 26584543Smarks free(hdl->libzfs_log_str); 26592926Sek110237 26604988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 26614988Sek110237 return (no_memory(hdl)); 26624543Smarks 26634988Sek110237 return (0); 26642926Sek110237 } 26652926Sek110237 26662926Sek110237 /* 26672926Sek110237 * Perform ioctl to get some command history of a pool. 26682926Sek110237 * 26692926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 26702926Sek110237 * logical offset of the history buffer to start reading from. 26712926Sek110237 * 26722926Sek110237 * Upon return, 'off' is the next logical offset to read from and 26732926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 26742926Sek110237 */ 26752926Sek110237 static int 26762926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 26772926Sek110237 { 26782926Sek110237 zfs_cmd_t zc = { 0 }; 26792926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 26802926Sek110237 26812926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 26822926Sek110237 26832926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 26842926Sek110237 zc.zc_history_len = *len; 26852926Sek110237 zc.zc_history_offset = *off; 26862926Sek110237 26872926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 26882926Sek110237 switch (errno) { 26892926Sek110237 case EPERM: 26903237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 26913237Slling dgettext(TEXT_DOMAIN, 26922926Sek110237 "cannot show history for pool '%s'"), 26932926Sek110237 zhp->zpool_name)); 26942926Sek110237 case ENOENT: 26953237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 26962926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 26972926Sek110237 "'%s'"), zhp->zpool_name)); 26983863Sek110237 case ENOTSUP: 26993863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 27003863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 27013863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 27022926Sek110237 default: 27033237Slling return (zpool_standard_error_fmt(hdl, errno, 27042926Sek110237 dgettext(TEXT_DOMAIN, 27052926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 27062926Sek110237 } 27072926Sek110237 } 27082926Sek110237 27092926Sek110237 *len = zc.zc_history_len; 27102926Sek110237 *off = zc.zc_history_offset; 27112926Sek110237 27122926Sek110237 return (0); 27132926Sek110237 } 27142926Sek110237 27152926Sek110237 /* 27162926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 27172926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 27182926Sek110237 * processed as there wasn't a complete record. 27192926Sek110237 */ 27202926Sek110237 static int 27212926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 27222926Sek110237 nvlist_t ***records, uint_t *numrecords) 27232926Sek110237 { 27242926Sek110237 uint64_t reclen; 27252926Sek110237 nvlist_t *nv; 27262926Sek110237 int i; 27272926Sek110237 27282926Sek110237 while (bytes_read > sizeof (reclen)) { 27292926Sek110237 27302926Sek110237 /* get length of packed record (stored as little endian) */ 27312926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 27322926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 27332926Sek110237 27342926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 27352926Sek110237 break; 27362926Sek110237 27372926Sek110237 /* unpack record */ 27382926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 27392926Sek110237 return (ENOMEM); 27402926Sek110237 bytes_read -= sizeof (reclen) + reclen; 27412926Sek110237 buf += sizeof (reclen) + reclen; 27422926Sek110237 27432926Sek110237 /* add record to nvlist array */ 27442926Sek110237 (*numrecords)++; 27452926Sek110237 if (ISP2(*numrecords + 1)) { 27462926Sek110237 *records = realloc(*records, 27472926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 27482926Sek110237 } 27492926Sek110237 (*records)[*numrecords - 1] = nv; 27502926Sek110237 } 27512926Sek110237 27522926Sek110237 *leftover = bytes_read; 27532926Sek110237 return (0); 27542926Sek110237 } 27552926Sek110237 27562926Sek110237 #define HIS_BUF_LEN (128*1024) 27572926Sek110237 27582926Sek110237 /* 27592926Sek110237 * Retrieve the command history of a pool. 27602926Sek110237 */ 27612926Sek110237 int 27622926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 27632926Sek110237 { 27642926Sek110237 char buf[HIS_BUF_LEN]; 27652926Sek110237 uint64_t off = 0; 27662926Sek110237 nvlist_t **records = NULL; 27672926Sek110237 uint_t numrecords = 0; 27682926Sek110237 int err, i; 27692926Sek110237 27702926Sek110237 do { 27712926Sek110237 uint64_t bytes_read = sizeof (buf); 27722926Sek110237 uint64_t leftover; 27732926Sek110237 27742926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 27752926Sek110237 break; 27762926Sek110237 27772926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 27782926Sek110237 if (!bytes_read) 27792926Sek110237 break; 27802926Sek110237 27812926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 27822926Sek110237 &leftover, &records, &numrecords)) != 0) 27832926Sek110237 break; 27842926Sek110237 off -= leftover; 27852926Sek110237 27862926Sek110237 /* CONSTCOND */ 27872926Sek110237 } while (1); 27882926Sek110237 27892926Sek110237 if (!err) { 27902926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 27912926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 27922926Sek110237 records, numrecords) == 0); 27932926Sek110237 } 27942926Sek110237 for (i = 0; i < numrecords; i++) 27952926Sek110237 nvlist_free(records[i]); 27962926Sek110237 free(records); 27972926Sek110237 27982926Sek110237 return (err); 27992926Sek110237 } 28003444Sek110237 28013444Sek110237 void 28023444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 28033444Sek110237 char *pathname, size_t len) 28043444Sek110237 { 28053444Sek110237 zfs_cmd_t zc = { 0 }; 28063444Sek110237 boolean_t mounted = B_FALSE; 28073444Sek110237 char *mntpnt = NULL; 28083444Sek110237 char dsname[MAXNAMELEN]; 28093444Sek110237 28103444Sek110237 if (dsobj == 0) { 28113444Sek110237 /* special case for the MOS */ 28123444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 28133444Sek110237 return; 28143444Sek110237 } 28153444Sek110237 28163444Sek110237 /* get the dataset's name */ 28173444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28183444Sek110237 zc.zc_obj = dsobj; 28193444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 28203444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 28213444Sek110237 /* just write out a path of two object numbers */ 28223444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 28233444Sek110237 dsobj, obj); 28243444Sek110237 return; 28253444Sek110237 } 28263444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 28273444Sek110237 28283444Sek110237 /* find out if the dataset is mounted */ 28293444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 28303444Sek110237 28313444Sek110237 /* get the corrupted object's path */ 28323444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 28333444Sek110237 zc.zc_obj = obj; 28343444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 28353444Sek110237 &zc) == 0) { 28363444Sek110237 if (mounted) { 28373444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 28383444Sek110237 zc.zc_value); 28393444Sek110237 } else { 28403444Sek110237 (void) snprintf(pathname, len, "%s:%s", 28413444Sek110237 dsname, zc.zc_value); 28423444Sek110237 } 28433444Sek110237 } else { 28443444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 28453444Sek110237 } 28463444Sek110237 free(mntpnt); 28473444Sek110237 } 28483912Slling 28494276Staylor /* 28507042Sgw25295 * Read the EFI label from the config, if a label does not exist then 28517042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 28527042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 28537042Sgw25295 * partition. 28547042Sgw25295 */ 28557042Sgw25295 static int 28567042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 28577042Sgw25295 { 28587042Sgw25295 char *path; 28597042Sgw25295 int fd; 28607042Sgw25295 char diskname[MAXPATHLEN]; 28617042Sgw25295 int err = -1; 28627042Sgw25295 28637042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 28647042Sgw25295 return (err); 28657042Sgw25295 28667042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 28677042Sgw25295 strrchr(path, '/')); 28687042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 28697042Sgw25295 struct dk_gpt *vtoc; 28707042Sgw25295 28717042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 28727042Sgw25295 if (sb != NULL) 28737042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 28747042Sgw25295 efi_free(vtoc); 28757042Sgw25295 } 28767042Sgw25295 (void) close(fd); 28777042Sgw25295 } 28787042Sgw25295 return (err); 28797042Sgw25295 } 28807042Sgw25295 28817042Sgw25295 /* 28824276Staylor * determine where a partition starts on a disk in the current 28834276Staylor * configuration 28844276Staylor */ 28854276Staylor static diskaddr_t 28864276Staylor find_start_block(nvlist_t *config) 28874276Staylor { 28884276Staylor nvlist_t **child; 28894276Staylor uint_t c, children; 28904276Staylor diskaddr_t sb = MAXOFFSET_T; 28914276Staylor uint64_t wholedisk; 28924276Staylor 28934276Staylor if (nvlist_lookup_nvlist_array(config, 28944276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 28954276Staylor if (nvlist_lookup_uint64(config, 28964276Staylor ZPOOL_CONFIG_WHOLE_DISK, 28974276Staylor &wholedisk) != 0 || !wholedisk) { 28984276Staylor return (MAXOFFSET_T); 28994276Staylor } 29007042Sgw25295 if (read_efi_label(config, &sb) < 0) 29017042Sgw25295 sb = MAXOFFSET_T; 29024276Staylor return (sb); 29034276Staylor } 29044276Staylor 29054276Staylor for (c = 0; c < children; c++) { 29064276Staylor sb = find_start_block(child[c]); 29074276Staylor if (sb != MAXOFFSET_T) { 29084276Staylor return (sb); 29094276Staylor } 29104276Staylor } 29114276Staylor return (MAXOFFSET_T); 29124276Staylor } 29134276Staylor 29144276Staylor /* 29154276Staylor * Label an individual disk. The name provided is the short name, 29164276Staylor * stripped of any leading /dev path. 29174276Staylor */ 29184276Staylor int 29194276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 29204276Staylor { 29214276Staylor char path[MAXPATHLEN]; 29224276Staylor struct dk_gpt *vtoc; 29234276Staylor int fd; 29244276Staylor size_t resv = EFI_MIN_RESV_SIZE; 29254276Staylor uint64_t slice_size; 29264276Staylor diskaddr_t start_block; 29274276Staylor char errbuf[1024]; 29284276Staylor 29296289Smmusante /* prepare an error message just in case */ 29306289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 29316289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 29326289Smmusante 29334276Staylor if (zhp) { 29344276Staylor nvlist_t *nvroot; 29354276Staylor 29367965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 29377965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29387965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 29397965SGeorge.Wilson@Sun.COM "pools.")); 29407965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 29417965SGeorge.Wilson@Sun.COM } 29427965SGeorge.Wilson@Sun.COM 29434276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 29444276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 29454276Staylor 29464276Staylor if (zhp->zpool_start_block == 0) 29474276Staylor start_block = find_start_block(nvroot); 29484276Staylor else 29494276Staylor start_block = zhp->zpool_start_block; 29504276Staylor zhp->zpool_start_block = start_block; 29514276Staylor } else { 29524276Staylor /* new pool */ 29534276Staylor start_block = NEW_START_BLOCK; 29544276Staylor } 29554276Staylor 29564276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 29574276Staylor BACKUP_SLICE); 29584276Staylor 29594276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 29604276Staylor /* 29614276Staylor * This shouldn't happen. We've long since verified that this 29624276Staylor * is a valid device. 29634276Staylor */ 29646289Smmusante zfs_error_aux(hdl, 29656289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 29664276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 29674276Staylor } 29684276Staylor 29694276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 29704276Staylor /* 29714276Staylor * The only way this can fail is if we run out of memory, or we 29724276Staylor * were unable to read the disk's capacity 29734276Staylor */ 29744276Staylor if (errno == ENOMEM) 29754276Staylor (void) no_memory(hdl); 29764276Staylor 29774276Staylor (void) close(fd); 29786289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29796289Smmusante "unable to read disk capacity"), name); 29804276Staylor 29814276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 29824276Staylor } 29834276Staylor 29844276Staylor slice_size = vtoc->efi_last_u_lba + 1; 29854276Staylor slice_size -= EFI_MIN_RESV_SIZE; 29864276Staylor if (start_block == MAXOFFSET_T) 29874276Staylor start_block = NEW_START_BLOCK; 29884276Staylor slice_size -= start_block; 29894276Staylor 29904276Staylor vtoc->efi_parts[0].p_start = start_block; 29914276Staylor vtoc->efi_parts[0].p_size = slice_size; 29924276Staylor 29934276Staylor /* 29944276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 29954276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 29964276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 29974276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 29984276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 29994276Staylor * can get, in the absence of V_OTHER. 30004276Staylor */ 30014276Staylor vtoc->efi_parts[0].p_tag = V_USR; 30024276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 30034276Staylor 30044276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 30054276Staylor vtoc->efi_parts[8].p_size = resv; 30064276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 30074276Staylor 30084276Staylor if (efi_write(fd, vtoc) != 0) { 30094276Staylor /* 30104276Staylor * Some block drivers (like pcata) may not support EFI 30114276Staylor * GPT labels. Print out a helpful error message dir- 30124276Staylor * ecting the user to manually label the disk and give 30134276Staylor * a specific slice. 30144276Staylor */ 30154276Staylor (void) close(fd); 30164276Staylor efi_free(vtoc); 30174276Staylor 30184276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30196289Smmusante "try using fdisk(1M) and then provide a specific slice")); 30204276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 30214276Staylor } 30224276Staylor 30234276Staylor (void) close(fd); 30244276Staylor efi_free(vtoc); 30254276Staylor return (0); 30264276Staylor } 30276423Sgw25295 30286423Sgw25295 static boolean_t 30296423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 30306423Sgw25295 { 30316423Sgw25295 char *type; 30326423Sgw25295 nvlist_t **child; 30336423Sgw25295 uint_t children, c; 30346423Sgw25295 30356423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 30366423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 30376423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 30386423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 30396423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 30406423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30416423Sgw25295 "vdev type '%s' is not supported"), type); 30426423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 30436423Sgw25295 return (B_FALSE); 30446423Sgw25295 } 30456423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 30466423Sgw25295 &child, &children) == 0) { 30476423Sgw25295 for (c = 0; c < children; c++) { 30486423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 30496423Sgw25295 return (B_FALSE); 30506423Sgw25295 } 30516423Sgw25295 } 30526423Sgw25295 return (B_TRUE); 30536423Sgw25295 } 30546423Sgw25295 30556423Sgw25295 /* 30566423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 30576423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 30586423Sgw25295 */ 30596423Sgw25295 int 30606423Sgw25295 zvol_check_dump_config(char *arg) 30616423Sgw25295 { 30626423Sgw25295 zpool_handle_t *zhp = NULL; 30636423Sgw25295 nvlist_t *config, *nvroot; 30646423Sgw25295 char *p, *volname; 30656423Sgw25295 nvlist_t **top; 30666423Sgw25295 uint_t toplevels; 30676423Sgw25295 libzfs_handle_t *hdl; 30686423Sgw25295 char errbuf[1024]; 30696423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 30706423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 30716423Sgw25295 int ret = 1; 30726423Sgw25295 30736423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 30746423Sgw25295 return (-1); 30756423Sgw25295 } 30766423Sgw25295 30776423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 30786423Sgw25295 "dump is not supported on device '%s'"), arg); 30796423Sgw25295 30806423Sgw25295 if ((hdl = libzfs_init()) == NULL) 30816423Sgw25295 return (1); 30826423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 30836423Sgw25295 30846423Sgw25295 volname = arg + pathlen; 30856423Sgw25295 30866423Sgw25295 /* check the configuration of the pool */ 30876423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 30886423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30896423Sgw25295 "malformed dataset name")); 30906423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 30916423Sgw25295 return (1); 30926423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 30936423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 30946423Sgw25295 "dataset name is too long")); 30956423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 30966423Sgw25295 return (1); 30976423Sgw25295 } else { 30986423Sgw25295 (void) strncpy(poolname, volname, p - volname); 30996423Sgw25295 poolname[p - volname] = '\0'; 31006423Sgw25295 } 31016423Sgw25295 31026423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 31036423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31046423Sgw25295 "could not open pool '%s'"), poolname); 31056423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 31066423Sgw25295 goto out; 31076423Sgw25295 } 31086423Sgw25295 config = zpool_get_config(zhp, NULL); 31096423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 31106423Sgw25295 &nvroot) != 0) { 31116423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31126423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 31136423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 31146423Sgw25295 goto out; 31156423Sgw25295 } 31166423Sgw25295 31176423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 31186423Sgw25295 &top, &toplevels) == 0); 31196423Sgw25295 if (toplevels != 1) { 31206423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31216423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 31226423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 31236423Sgw25295 goto out; 31246423Sgw25295 } 31256423Sgw25295 31266423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 31276423Sgw25295 goto out; 31286423Sgw25295 } 31296423Sgw25295 ret = 0; 31306423Sgw25295 31316423Sgw25295 out: 31326423Sgw25295 if (zhp) 31336423Sgw25295 zpool_close(zhp); 31346423Sgw25295 libzfs_fini(hdl); 31356423Sgw25295 return (ret); 31366423Sgw25295 } 3137