1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51485Slling * Common Development and Distribution License (the "License"). 61485Slling * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 2312296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <ctype.h> 27789Sahrens #include <errno.h> 28789Sahrens #include <devid.h> 29789Sahrens #include <fcntl.h> 30789Sahrens #include <libintl.h> 31789Sahrens #include <stdio.h> 32789Sahrens #include <stdlib.h> 333126Sahl #include <strings.h> 34789Sahrens #include <unistd.h> 354276Staylor #include <sys/efi_partition.h> 364276Staylor #include <sys/vtoc.h> 37789Sahrens #include <sys/zfs_ioctl.h> 389816SGeorge.Wilson@Sun.COM #include <dlfcn.h> 39789Sahrens 40789Sahrens #include "zfs_namecheck.h" 413912Slling #include "zfs_prop.h" 42789Sahrens #include "libzfs_impl.h" 4310921STim.Haley@Sun.COM #include "zfs_comutil.h" 44789Sahrens 457042Sgw25295 static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 465094Slling 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")); 19011422SMark.Musante@Sun.COM else if (aux == VDEV_AUX_SPLIT_POOL) 19111422SMark.Musante@Sun.COM return (gettext("SPLIT")); 1925094Slling else 1935094Slling return (gettext("UNAVAIL")); 1945094Slling case VDEV_STATE_FAULTED: 1955094Slling return (gettext("FAULTED")); 1965094Slling case VDEV_STATE_DEGRADED: 1975094Slling return (gettext("DEGRADED")); 1985094Slling case VDEV_STATE_HEALTHY: 1995094Slling return (gettext("ONLINE")); 2005094Slling } 2015094Slling 2025094Slling return (gettext("UNKNOWN")); 2035094Slling } 2045094Slling 2055094Slling /* 2065094Slling * Get a zpool property value for 'prop' and return the value in 2075094Slling * a pre-allocated buffer. 2085094Slling */ 2095094Slling int 2105094Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 2115094Slling zprop_source_t *srctype) 2125094Slling { 2135094Slling uint64_t intval; 2145094Slling const char *strval; 2155094Slling zprop_source_t src = ZPROP_SRC_NONE; 2165094Slling nvlist_t *nvroot; 2175094Slling vdev_stat_t *vs; 2185094Slling uint_t vsc; 2195094Slling 2205094Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 2218525SEric.Schrock@Sun.COM switch (prop) { 2228525SEric.Schrock@Sun.COM case ZPOOL_PROP_NAME: 2235094Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 2248525SEric.Schrock@Sun.COM break; 2258525SEric.Schrock@Sun.COM 2268525SEric.Schrock@Sun.COM case ZPOOL_PROP_HEALTH: 2275094Slling (void) strlcpy(buf, "FAULTED", len); 2288525SEric.Schrock@Sun.COM break; 2298525SEric.Schrock@Sun.COM 2308525SEric.Schrock@Sun.COM case ZPOOL_PROP_GUID: 2318525SEric.Schrock@Sun.COM intval = zpool_get_prop_int(zhp, prop, &src); 2328525SEric.Schrock@Sun.COM (void) snprintf(buf, len, "%llu", intval); 2338525SEric.Schrock@Sun.COM break; 2348525SEric.Schrock@Sun.COM 2358525SEric.Schrock@Sun.COM case ZPOOL_PROP_ALTROOT: 2368525SEric.Schrock@Sun.COM case ZPOOL_PROP_CACHEFILE: 2378525SEric.Schrock@Sun.COM if (zhp->zpool_props != NULL || 2388525SEric.Schrock@Sun.COM zpool_get_all_props(zhp) == 0) { 2398525SEric.Schrock@Sun.COM (void) strlcpy(buf, 2408525SEric.Schrock@Sun.COM zpool_get_prop_string(zhp, prop, &src), 2418525SEric.Schrock@Sun.COM len); 2428525SEric.Schrock@Sun.COM if (srctype != NULL) 2438525SEric.Schrock@Sun.COM *srctype = src; 2448525SEric.Schrock@Sun.COM return (0); 2458525SEric.Schrock@Sun.COM } 2468525SEric.Schrock@Sun.COM /* FALLTHROUGH */ 2478525SEric.Schrock@Sun.COM default: 2485094Slling (void) strlcpy(buf, "-", len); 2498525SEric.Schrock@Sun.COM break; 2508525SEric.Schrock@Sun.COM } 2518525SEric.Schrock@Sun.COM 2528525SEric.Schrock@Sun.COM if (srctype != NULL) 2538525SEric.Schrock@Sun.COM *srctype = src; 2545094Slling return (0); 2555094Slling } 2565094Slling 2575094Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 2585094Slling prop != ZPOOL_PROP_NAME) 2595094Slling return (-1); 2605094Slling 2615094Slling switch (zpool_prop_get_type(prop)) { 2625094Slling case PROP_TYPE_STRING: 2635094Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 2645094Slling len); 2655094Slling break; 2665094Slling 2675094Slling case PROP_TYPE_NUMBER: 2685094Slling intval = zpool_get_prop_int(zhp, prop, &src); 2695094Slling 2705094Slling switch (prop) { 2715094Slling case ZPOOL_PROP_SIZE: 27210956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_ALLOCATED: 27310956SGeorge.Wilson@Sun.COM case ZPOOL_PROP_FREE: 2745094Slling (void) zfs_nicenum(intval, buf, len); 2755094Slling break; 2765094Slling 2775094Slling case ZPOOL_PROP_CAPACITY: 2785094Slling (void) snprintf(buf, len, "%llu%%", 2795094Slling (u_longlong_t)intval); 2805094Slling break; 2815094Slling 28210922SJeff.Bonwick@Sun.COM case ZPOOL_PROP_DEDUPRATIO: 28310922SJeff.Bonwick@Sun.COM (void) snprintf(buf, len, "%llu.%02llux", 28410922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval / 100), 28510922SJeff.Bonwick@Sun.COM (u_longlong_t)(intval % 100)); 28610922SJeff.Bonwick@Sun.COM break; 28710922SJeff.Bonwick@Sun.COM 2885094Slling case ZPOOL_PROP_HEALTH: 2895094Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 2905094Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 2915094Slling verify(nvlist_lookup_uint64_array(nvroot, 29212296SLin.Ling@Sun.COM ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) 29312296SLin.Ling@Sun.COM == 0); 2945094Slling 2955094Slling (void) strlcpy(buf, zpool_state_to_name(intval, 2965094Slling vs->vs_aux), len); 2975094Slling break; 2985094Slling default: 2995094Slling (void) snprintf(buf, len, "%llu", intval); 3005094Slling } 3015094Slling break; 3025094Slling 3035094Slling case PROP_TYPE_INDEX: 3045094Slling intval = zpool_get_prop_int(zhp, prop, &src); 3055094Slling if (zpool_prop_index_to_string(prop, intval, &strval) 3065094Slling != 0) 3075094Slling return (-1); 3085094Slling (void) strlcpy(buf, strval, len); 3095094Slling break; 3105094Slling 3115094Slling default: 3125094Slling abort(); 3135094Slling } 3145094Slling 3155094Slling if (srctype) 3165094Slling *srctype = src; 3175094Slling 3185094Slling return (0); 3195094Slling } 3205094Slling 3215094Slling /* 3225094Slling * Check if the bootfs name has the same pool name as it is set to. 3235094Slling * Assuming bootfs is a valid dataset name. 3245094Slling */ 3255094Slling static boolean_t 3265094Slling bootfs_name_valid(const char *pool, char *bootfs) 3275094Slling { 3285094Slling int len = strlen(pool); 3295094Slling 3307300SEric.Taylor@Sun.COM if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 3315094Slling return (B_FALSE); 3325094Slling 3335094Slling if (strncmp(pool, bootfs, len) == 0 && 3345094Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 3355094Slling return (B_TRUE); 3365094Slling 3375094Slling return (B_FALSE); 3385094Slling } 3395094Slling 3405094Slling /* 3417042Sgw25295 * Inspect the configuration to determine if any of the devices contain 3427042Sgw25295 * an EFI label. 3437042Sgw25295 */ 3447042Sgw25295 static boolean_t 3457042Sgw25295 pool_uses_efi(nvlist_t *config) 3467042Sgw25295 { 3477042Sgw25295 nvlist_t **child; 3487042Sgw25295 uint_t c, children; 3497042Sgw25295 3507042Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3517042Sgw25295 &child, &children) != 0) 3527042Sgw25295 return (read_efi_label(config, NULL) >= 0); 3537042Sgw25295 3547042Sgw25295 for (c = 0; c < children; c++) { 3557042Sgw25295 if (pool_uses_efi(child[c])) 3567042Sgw25295 return (B_TRUE); 3577042Sgw25295 } 3587042Sgw25295 return (B_FALSE); 3597042Sgw25295 } 3607042Sgw25295 3617965SGeorge.Wilson@Sun.COM static boolean_t 3627965SGeorge.Wilson@Sun.COM pool_is_bootable(zpool_handle_t *zhp) 3637965SGeorge.Wilson@Sun.COM { 3647965SGeorge.Wilson@Sun.COM char bootfs[ZPOOL_MAXNAMELEN]; 3657965SGeorge.Wilson@Sun.COM 3667965SGeorge.Wilson@Sun.COM return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 3677965SGeorge.Wilson@Sun.COM sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 3687965SGeorge.Wilson@Sun.COM sizeof (bootfs)) != 0); 3697965SGeorge.Wilson@Sun.COM } 3707965SGeorge.Wilson@Sun.COM 3717965SGeorge.Wilson@Sun.COM 3727042Sgw25295 /* 3735094Slling * Given an nvlist of zpool properties to be set, validate that they are 3745094Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 3755094Slling * specified as strings. 3765094Slling */ 3775094Slling static nvlist_t * 3787184Stimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 3795094Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 3805094Slling { 3815094Slling nvpair_t *elem; 3825094Slling nvlist_t *retprops; 3835094Slling zpool_prop_t prop; 3845094Slling char *strval; 3855094Slling uint64_t intval; 3865363Seschrock char *slash; 3875363Seschrock struct stat64 statbuf; 3887042Sgw25295 zpool_handle_t *zhp; 3897042Sgw25295 nvlist_t *nvroot; 3905094Slling 3915094Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 3925094Slling (void) no_memory(hdl); 3935094Slling return (NULL); 3945094Slling } 3955094Slling 3965094Slling elem = NULL; 3975094Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 3985094Slling const char *propname = nvpair_name(elem); 3995094Slling 4005094Slling /* 4015094Slling * Make sure this property is valid and applies to this type. 4025094Slling */ 4035094Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 4045094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4055094Slling "invalid property '%s'"), propname); 4065094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4075094Slling goto error; 4085094Slling } 4095094Slling 4105094Slling if (zpool_prop_readonly(prop)) { 4115094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4125094Slling "is readonly"), propname); 4135094Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 4145094Slling goto error; 4155094Slling } 4165094Slling 4175094Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 4185094Slling &strval, &intval, errbuf) != 0) 4195094Slling goto error; 4205094Slling 4215094Slling /* 4225094Slling * Perform additional checking for specific properties. 4235094Slling */ 4245094Slling switch (prop) { 4255094Slling case ZPOOL_PROP_VERSION: 4265094Slling if (intval < version || intval > SPA_VERSION) { 4275094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4285094Slling "property '%s' number %d is invalid."), 4295094Slling propname, intval); 4305094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4315094Slling goto error; 4325094Slling } 4335094Slling break; 4345094Slling 4355094Slling case ZPOOL_PROP_BOOTFS: 4365094Slling if (create_or_import) { 4375094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4385094Slling "property '%s' cannot be set at creation " 4395094Slling "or import time"), propname); 4405094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4415094Slling goto error; 4425094Slling } 4435094Slling 4445094Slling if (version < SPA_VERSION_BOOTFS) { 4455094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4465094Slling "pool must be upgraded to support " 4475094Slling "'%s' property"), propname); 4485094Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 4495094Slling goto error; 4505094Slling } 4515094Slling 4525094Slling /* 4535094Slling * bootfs property value has to be a dataset name and 4545094Slling * the dataset has to be in the same pool as it sets to. 4555094Slling */ 4565094Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 4575094Slling strval)) { 4585094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 4595094Slling "is an invalid name"), strval); 4605094Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4615094Slling goto error; 4625094Slling } 4637042Sgw25295 4647042Sgw25295 if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 4657042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4667042Sgw25295 "could not open pool '%s'"), poolname); 4677042Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4687042Sgw25295 goto error; 4697042Sgw25295 } 4707042Sgw25295 verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 4717042Sgw25295 ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 4727042Sgw25295 4737042Sgw25295 /* 4747042Sgw25295 * bootfs property cannot be set on a disk which has 4757042Sgw25295 * been EFI labeled. 4767042Sgw25295 */ 4777042Sgw25295 if (pool_uses_efi(nvroot)) { 4787042Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4797042Sgw25295 "property '%s' not supported on " 4807042Sgw25295 "EFI labeled devices"), propname); 4817042Sgw25295 (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 4827042Sgw25295 zpool_close(zhp); 4837042Sgw25295 goto error; 4847042Sgw25295 } 4857042Sgw25295 zpool_close(zhp); 4865094Slling break; 4875094Slling 4885094Slling case ZPOOL_PROP_ALTROOT: 4895094Slling if (!create_or_import) { 4905094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4915094Slling "property '%s' can only be set during pool " 4925094Slling "creation or import"), propname); 4935094Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 4945094Slling goto error; 4955094Slling } 4965094Slling 4975094Slling if (strval[0] != '/') { 4985094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4995094Slling "bad alternate root '%s'"), strval); 5005094Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5015094Slling goto error; 5025094Slling } 5035094Slling break; 5045363Seschrock 5055363Seschrock case ZPOOL_PROP_CACHEFILE: 5065363Seschrock if (strval[0] == '\0') 5075363Seschrock break; 5085363Seschrock 5095363Seschrock if (strcmp(strval, "none") == 0) 5105363Seschrock break; 5115363Seschrock 5125363Seschrock if (strval[0] != '/') { 5135363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5145363Seschrock "property '%s' must be empty, an " 5155363Seschrock "absolute path, or 'none'"), propname); 5165363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5175363Seschrock goto error; 5185363Seschrock } 5195363Seschrock 5205363Seschrock slash = strrchr(strval, '/'); 5215363Seschrock 5225363Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5235363Seschrock strcmp(slash, "/..") == 0) { 5245363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5255363Seschrock "'%s' is not a valid file"), strval); 5265363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5275363Seschrock goto error; 5285363Seschrock } 5295363Seschrock 5305363Seschrock *slash = '\0'; 5315363Seschrock 5325621Seschrock if (strval[0] != '\0' && 5335621Seschrock (stat64(strval, &statbuf) != 0 || 5345621Seschrock !S_ISDIR(statbuf.st_mode))) { 5355363Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5365363Seschrock "'%s' is not a valid directory"), 5375363Seschrock strval); 5385363Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5395363Seschrock goto error; 5405363Seschrock } 5415363Seschrock 5425363Seschrock *slash = '/'; 5435363Seschrock break; 5445094Slling } 5455094Slling } 5465094Slling 5475094Slling return (retprops); 5485094Slling error: 5495094Slling nvlist_free(retprops); 5505094Slling return (NULL); 5515094Slling } 5525094Slling 5535094Slling /* 5545094Slling * Set zpool property : propname=propval. 5555094Slling */ 5565094Slling int 5575094Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 5585094Slling { 5595094Slling zfs_cmd_t zc = { 0 }; 5605094Slling int ret = -1; 5615094Slling char errbuf[1024]; 5625094Slling nvlist_t *nvl = NULL; 5635094Slling nvlist_t *realprops; 5645094Slling uint64_t version; 5655094Slling 5665094Slling (void) snprintf(errbuf, sizeof (errbuf), 5675094Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 5685094Slling zhp->zpool_name); 5695094Slling 5705094Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 5715094Slling return (no_memory(zhp->zpool_hdl)); 5725094Slling 5735094Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 5745094Slling nvlist_free(nvl); 5755094Slling return (no_memory(zhp->zpool_hdl)); 5765094Slling } 5775094Slling 5785094Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5797184Stimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 5805094Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 5815094Slling nvlist_free(nvl); 5825094Slling return (-1); 5835094Slling } 5845094Slling 5855094Slling nvlist_free(nvl); 5865094Slling nvl = realprops; 5875094Slling 5885094Slling /* 5895094Slling * Execute the corresponding ioctl() to set this property. 5905094Slling */ 5915094Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 5925094Slling 5935094Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 5945094Slling nvlist_free(nvl); 5955094Slling return (-1); 5965094Slling } 5975094Slling 5985094Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 5995094Slling 6005094Slling zcmd_free_nvlists(&zc); 6015094Slling nvlist_free(nvl); 6025094Slling 6035094Slling if (ret) 6045094Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 6055094Slling else 6065094Slling (void) zpool_props_refresh(zhp); 6075094Slling 6085094Slling return (ret); 6095094Slling } 6105094Slling 6115094Slling int 6125094Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 6135094Slling { 6145094Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 6155094Slling zprop_list_t *entry; 6165094Slling char buf[ZFS_MAXPROPLEN]; 6175094Slling 6185094Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 6195094Slling return (-1); 6205094Slling 6215094Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 6225094Slling 6235094Slling if (entry->pl_fixed) 6245094Slling continue; 6255094Slling 6265094Slling if (entry->pl_prop != ZPROP_INVAL && 6275094Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 6285094Slling NULL) == 0) { 6295094Slling if (strlen(buf) > entry->pl_width) 6305094Slling entry->pl_width = strlen(buf); 6315094Slling } 6325094Slling } 6335094Slling 6345094Slling return (0); 6355094Slling } 6365094Slling 6375094Slling 638789Sahrens /* 6399816SGeorge.Wilson@Sun.COM * Don't start the slice at the default block of 34; many storage 6409816SGeorge.Wilson@Sun.COM * devices will use a stripe width of 128k, so start there instead. 6419816SGeorge.Wilson@Sun.COM */ 6429816SGeorge.Wilson@Sun.COM #define NEW_START_BLOCK 256 6439816SGeorge.Wilson@Sun.COM 6449816SGeorge.Wilson@Sun.COM /* 645789Sahrens * Validate the given pool name, optionally putting an extended error message in 646789Sahrens * 'buf'. 647789Sahrens */ 6486423Sgw25295 boolean_t 6492082Seschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 650789Sahrens { 651789Sahrens namecheck_err_t why; 652789Sahrens char what; 6531773Seschrock int ret; 654789Sahrens 6551773Seschrock ret = pool_namecheck(pool, &why, &what); 6561773Seschrock 6571773Seschrock /* 6581773Seschrock * The rules for reserved pool names were extended at a later point. 6591773Seschrock * But we need to support users with existing pools that may now be 6601773Seschrock * invalid. So we only check for this expanded set of names during a 6611773Seschrock * create (or import), and only in userland. 6621773Seschrock */ 6631773Seschrock if (ret == 0 && !isopen && 6641773Seschrock (strncmp(pool, "mirror", 6) == 0 || 6651773Seschrock strncmp(pool, "raidz", 5) == 0 || 6664527Sperrin strncmp(pool, "spare", 5) == 0 || 6674527Sperrin strcmp(pool, "log") == 0)) { 6686423Sgw25295 if (hdl != NULL) 6696423Sgw25295 zfs_error_aux(hdl, 6706423Sgw25295 dgettext(TEXT_DOMAIN, "name is reserved")); 6712082Seschrock return (B_FALSE); 6721773Seschrock } 6731773Seschrock 6741773Seschrock 6751773Seschrock if (ret != 0) { 6762082Seschrock if (hdl != NULL) { 677789Sahrens switch (why) { 6781003Slling case NAME_ERR_TOOLONG: 6792082Seschrock zfs_error_aux(hdl, 6801003Slling dgettext(TEXT_DOMAIN, "name is too long")); 6811003Slling break; 6821003Slling 683789Sahrens case NAME_ERR_INVALCHAR: 6842082Seschrock zfs_error_aux(hdl, 685789Sahrens dgettext(TEXT_DOMAIN, "invalid character " 686789Sahrens "'%c' in pool name"), what); 687789Sahrens break; 688789Sahrens 689789Sahrens case NAME_ERR_NOLETTER: 6902082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6912082Seschrock "name must begin with a letter")); 692789Sahrens break; 693789Sahrens 694789Sahrens case NAME_ERR_RESERVED: 6952082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6962082Seschrock "name is reserved")); 697789Sahrens break; 698789Sahrens 699789Sahrens case NAME_ERR_DISKLIKE: 7002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7012082Seschrock "pool name is reserved")); 702789Sahrens break; 7032856Snd150628 7042856Snd150628 case NAME_ERR_LEADING_SLASH: 7052856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7062856Snd150628 "leading slash in name")); 7072856Snd150628 break; 7082856Snd150628 7092856Snd150628 case NAME_ERR_EMPTY_COMPONENT: 7102856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7112856Snd150628 "empty component in name")); 7122856Snd150628 break; 7132856Snd150628 7142856Snd150628 case NAME_ERR_TRAILING_SLASH: 7152856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7162856Snd150628 "trailing slash in name")); 7172856Snd150628 break; 7182856Snd150628 7192856Snd150628 case NAME_ERR_MULTIPLE_AT: 7202856Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7212856Snd150628 "multiple '@' delimiters in name")); 7222856Snd150628 break; 7232856Snd150628 724789Sahrens } 725789Sahrens } 7262082Seschrock return (B_FALSE); 727789Sahrens } 728789Sahrens 7292082Seschrock return (B_TRUE); 730789Sahrens } 731789Sahrens 732789Sahrens /* 733789Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 734789Sahrens * state. 735789Sahrens */ 736789Sahrens zpool_handle_t * 7372082Seschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 738789Sahrens { 739789Sahrens zpool_handle_t *zhp; 7402142Seschrock boolean_t missing; 741789Sahrens 742789Sahrens /* 743789Sahrens * Make sure the pool name is valid. 744789Sahrens */ 7452082Seschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 7463237Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 7472082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 7482082Seschrock pool); 749789Sahrens return (NULL); 750789Sahrens } 751789Sahrens 7522082Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7532082Seschrock return (NULL); 754789Sahrens 7552082Seschrock zhp->zpool_hdl = hdl; 756789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 757789Sahrens 7582142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7592142Seschrock zpool_close(zhp); 7602142Seschrock return (NULL); 7612142Seschrock } 7622142Seschrock 7632142Seschrock if (missing) { 7645094Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 7653237Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 7665094Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 7672142Seschrock zpool_close(zhp); 7682142Seschrock return (NULL); 769789Sahrens } 770789Sahrens 771789Sahrens return (zhp); 772789Sahrens } 773789Sahrens 774789Sahrens /* 775789Sahrens * Like the above, but silent on error. Used when iterating over pools (because 776789Sahrens * the configuration cache may be out of date). 777789Sahrens */ 7782142Seschrock int 7792142Seschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 780789Sahrens { 781789Sahrens zpool_handle_t *zhp; 7822142Seschrock boolean_t missing; 783789Sahrens 7842142Seschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 7852142Seschrock return (-1); 786789Sahrens 7872082Seschrock zhp->zpool_hdl = hdl; 788789Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 789789Sahrens 7902142Seschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 7912142Seschrock zpool_close(zhp); 7922142Seschrock return (-1); 793789Sahrens } 794789Sahrens 7952142Seschrock if (missing) { 7962142Seschrock zpool_close(zhp); 7972142Seschrock *ret = NULL; 7982142Seschrock return (0); 7992142Seschrock } 8002142Seschrock 8012142Seschrock *ret = zhp; 8022142Seschrock return (0); 803789Sahrens } 804789Sahrens 805789Sahrens /* 806789Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 807789Sahrens * state. 808789Sahrens */ 809789Sahrens zpool_handle_t * 8102082Seschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 811789Sahrens { 812789Sahrens zpool_handle_t *zhp; 813789Sahrens 8142082Seschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 815789Sahrens return (NULL); 816789Sahrens 817789Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 8183237Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 8192082Seschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 820789Sahrens zpool_close(zhp); 821789Sahrens return (NULL); 822789Sahrens } 823789Sahrens 824789Sahrens return (zhp); 825789Sahrens } 826789Sahrens 827789Sahrens /* 828789Sahrens * Close the handle. Simply frees the memory associated with the handle. 829789Sahrens */ 830789Sahrens void 831789Sahrens zpool_close(zpool_handle_t *zhp) 832789Sahrens { 833789Sahrens if (zhp->zpool_config) 834789Sahrens nvlist_free(zhp->zpool_config); 835952Seschrock if (zhp->zpool_old_config) 836952Seschrock nvlist_free(zhp->zpool_old_config); 8373912Slling if (zhp->zpool_props) 8383912Slling nvlist_free(zhp->zpool_props); 839789Sahrens free(zhp); 840789Sahrens } 841789Sahrens 842789Sahrens /* 843789Sahrens * Return the name of the pool. 844789Sahrens */ 845789Sahrens const char * 846789Sahrens zpool_get_name(zpool_handle_t *zhp) 847789Sahrens { 848789Sahrens return (zhp->zpool_name); 849789Sahrens } 850789Sahrens 851789Sahrens 852789Sahrens /* 853789Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 854789Sahrens */ 855789Sahrens int 856789Sahrens zpool_get_state(zpool_handle_t *zhp) 857789Sahrens { 858789Sahrens return (zhp->zpool_state); 859789Sahrens } 860789Sahrens 861789Sahrens /* 862789Sahrens * Create the named pool, using the provided vdev list. It is assumed 863789Sahrens * that the consumer has already validated the contents of the nvlist, so we 864789Sahrens * don't have to worry about error semantics. 865789Sahrens */ 866789Sahrens int 8672082Seschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8687184Stimh nvlist_t *props, nvlist_t *fsprops) 869789Sahrens { 870789Sahrens zfs_cmd_t zc = { 0 }; 8717184Stimh nvlist_t *zc_fsprops = NULL; 8727184Stimh nvlist_t *zc_props = NULL; 8732082Seschrock char msg[1024]; 8745094Slling char *altroot; 8757184Stimh int ret = -1; 8762082Seschrock 8772082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 8782082Seschrock "cannot create '%s'"), pool); 879789Sahrens 8802082Seschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 8812082Seschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 8822082Seschrock 8835320Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 8845320Slling return (-1); 8855320Slling 8867184Stimh if (props) { 8877184Stimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8887184Stimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8897184Stimh goto create_failed; 8907184Stimh } 8915320Slling } 892789Sahrens 8937184Stimh if (fsprops) { 8947184Stimh uint64_t zoned; 8957184Stimh char *zonestr; 8967184Stimh 8977184Stimh zoned = ((nvlist_lookup_string(fsprops, 8987184Stimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8997184Stimh strcmp(zonestr, "on") == 0); 9007184Stimh 9017184Stimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9027184Stimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9037184Stimh goto create_failed; 9047184Stimh } 9057184Stimh if (!zc_props && 9067184Stimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9077184Stimh goto create_failed; 9087184Stimh } 9097184Stimh if (nvlist_add_nvlist(zc_props, 9107184Stimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9117184Stimh goto create_failed; 9127184Stimh } 9137184Stimh } 9147184Stimh 9157184Stimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9167184Stimh goto create_failed; 9177184Stimh 918789Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 919789Sahrens 9207184Stimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 9215320Slling 9222676Seschrock zcmd_free_nvlists(&zc); 9237184Stimh nvlist_free(zc_props); 9247184Stimh nvlist_free(zc_fsprops); 9252082Seschrock 926789Sahrens switch (errno) { 927789Sahrens case EBUSY: 928789Sahrens /* 929789Sahrens * This can happen if the user has specified the same 930789Sahrens * device multiple times. We can't reliably detect this 931789Sahrens * until we try to add it and see we already have a 932789Sahrens * label. 933789Sahrens */ 9342082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9352082Seschrock "one or more vdevs refer to the same device")); 9362082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 937789Sahrens 938789Sahrens case EOVERFLOW: 939789Sahrens /* 9402082Seschrock * This occurs when one of the devices is below 941789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 942789Sahrens * device was the problem device since there's no 943789Sahrens * reliable way to determine device size from userland. 944789Sahrens */ 945789Sahrens { 946789Sahrens char buf[64]; 947789Sahrens 948789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 949789Sahrens 9502082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9512082Seschrock "one or more devices is less than the " 9522082Seschrock "minimum size (%s)"), buf); 953789Sahrens } 9542082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 955789Sahrens 956789Sahrens case ENOSPC: 9572082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9582082Seschrock "one or more devices is out of space")); 9592082Seschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 960789Sahrens 9615450Sbrendan case ENOTBLK: 9625450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9635450Sbrendan "cache device must be a disk or disk slice")); 9645450Sbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 9655450Sbrendan 966789Sahrens default: 9672082Seschrock return (zpool_standard_error(hdl, errno, msg)); 968789Sahrens } 969789Sahrens } 970789Sahrens 971789Sahrens /* 972789Sahrens * If this is an alternate root pool, then we automatically set the 9732676Seschrock * mountpoint of the root dataset to be '/'. 974789Sahrens */ 9755094Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 9765094Slling &altroot) == 0) { 977789Sahrens zfs_handle_t *zhp; 978789Sahrens 9795094Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 9802676Seschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 9812676Seschrock "/") == 0); 982789Sahrens 983789Sahrens zfs_close(zhp); 984789Sahrens } 985789Sahrens 9867184Stimh create_failed: 9875320Slling zcmd_free_nvlists(&zc); 9887184Stimh nvlist_free(zc_props); 9897184Stimh nvlist_free(zc_fsprops); 9907184Stimh return (ret); 991789Sahrens } 992789Sahrens 993789Sahrens /* 994789Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 995789Sahrens * datasets left in the pool. 996789Sahrens */ 997789Sahrens int 998789Sahrens zpool_destroy(zpool_handle_t *zhp) 999789Sahrens { 1000789Sahrens zfs_cmd_t zc = { 0 }; 1001789Sahrens zfs_handle_t *zfp = NULL; 10022082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10032082Seschrock char msg[1024]; 1004789Sahrens 1005789Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 10062082Seschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 10072082Seschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1008789Sahrens return (-1); 1009789Sahrens 1010789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1011789Sahrens 10124543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 10132082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10142082Seschrock "cannot destroy '%s'"), zhp->zpool_name); 1015789Sahrens 10162082Seschrock if (errno == EROFS) { 10172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10182082Seschrock "one or more devices is read only")); 10192082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 10202082Seschrock } else { 10212082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1022789Sahrens } 1023789Sahrens 1024789Sahrens if (zfp) 1025789Sahrens zfs_close(zfp); 1026789Sahrens return (-1); 1027789Sahrens } 1028789Sahrens 1029789Sahrens if (zfp) { 1030789Sahrens remove_mountpoint(zfp); 1031789Sahrens zfs_close(zfp); 1032789Sahrens } 1033789Sahrens 1034789Sahrens return (0); 1035789Sahrens } 1036789Sahrens 1037789Sahrens /* 1038789Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1039789Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1040789Sahrens */ 1041789Sahrens int 1042789Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1043789Sahrens { 10442676Seschrock zfs_cmd_t zc = { 0 }; 10452082Seschrock int ret; 10462082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10472082Seschrock char msg[1024]; 10485450Sbrendan nvlist_t **spares, **l2cache; 10495450Sbrendan uint_t nspares, nl2cache; 10502082Seschrock 10512082Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 10522082Seschrock "cannot add to '%s'"), zhp->zpool_name); 10532082Seschrock 10545450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10555450Sbrendan SPA_VERSION_SPARES && 10562082Seschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 10572082Seschrock &spares, &nspares) == 0) { 10582082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10592082Seschrock "upgraded to add hot spares")); 10602082Seschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10612082Seschrock } 1062789Sahrens 10637965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 10647965SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 10657965SGeorge.Wilson@Sun.COM uint64_t s; 10667965SGeorge.Wilson@Sun.COM 10677965SGeorge.Wilson@Sun.COM for (s = 0; s < nspares; s++) { 10687965SGeorge.Wilson@Sun.COM char *path; 10697965SGeorge.Wilson@Sun.COM 10707965SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 10717965SGeorge.Wilson@Sun.COM &path) == 0 && pool_uses_efi(spares[s])) { 10727965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10737965SGeorge.Wilson@Sun.COM "device '%s' contains an EFI label and " 10747965SGeorge.Wilson@Sun.COM "cannot be used on root pools."), 107510594SGeorge.Wilson@Sun.COM zpool_vdev_name(hdl, NULL, spares[s], 107610594SGeorge.Wilson@Sun.COM B_FALSE)); 10777965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 10787965SGeorge.Wilson@Sun.COM } 10797965SGeorge.Wilson@Sun.COM } 10807965SGeorge.Wilson@Sun.COM } 10817965SGeorge.Wilson@Sun.COM 10825450Sbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 10835450Sbrendan SPA_VERSION_L2CACHE && 10845450Sbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 10855450Sbrendan &l2cache, &nl2cache) == 0) { 10865450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 10875450Sbrendan "upgraded to add cache devices")); 10885450Sbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 10895450Sbrendan } 10905450Sbrendan 10915094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 10922082Seschrock return (-1); 1093789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1094789Sahrens 10954543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1096789Sahrens switch (errno) { 1097789Sahrens case EBUSY: 1098789Sahrens /* 1099789Sahrens * This can happen if the user has specified the same 1100789Sahrens * device multiple times. We can't reliably detect this 1101789Sahrens * until we try to add it and see we already have a 1102789Sahrens * label. 1103789Sahrens */ 11042082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11052082Seschrock "one or more vdevs refer to the same device")); 11062082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1107789Sahrens break; 1108789Sahrens 1109789Sahrens case EOVERFLOW: 1110789Sahrens /* 1111789Sahrens * This occurrs when one of the devices is below 1112789Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1113789Sahrens * device was the problem device since there's no 1114789Sahrens * reliable way to determine device size from userland. 1115789Sahrens */ 1116789Sahrens { 1117789Sahrens char buf[64]; 1118789Sahrens 1119789Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1120789Sahrens 11212082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11222082Seschrock "device is less than the minimum " 11232082Seschrock "size (%s)"), buf); 1124789Sahrens } 11252082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 11262082Seschrock break; 11272082Seschrock 11282082Seschrock case ENOTSUP: 11292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11304527Sperrin "pool must be upgraded to add these vdevs")); 11312082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1132789Sahrens break; 1133789Sahrens 11343912Slling case EDOM: 11353912Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11364527Sperrin "root pool can not have multiple vdevs" 11374527Sperrin " or separate logs")); 11383912Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 11393912Slling break; 11403912Slling 11415450Sbrendan case ENOTBLK: 11425450Sbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11435450Sbrendan "cache device must be a disk or disk slice")); 11445450Sbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 11455450Sbrendan break; 11465450Sbrendan 1147789Sahrens default: 11482082Seschrock (void) zpool_standard_error(hdl, errno, msg); 1149789Sahrens } 1150789Sahrens 11512082Seschrock ret = -1; 11522082Seschrock } else { 11532082Seschrock ret = 0; 1154789Sahrens } 1155789Sahrens 11562676Seschrock zcmd_free_nvlists(&zc); 1157789Sahrens 11582082Seschrock return (ret); 1159789Sahrens } 1160789Sahrens 1161789Sahrens /* 1162789Sahrens * Exports the pool from the system. The caller must ensure that there are no 1163789Sahrens * mounted datasets in the pool. 1164789Sahrens */ 1165789Sahrens int 11668211SGeorge.Wilson@Sun.COM zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1167789Sahrens { 1168789Sahrens zfs_cmd_t zc = { 0 }; 11697214Slling char msg[1024]; 1170789Sahrens 11717214Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 11727214Slling "cannot export '%s'"), zhp->zpool_name); 11737214Slling 1174789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 11757214Slling zc.zc_cookie = force; 11768211SGeorge.Wilson@Sun.COM zc.zc_guid = hardforce; 11777214Slling 11787214Slling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 11797214Slling switch (errno) { 11807214Slling case EXDEV: 11817214Slling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 11827214Slling "use '-f' to override the following errors:\n" 11837214Slling "'%s' has an active shared spare which could be" 11847214Slling " used by other pools once '%s' is exported."), 11857214Slling zhp->zpool_name, zhp->zpool_name); 11867214Slling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 11877214Slling msg)); 11887214Slling default: 11897214Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 11907214Slling msg)); 11917214Slling } 11927214Slling } 11937214Slling 1194789Sahrens return (0); 1195789Sahrens } 1196789Sahrens 11978211SGeorge.Wilson@Sun.COM int 11988211SGeorge.Wilson@Sun.COM zpool_export(zpool_handle_t *zhp, boolean_t force) 11998211SGeorge.Wilson@Sun.COM { 12008211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, force, B_FALSE)); 12018211SGeorge.Wilson@Sun.COM } 12028211SGeorge.Wilson@Sun.COM 12038211SGeorge.Wilson@Sun.COM int 12048211SGeorge.Wilson@Sun.COM zpool_export_force(zpool_handle_t *zhp) 12058211SGeorge.Wilson@Sun.COM { 12068211SGeorge.Wilson@Sun.COM return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 12078211SGeorge.Wilson@Sun.COM } 12088211SGeorge.Wilson@Sun.COM 120910921STim.Haley@Sun.COM static void 121010921STim.Haley@Sun.COM zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 121110921STim.Haley@Sun.COM nvlist_t *rbi) 121210921STim.Haley@Sun.COM { 121310921STim.Haley@Sun.COM uint64_t rewindto; 121410921STim.Haley@Sun.COM int64_t loss = -1; 121510921STim.Haley@Sun.COM struct tm t; 121610921STim.Haley@Sun.COM char timestr[128]; 121710921STim.Haley@Sun.COM 121810921STim.Haley@Sun.COM if (!hdl->libzfs_printerr || rbi == NULL) 121910921STim.Haley@Sun.COM return; 122010921STim.Haley@Sun.COM 122110921STim.Haley@Sun.COM if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 122210921STim.Haley@Sun.COM return; 122310921STim.Haley@Sun.COM (void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss); 122410921STim.Haley@Sun.COM 122510921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 122610921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 122710921STim.Haley@Sun.COM if (dryrun) { 122810921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 122910921STim.Haley@Sun.COM "Would be able to return %s " 123010921STim.Haley@Sun.COM "to its state as of %s.\n"), 123110921STim.Haley@Sun.COM name, timestr); 123210921STim.Haley@Sun.COM } else { 123310921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 123410921STim.Haley@Sun.COM "Pool %s returned to its state as of %s.\n"), 123510921STim.Haley@Sun.COM name, timestr); 123610921STim.Haley@Sun.COM } 123710921STim.Haley@Sun.COM if (loss > 120) { 123810921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 123910921STim.Haley@Sun.COM "%s approximately %lld "), 124010921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", 124110921STim.Haley@Sun.COM (loss + 30) / 60); 124210921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 124310921STim.Haley@Sun.COM "minutes of transactions.\n")); 124410921STim.Haley@Sun.COM } else if (loss > 0) { 124510921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 124610921STim.Haley@Sun.COM "%s approximately %lld "), 124710921STim.Haley@Sun.COM dryrun ? "Would discard" : "Discarded", loss); 124810921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 124910921STim.Haley@Sun.COM "seconds of transactions.\n")); 125010921STim.Haley@Sun.COM } 125110921STim.Haley@Sun.COM } 125210921STim.Haley@Sun.COM } 125310921STim.Haley@Sun.COM 125410921STim.Haley@Sun.COM void 125510921STim.Haley@Sun.COM zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 125610921STim.Haley@Sun.COM nvlist_t *config) 125710921STim.Haley@Sun.COM { 125810921STim.Haley@Sun.COM int64_t loss = -1; 125910921STim.Haley@Sun.COM uint64_t edata = UINT64_MAX; 126010921STim.Haley@Sun.COM uint64_t rewindto; 126110921STim.Haley@Sun.COM struct tm t; 126210921STim.Haley@Sun.COM char timestr[128]; 126310921STim.Haley@Sun.COM 126410921STim.Haley@Sun.COM if (!hdl->libzfs_printerr) 126510921STim.Haley@Sun.COM return; 126610921STim.Haley@Sun.COM 126710921STim.Haley@Sun.COM if (reason >= 0) 126810921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 126910921STim.Haley@Sun.COM else 127010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, "\t")); 127110921STim.Haley@Sun.COM 127210921STim.Haley@Sun.COM /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 127310921STim.Haley@Sun.COM if (nvlist_lookup_uint64(config, 127410921STim.Haley@Sun.COM ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 127510921STim.Haley@Sun.COM goto no_info; 127610921STim.Haley@Sun.COM 127710921STim.Haley@Sun.COM (void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss); 127810921STim.Haley@Sun.COM (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 127910921STim.Haley@Sun.COM &edata); 128010921STim.Haley@Sun.COM 128110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 128210921STim.Haley@Sun.COM "Recovery is possible, but will result in some data loss.\n")); 128310921STim.Haley@Sun.COM 128410921STim.Haley@Sun.COM if (localtime_r((time_t *)&rewindto, &t) != NULL && 128510921STim.Haley@Sun.COM strftime(timestr, 128, 0, &t) != 0) { 128610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 128710921STim.Haley@Sun.COM "\tReturning the pool to its state as of %s\n" 128810921STim.Haley@Sun.COM "\tshould correct the problem. "), 128910921STim.Haley@Sun.COM timestr); 129010921STim.Haley@Sun.COM } else { 129110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 129210921STim.Haley@Sun.COM "\tReverting the pool to an earlier state " 129310921STim.Haley@Sun.COM "should correct the problem.\n\t")); 129410921STim.Haley@Sun.COM } 129510921STim.Haley@Sun.COM 129610921STim.Haley@Sun.COM if (loss > 120) { 129710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 129810921STim.Haley@Sun.COM "Approximately %lld minutes of data\n" 129910921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 130010921STim.Haley@Sun.COM } else if (loss > 0) { 130110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 130210921STim.Haley@Sun.COM "Approximately %lld seconds of data\n" 130310921STim.Haley@Sun.COM "\tmust be discarded, irreversibly. "), loss); 130410921STim.Haley@Sun.COM } 130510921STim.Haley@Sun.COM if (edata != 0 && edata != UINT64_MAX) { 130610921STim.Haley@Sun.COM if (edata == 1) { 130710921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 130810921STim.Haley@Sun.COM "After rewind, at least\n" 130910921STim.Haley@Sun.COM "\tone persistent user-data error will remain. ")); 131010921STim.Haley@Sun.COM } else { 131110921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 131210921STim.Haley@Sun.COM "After rewind, several\n" 131310921STim.Haley@Sun.COM "\tpersistent user-data errors will remain. ")); 131410921STim.Haley@Sun.COM } 131510921STim.Haley@Sun.COM } 131610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 131711026STim.Haley@Sun.COM "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "), 131811026STim.Haley@Sun.COM reason >= 0 ? "clear" : "import", name); 131910921STim.Haley@Sun.COM 132010921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 132110921STim.Haley@Sun.COM "A scrub of the pool\n" 132210921STim.Haley@Sun.COM "\tis strongly recommended after recovery.\n")); 132310921STim.Haley@Sun.COM return; 132410921STim.Haley@Sun.COM 132510921STim.Haley@Sun.COM no_info: 132610921STim.Haley@Sun.COM (void) printf(dgettext(TEXT_DOMAIN, 132710921STim.Haley@Sun.COM "Destroy and re-create the pool from\n\ta backup source.\n")); 132810921STim.Haley@Sun.COM } 132910921STim.Haley@Sun.COM 1330789Sahrens /* 13315094Slling * zpool_import() is a contracted interface. Should be kept the same 13325094Slling * if possible. 13335094Slling * 13345094Slling * Applications should use zpool_import_props() to import a pool with 13355094Slling * new properties value to be set. 1336789Sahrens */ 1337789Sahrens int 13382082Seschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 13395094Slling char *altroot) 13405094Slling { 13415094Slling nvlist_t *props = NULL; 13425094Slling int ret; 13435094Slling 13445094Slling if (altroot != NULL) { 13455094Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 13465094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13475094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13485094Slling newname)); 13495094Slling } 13505094Slling 13515094Slling if (nvlist_add_string(props, 13528084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 13538084SGeorge.Wilson@Sun.COM nvlist_add_string(props, 13548084SGeorge.Wilson@Sun.COM zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 13555094Slling nvlist_free(props); 13565094Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 13575094Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13585094Slling newname)); 13595094Slling } 13605094Slling } 13615094Slling 13626643Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 13635094Slling if (props) 13645094Slling nvlist_free(props); 13655094Slling return (ret); 13665094Slling } 13675094Slling 13685094Slling /* 13695094Slling * Import the given pool using the known configuration and a list of 13705094Slling * properties to be set. The configuration should have come from 13715094Slling * zpool_find_import(). The 'newname' parameters control whether the pool 13725094Slling * is imported with a different name. 13735094Slling */ 13745094Slling int 13755094Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 13766643Seschrock nvlist_t *props, boolean_t importfaulted) 1377789Sahrens { 13782676Seschrock zfs_cmd_t zc = { 0 }; 137910921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 138010921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 1381789Sahrens char *thename; 1382789Sahrens char *origname; 138310921STim.Haley@Sun.COM uint64_t returned_size; 1384789Sahrens int ret; 13855094Slling char errbuf[1024]; 1386789Sahrens 1387789Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1388789Sahrens &origname) == 0); 1389789Sahrens 13905094Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 13915094Slling "cannot import pool '%s'"), origname); 13925094Slling 1393789Sahrens if (newname != NULL) { 13942082Seschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 13953237Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 13962082Seschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 13972082Seschrock newname)); 1398789Sahrens thename = (char *)newname; 1399789Sahrens } else { 1400789Sahrens thename = origname; 1401789Sahrens } 1402789Sahrens 14035094Slling if (props) { 14045094Slling uint64_t version; 14055094Slling 14065094Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 14075094Slling &version) == 0); 14085094Slling 14097184Stimh if ((props = zpool_valid_proplist(hdl, origname, 14105320Slling props, version, B_TRUE, errbuf)) == NULL) { 14115094Slling return (-1); 14125320Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 14135320Slling nvlist_free(props); 14145094Slling return (-1); 14155320Slling } 14165094Slling } 1417789Sahrens 1418789Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1419789Sahrens 1420789Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 14211544Seschrock &zc.zc_guid) == 0); 1422789Sahrens 14235320Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 14245320Slling nvlist_free(props); 14252082Seschrock return (-1); 14265320Slling } 142710921STim.Haley@Sun.COM returned_size = zc.zc_nvlist_conf_size + 512; 142810921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) { 142910921STim.Haley@Sun.COM nvlist_free(props); 143010921STim.Haley@Sun.COM return (-1); 143110921STim.Haley@Sun.COM } 1432789Sahrens 14336643Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1434789Sahrens ret = 0; 14354543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1436789Sahrens char desc[1024]; 143710921STim.Haley@Sun.COM 143810921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 143910921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 144010921STim.Haley@Sun.COM /* 144110921STim.Haley@Sun.COM * Dry-run failed, but we print out what success 144210921STim.Haley@Sun.COM * looks like if we found a best txg 144310921STim.Haley@Sun.COM */ 144410921STim.Haley@Sun.COM if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) { 144510921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 144610921STim.Haley@Sun.COM B_TRUE, nvi); 144710921STim.Haley@Sun.COM nvlist_free(nvi); 144810921STim.Haley@Sun.COM return (-1); 144910921STim.Haley@Sun.COM } 145010921STim.Haley@Sun.COM 1451789Sahrens if (newname == NULL) 1452789Sahrens (void) snprintf(desc, sizeof (desc), 1453789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1454789Sahrens thename); 1455789Sahrens else 1456789Sahrens (void) snprintf(desc, sizeof (desc), 1457789Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1458789Sahrens origname, thename); 1459789Sahrens 1460789Sahrens switch (errno) { 14611544Seschrock case ENOTSUP: 14621544Seschrock /* 14631544Seschrock * Unsupported version. 14641544Seschrock */ 14652082Seschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 14661544Seschrock break; 14671544Seschrock 14682174Seschrock case EINVAL: 14692174Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 14702174Seschrock break; 14712174Seschrock 147211814SChris.Kirby@sun.com case EROFS: 147311814SChris.Kirby@sun.com zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 147411814SChris.Kirby@sun.com "one or more devices is read only")); 147511814SChris.Kirby@sun.com (void) zfs_error(hdl, EZFS_BADDEV, desc); 147611814SChris.Kirby@sun.com break; 147711814SChris.Kirby@sun.com 1478789Sahrens default: 147910921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 14802082Seschrock (void) zpool_standard_error(hdl, errno, desc); 148110921STim.Haley@Sun.COM zpool_explain_recover(hdl, 148210921STim.Haley@Sun.COM newname ? origname : thename, -errno, nvi); 148310921STim.Haley@Sun.COM nvlist_free(nvi); 148410921STim.Haley@Sun.COM break; 1485789Sahrens } 1486789Sahrens 1487789Sahrens ret = -1; 1488789Sahrens } else { 1489789Sahrens zpool_handle_t *zhp; 14904543Smarks 1491789Sahrens /* 1492789Sahrens * This should never fail, but play it safe anyway. 1493789Sahrens */ 149410588SEric.Taylor@Sun.COM if (zpool_open_silent(hdl, thename, &zhp) != 0) 14952142Seschrock ret = -1; 149610588SEric.Taylor@Sun.COM else if (zhp != NULL) 1497789Sahrens zpool_close(zhp); 149810921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 149910921STim.Haley@Sun.COM zpool_get_rewind_policy(config, &policy); 150010921STim.Haley@Sun.COM if (policy.zrp_request & 150110921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 150210921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, newname ? origname : thename, 150310921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 150410921STim.Haley@Sun.COM nvi); 150510921STim.Haley@Sun.COM } 150610921STim.Haley@Sun.COM nvlist_free(nvi); 150710921STim.Haley@Sun.COM return (0); 1508789Sahrens } 1509789Sahrens 15102676Seschrock zcmd_free_nvlists(&zc); 15115320Slling nvlist_free(props); 15125320Slling 1513789Sahrens return (ret); 1514789Sahrens } 1515789Sahrens 1516789Sahrens /* 151712296SLin.Ling@Sun.COM * Scan the pool. 1518789Sahrens */ 1519789Sahrens int 152012296SLin.Ling@Sun.COM zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func) 1521789Sahrens { 1522789Sahrens zfs_cmd_t zc = { 0 }; 1523789Sahrens char msg[1024]; 15242082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1525789Sahrens 1526789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 152712296SLin.Ling@Sun.COM zc.zc_cookie = func; 152812296SLin.Ling@Sun.COM 152912296SLin.Ling@Sun.COM if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCAN, &zc) == 0 || 153012296SLin.Ling@Sun.COM (errno == ENOENT && func != POOL_SCAN_NONE)) 1531789Sahrens return (0); 1532789Sahrens 153312296SLin.Ling@Sun.COM if (func == POOL_SCAN_SCRUB) { 153412296SLin.Ling@Sun.COM (void) snprintf(msg, sizeof (msg), 153512296SLin.Ling@Sun.COM dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 153612296SLin.Ling@Sun.COM } else if (func == POOL_SCAN_NONE) { 153712296SLin.Ling@Sun.COM (void) snprintf(msg, sizeof (msg), 153812296SLin.Ling@Sun.COM dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"), 153912296SLin.Ling@Sun.COM zc.zc_name); 154012296SLin.Ling@Sun.COM } else { 154112296SLin.Ling@Sun.COM assert(!"unexpected result"); 154212296SLin.Ling@Sun.COM } 154312296SLin.Ling@Sun.COM 154412296SLin.Ling@Sun.COM if (errno == EBUSY) { 154512296SLin.Ling@Sun.COM nvlist_t *nvroot; 154612296SLin.Ling@Sun.COM pool_scan_stat_t *ps = NULL; 154712296SLin.Ling@Sun.COM uint_t psc; 154812296SLin.Ling@Sun.COM 154912296SLin.Ling@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, 155012296SLin.Ling@Sun.COM ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 155112296SLin.Ling@Sun.COM (void) nvlist_lookup_uint64_array(nvroot, 155212296SLin.Ling@Sun.COM ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc); 155312296SLin.Ling@Sun.COM if (ps && ps->pss_func == POOL_SCAN_SCRUB) 155412296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_SCRUBBING, msg)); 155512296SLin.Ling@Sun.COM else 155612296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_RESILVERING, msg)); 155712296SLin.Ling@Sun.COM } else if (errno == ENOENT) { 155812296SLin.Ling@Sun.COM return (zfs_error(hdl, EZFS_NO_SCRUB, msg)); 155912296SLin.Ling@Sun.COM } else { 15602082Seschrock return (zpool_standard_error(hdl, errno, msg)); 156112296SLin.Ling@Sun.COM } 1562789Sahrens } 1563789Sahrens 15642468Sek110237 /* 1565*12383SJohn.Harres@Sun.COM * This provides a very minimal check whether a given string is likely a 1566*12383SJohn.Harres@Sun.COM * c#t#d# style string. Users of this are expected to do their own 1567*12383SJohn.Harres@Sun.COM * verification of the s# part. 1568*12383SJohn.Harres@Sun.COM */ 1569*12383SJohn.Harres@Sun.COM #define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1])) 1570*12383SJohn.Harres@Sun.COM 1571*12383SJohn.Harres@Sun.COM /* 1572*12383SJohn.Harres@Sun.COM * More elaborate version for ones which may start with "/dev/dsk/" 1573*12383SJohn.Harres@Sun.COM * and the like. 1574*12383SJohn.Harres@Sun.COM */ 1575*12383SJohn.Harres@Sun.COM static int 1576*12383SJohn.Harres@Sun.COM ctd_check_path(char *str) { 1577*12383SJohn.Harres@Sun.COM /* 1578*12383SJohn.Harres@Sun.COM * If it starts with a slash, check the last component. 1579*12383SJohn.Harres@Sun.COM */ 1580*12383SJohn.Harres@Sun.COM if (str && str[0] == '/') { 1581*12383SJohn.Harres@Sun.COM char *tmp = strrchr(str, '/'); 1582*12383SJohn.Harres@Sun.COM 1583*12383SJohn.Harres@Sun.COM /* 1584*12383SJohn.Harres@Sun.COM * If it ends in "/old", check the second-to-last 1585*12383SJohn.Harres@Sun.COM * component of the string instead. 1586*12383SJohn.Harres@Sun.COM */ 1587*12383SJohn.Harres@Sun.COM if (tmp != str && strcmp(tmp, "/old") == 0) { 1588*12383SJohn.Harres@Sun.COM for (tmp--; *tmp != '/'; tmp--) 1589*12383SJohn.Harres@Sun.COM ; 1590*12383SJohn.Harres@Sun.COM } 1591*12383SJohn.Harres@Sun.COM str = tmp + 1; 1592*12383SJohn.Harres@Sun.COM } 1593*12383SJohn.Harres@Sun.COM return (CTD_CHECK(str)); 1594*12383SJohn.Harres@Sun.COM } 1595*12383SJohn.Harres@Sun.COM 1596*12383SJohn.Harres@Sun.COM /* 15979816SGeorge.Wilson@Sun.COM * Find a vdev that matches the search criteria specified. We use the 15989816SGeorge.Wilson@Sun.COM * the nvpair name to determine how we should look for the device. 15992468Sek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 16002468Sek110237 * spare; but FALSE if its an INUSE spare. 16012468Sek110237 */ 16022082Seschrock static nvlist_t * 16039816SGeorge.Wilson@Sun.COM vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 16049816SGeorge.Wilson@Sun.COM boolean_t *l2cache, boolean_t *log) 16051544Seschrock { 16061544Seschrock uint_t c, children; 16071544Seschrock nvlist_t **child; 16082082Seschrock nvlist_t *ret; 16097326SEric.Schrock@Sun.COM uint64_t is_log; 16109816SGeorge.Wilson@Sun.COM char *srchkey; 16119816SGeorge.Wilson@Sun.COM nvpair_t *pair = nvlist_next_nvpair(search, NULL); 16129816SGeorge.Wilson@Sun.COM 16139816SGeorge.Wilson@Sun.COM /* Nothing to look for */ 16149816SGeorge.Wilson@Sun.COM if (search == NULL || pair == NULL) 16159816SGeorge.Wilson@Sun.COM return (NULL); 16169816SGeorge.Wilson@Sun.COM 16179816SGeorge.Wilson@Sun.COM /* Obtain the key we will use to search */ 16189816SGeorge.Wilson@Sun.COM srchkey = nvpair_name(pair); 16199816SGeorge.Wilson@Sun.COM 16209816SGeorge.Wilson@Sun.COM switch (nvpair_type(pair)) { 16219816SGeorge.Wilson@Sun.COM case DATA_TYPE_UINT64: { 16229816SGeorge.Wilson@Sun.COM uint64_t srchval, theguid, present; 16239816SGeorge.Wilson@Sun.COM 16249816SGeorge.Wilson@Sun.COM verify(nvpair_value_uint64(pair, &srchval) == 0); 16259816SGeorge.Wilson@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 16269816SGeorge.Wilson@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 16279816SGeorge.Wilson@Sun.COM &present) == 0) { 16289816SGeorge.Wilson@Sun.COM /* 16299816SGeorge.Wilson@Sun.COM * If the device has never been present since 16309816SGeorge.Wilson@Sun.COM * import, the only reliable way to match the 16319816SGeorge.Wilson@Sun.COM * vdev is by GUID. 16329816SGeorge.Wilson@Sun.COM */ 16339816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, 16349816SGeorge.Wilson@Sun.COM ZPOOL_CONFIG_GUID, &theguid) == 0); 16359816SGeorge.Wilson@Sun.COM if (theguid == srchval) 16369816SGeorge.Wilson@Sun.COM return (nv); 16379816SGeorge.Wilson@Sun.COM } 16389816SGeorge.Wilson@Sun.COM } 16399816SGeorge.Wilson@Sun.COM break; 16409816SGeorge.Wilson@Sun.COM } 16419816SGeorge.Wilson@Sun.COM 16429816SGeorge.Wilson@Sun.COM case DATA_TYPE_STRING: { 16439816SGeorge.Wilson@Sun.COM char *srchval, *val; 16449816SGeorge.Wilson@Sun.COM 16459816SGeorge.Wilson@Sun.COM verify(nvpair_value_string(pair, &srchval) == 0); 16469816SGeorge.Wilson@Sun.COM if (nvlist_lookup_string(nv, srchkey, &val) != 0) 16479816SGeorge.Wilson@Sun.COM break; 16489816SGeorge.Wilson@Sun.COM 16491544Seschrock /* 1650*12383SJohn.Harres@Sun.COM * Search for the requested value. Special cases: 1651*12383SJohn.Harres@Sun.COM * 1652*12383SJohn.Harres@Sun.COM * - ZPOOL_CONFIG_PATH for whole disk entries. These end in 1653*12383SJohn.Harres@Sun.COM * "s0" or "s0/old". The "s0" part is hidden from the user, 1654*12383SJohn.Harres@Sun.COM * but included in the string, so this matches around it. 1655*12383SJohn.Harres@Sun.COM * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 1656*12383SJohn.Harres@Sun.COM * 165710594SGeorge.Wilson@Sun.COM * Otherwise, all other searches are simple string compares. 16581544Seschrock */ 1659*12383SJohn.Harres@Sun.COM if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && 1660*12383SJohn.Harres@Sun.COM ctd_check_path(val)) { 16619816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 16629816SGeorge.Wilson@Sun.COM 16639816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 16649816SGeorge.Wilson@Sun.COM &wholedisk); 16659816SGeorge.Wilson@Sun.COM if (wholedisk) { 1666*12383SJohn.Harres@Sun.COM int slen = strlen(srchval); 1667*12383SJohn.Harres@Sun.COM int vlen = strlen(val); 1668*12383SJohn.Harres@Sun.COM 1669*12383SJohn.Harres@Sun.COM if (slen != vlen - 2) 1670*12383SJohn.Harres@Sun.COM break; 1671*12383SJohn.Harres@Sun.COM 16729816SGeorge.Wilson@Sun.COM /* 1673*12383SJohn.Harres@Sun.COM * make_leaf_vdev() should only set 1674*12383SJohn.Harres@Sun.COM * wholedisk for ZPOOL_CONFIG_PATHs which 1675*12383SJohn.Harres@Sun.COM * will include "/dev/dsk/", giving plenty of 1676*12383SJohn.Harres@Sun.COM * room for the indices used next. 16779816SGeorge.Wilson@Sun.COM */ 1678*12383SJohn.Harres@Sun.COM ASSERT(vlen >= 6); 1679*12383SJohn.Harres@Sun.COM 1680*12383SJohn.Harres@Sun.COM /* 1681*12383SJohn.Harres@Sun.COM * strings identical except trailing "s0" 1682*12383SJohn.Harres@Sun.COM */ 1683*12383SJohn.Harres@Sun.COM if (strcmp(&val[vlen - 2], "s0") == 0 && 1684*12383SJohn.Harres@Sun.COM strncmp(srchval, val, slen) == 0) 16859816SGeorge.Wilson@Sun.COM return (nv); 1686*12383SJohn.Harres@Sun.COM 1687*12383SJohn.Harres@Sun.COM /* 1688*12383SJohn.Harres@Sun.COM * strings identical except trailing "s0/old" 1689*12383SJohn.Harres@Sun.COM */ 1690*12383SJohn.Harres@Sun.COM if (strcmp(&val[vlen - 6], "s0/old") == 0 && 1691*12383SJohn.Harres@Sun.COM strcmp(&srchval[slen - 4], "/old") == 0 && 1692*12383SJohn.Harres@Sun.COM strncmp(srchval, val, slen - 4) == 0) 1693*12383SJohn.Harres@Sun.COM return (nv); 1694*12383SJohn.Harres@Sun.COM 16959816SGeorge.Wilson@Sun.COM break; 16969816SGeorge.Wilson@Sun.COM } 169710594SGeorge.Wilson@Sun.COM } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 169810594SGeorge.Wilson@Sun.COM char *type, *idx, *end, *p; 169910594SGeorge.Wilson@Sun.COM uint64_t id, vdev_id; 170010594SGeorge.Wilson@Sun.COM 170110594SGeorge.Wilson@Sun.COM /* 170210594SGeorge.Wilson@Sun.COM * Determine our vdev type, keeping in mind 170310594SGeorge.Wilson@Sun.COM * that the srchval is composed of a type and 170410594SGeorge.Wilson@Sun.COM * vdev id pair (i.e. mirror-4). 170510594SGeorge.Wilson@Sun.COM */ 170610594SGeorge.Wilson@Sun.COM if ((type = strdup(srchval)) == NULL) 170710594SGeorge.Wilson@Sun.COM return (NULL); 170810594SGeorge.Wilson@Sun.COM 170910594SGeorge.Wilson@Sun.COM if ((p = strrchr(type, '-')) == NULL) { 171010594SGeorge.Wilson@Sun.COM free(type); 171110594SGeorge.Wilson@Sun.COM break; 171210594SGeorge.Wilson@Sun.COM } 171310594SGeorge.Wilson@Sun.COM idx = p + 1; 171410594SGeorge.Wilson@Sun.COM *p = '\0'; 171510594SGeorge.Wilson@Sun.COM 171610594SGeorge.Wilson@Sun.COM /* 171710594SGeorge.Wilson@Sun.COM * If the types don't match then keep looking. 171810594SGeorge.Wilson@Sun.COM */ 171910594SGeorge.Wilson@Sun.COM if (strncmp(val, type, strlen(val)) != 0) { 172010594SGeorge.Wilson@Sun.COM free(type); 172110594SGeorge.Wilson@Sun.COM break; 172210594SGeorge.Wilson@Sun.COM } 172310594SGeorge.Wilson@Sun.COM 172410594SGeorge.Wilson@Sun.COM verify(strncmp(type, VDEV_TYPE_RAIDZ, 172510594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_RAIDZ)) == 0 || 172610594SGeorge.Wilson@Sun.COM strncmp(type, VDEV_TYPE_MIRROR, 172710594SGeorge.Wilson@Sun.COM strlen(VDEV_TYPE_MIRROR)) == 0); 172810594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 172910594SGeorge.Wilson@Sun.COM &id) == 0); 173010594SGeorge.Wilson@Sun.COM 173110594SGeorge.Wilson@Sun.COM errno = 0; 173210594SGeorge.Wilson@Sun.COM vdev_id = strtoull(idx, &end, 10); 173310594SGeorge.Wilson@Sun.COM 173410594SGeorge.Wilson@Sun.COM free(type); 173510594SGeorge.Wilson@Sun.COM if (errno != 0) 173610594SGeorge.Wilson@Sun.COM return (NULL); 173710594SGeorge.Wilson@Sun.COM 173810594SGeorge.Wilson@Sun.COM /* 173910594SGeorge.Wilson@Sun.COM * Now verify that we have the correct vdev id. 174010594SGeorge.Wilson@Sun.COM */ 174110594SGeorge.Wilson@Sun.COM if (vdev_id == id) 174210594SGeorge.Wilson@Sun.COM return (nv); 17439816SGeorge.Wilson@Sun.COM } 17449816SGeorge.Wilson@Sun.COM 17459816SGeorge.Wilson@Sun.COM /* 17469816SGeorge.Wilson@Sun.COM * Common case 17479816SGeorge.Wilson@Sun.COM */ 17489816SGeorge.Wilson@Sun.COM if (strcmp(srchval, val) == 0) 17492082Seschrock return (nv); 17509816SGeorge.Wilson@Sun.COM break; 17519816SGeorge.Wilson@Sun.COM } 17529816SGeorge.Wilson@Sun.COM 17539816SGeorge.Wilson@Sun.COM default: 17549816SGeorge.Wilson@Sun.COM break; 17551544Seschrock } 17561544Seschrock 17571544Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 17581544Seschrock &child, &children) != 0) 17592082Seschrock return (NULL); 17601544Seschrock 17617326SEric.Schrock@Sun.COM for (c = 0; c < children; c++) { 17629816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17637326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17647326SEric.Schrock@Sun.COM /* 17657326SEric.Schrock@Sun.COM * The 'is_log' value is only set for the toplevel 17667326SEric.Schrock@Sun.COM * vdev, not the leaf vdevs. So we always lookup the 17677326SEric.Schrock@Sun.COM * log device from the root of the vdev tree (where 17687326SEric.Schrock@Sun.COM * 'log' is non-NULL). 17697326SEric.Schrock@Sun.COM */ 17707326SEric.Schrock@Sun.COM if (log != NULL && 17717326SEric.Schrock@Sun.COM nvlist_lookup_uint64(child[c], 17727326SEric.Schrock@Sun.COM ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 17737326SEric.Schrock@Sun.COM is_log) { 17747326SEric.Schrock@Sun.COM *log = B_TRUE; 17757326SEric.Schrock@Sun.COM } 17761544Seschrock return (ret); 17777326SEric.Schrock@Sun.COM } 17787326SEric.Schrock@Sun.COM } 17791544Seschrock 17802082Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 17812082Seschrock &child, &children) == 0) { 17822082Seschrock for (c = 0; c < children; c++) { 17839816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17847326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17852468Sek110237 *avail_spare = B_TRUE; 17862082Seschrock return (ret); 17872082Seschrock } 17882082Seschrock } 17892082Seschrock } 17902082Seschrock 17915450Sbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 17925450Sbrendan &child, &children) == 0) { 17935450Sbrendan for (c = 0; c < children; c++) { 17949816SGeorge.Wilson@Sun.COM if ((ret = vdev_to_nvlist_iter(child[c], search, 17957326SEric.Schrock@Sun.COM avail_spare, l2cache, NULL)) != NULL) { 17965450Sbrendan *l2cache = B_TRUE; 17975450Sbrendan return (ret); 17985450Sbrendan } 17995450Sbrendan } 18005450Sbrendan } 18015450Sbrendan 18022082Seschrock return (NULL); 18031544Seschrock } 18041544Seschrock 18059816SGeorge.Wilson@Sun.COM /* 18069816SGeorge.Wilson@Sun.COM * Given a physical path (minus the "/devices" prefix), find the 18079816SGeorge.Wilson@Sun.COM * associated vdev. 18089816SGeorge.Wilson@Sun.COM */ 18099816SGeorge.Wilson@Sun.COM nvlist_t * 18109816SGeorge.Wilson@Sun.COM zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 18119816SGeorge.Wilson@Sun.COM boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 18129816SGeorge.Wilson@Sun.COM { 18139816SGeorge.Wilson@Sun.COM nvlist_t *search, *nvroot, *ret; 18149816SGeorge.Wilson@Sun.COM 18159816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 18169816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 18179816SGeorge.Wilson@Sun.COM 18189816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18199816SGeorge.Wilson@Sun.COM &nvroot) == 0); 18209816SGeorge.Wilson@Sun.COM 18219816SGeorge.Wilson@Sun.COM *avail_spare = B_FALSE; 18229816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 18239816SGeorge.Wilson@Sun.COM nvlist_free(search); 18249816SGeorge.Wilson@Sun.COM 18259816SGeorge.Wilson@Sun.COM return (ret); 18269816SGeorge.Wilson@Sun.COM } 18279816SGeorge.Wilson@Sun.COM 182810594SGeorge.Wilson@Sun.COM /* 182910594SGeorge.Wilson@Sun.COM * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 183010594SGeorge.Wilson@Sun.COM */ 183110594SGeorge.Wilson@Sun.COM boolean_t 183210594SGeorge.Wilson@Sun.COM zpool_vdev_is_interior(const char *name) 183310594SGeorge.Wilson@Sun.COM { 183410594SGeorge.Wilson@Sun.COM if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 183510594SGeorge.Wilson@Sun.COM strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 183610594SGeorge.Wilson@Sun.COM return (B_TRUE); 183710594SGeorge.Wilson@Sun.COM return (B_FALSE); 183810594SGeorge.Wilson@Sun.COM } 183910594SGeorge.Wilson@Sun.COM 18402082Seschrock nvlist_t * 18415450Sbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 18427326SEric.Schrock@Sun.COM boolean_t *l2cache, boolean_t *log) 18431544Seschrock { 18441544Seschrock char buf[MAXPATHLEN]; 18451544Seschrock char *end; 18469816SGeorge.Wilson@Sun.COM nvlist_t *nvroot, *search, *ret; 18471544Seschrock uint64_t guid; 18481544Seschrock 18499816SGeorge.Wilson@Sun.COM verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 18509816SGeorge.Wilson@Sun.COM 18511613Seschrock guid = strtoull(path, &end, 10); 18521544Seschrock if (guid != 0 && *end == '\0') { 18539816SGeorge.Wilson@Sun.COM verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 185410594SGeorge.Wilson@Sun.COM } else if (zpool_vdev_is_interior(path)) { 185510594SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 18561544Seschrock } else if (path[0] != '/') { 18571544Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 18589816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 18591544Seschrock } else { 18609816SGeorge.Wilson@Sun.COM verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 18611544Seschrock } 18621544Seschrock 18631544Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 18641544Seschrock &nvroot) == 0); 18651544Seschrock 18662468Sek110237 *avail_spare = B_FALSE; 18675450Sbrendan *l2cache = B_FALSE; 18687326SEric.Schrock@Sun.COM if (log != NULL) 18697326SEric.Schrock@Sun.COM *log = B_FALSE; 18709816SGeorge.Wilson@Sun.COM ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 18719816SGeorge.Wilson@Sun.COM nvlist_free(search); 18729816SGeorge.Wilson@Sun.COM 18739816SGeorge.Wilson@Sun.COM return (ret); 18742468Sek110237 } 18752468Sek110237 18767656SSherry.Moore@Sun.COM static int 18777656SSherry.Moore@Sun.COM vdev_online(nvlist_t *nv) 18787656SSherry.Moore@Sun.COM { 18797656SSherry.Moore@Sun.COM uint64_t ival; 18807656SSherry.Moore@Sun.COM 18817656SSherry.Moore@Sun.COM if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 18827656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 18837656SSherry.Moore@Sun.COM nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 18847656SSherry.Moore@Sun.COM return (0); 18857656SSherry.Moore@Sun.COM 18867656SSherry.Moore@Sun.COM return (1); 18877656SSherry.Moore@Sun.COM } 18887656SSherry.Moore@Sun.COM 18897656SSherry.Moore@Sun.COM /* 18909790SLin.Ling@Sun.COM * Helper function for zpool_get_physpaths(). 18917656SSherry.Moore@Sun.COM */ 18929160SSherry.Moore@Sun.COM static int 18939790SLin.Ling@Sun.COM vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 18949160SSherry.Moore@Sun.COM size_t *bytes_written) 18957656SSherry.Moore@Sun.COM { 18969160SSherry.Moore@Sun.COM size_t bytes_left, pos, rsz; 18979160SSherry.Moore@Sun.COM char *tmppath; 18989160SSherry.Moore@Sun.COM const char *format; 18999160SSherry.Moore@Sun.COM 19009160SSherry.Moore@Sun.COM if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 19019160SSherry.Moore@Sun.COM &tmppath) != 0) 19029160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 19039160SSherry.Moore@Sun.COM 19049160SSherry.Moore@Sun.COM pos = *bytes_written; 19059160SSherry.Moore@Sun.COM bytes_left = physpath_size - pos; 19069160SSherry.Moore@Sun.COM format = (pos == 0) ? "%s" : " %s"; 19079160SSherry.Moore@Sun.COM 19089160SSherry.Moore@Sun.COM rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 19099160SSherry.Moore@Sun.COM *bytes_written += rsz; 19109160SSherry.Moore@Sun.COM 19119160SSherry.Moore@Sun.COM if (rsz >= bytes_left) { 19129160SSherry.Moore@Sun.COM /* if physpath was not copied properly, clear it */ 19139160SSherry.Moore@Sun.COM if (bytes_left != 0) { 19149160SSherry.Moore@Sun.COM physpath[pos] = 0; 19159160SSherry.Moore@Sun.COM } 19169160SSherry.Moore@Sun.COM return (EZFS_NOSPC); 19179160SSherry.Moore@Sun.COM } 19189160SSherry.Moore@Sun.COM return (0); 19199160SSherry.Moore@Sun.COM } 19209160SSherry.Moore@Sun.COM 19219790SLin.Ling@Sun.COM static int 19229790SLin.Ling@Sun.COM vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 19239790SLin.Ling@Sun.COM size_t *rsz, boolean_t is_spare) 19249790SLin.Ling@Sun.COM { 19259790SLin.Ling@Sun.COM char *type; 19269790SLin.Ling@Sun.COM int ret; 19279790SLin.Ling@Sun.COM 19289790SLin.Ling@Sun.COM if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 19299790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19309790SLin.Ling@Sun.COM 19319790SLin.Ling@Sun.COM if (strcmp(type, VDEV_TYPE_DISK) == 0) { 19329790SLin.Ling@Sun.COM /* 19339790SLin.Ling@Sun.COM * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 19349790SLin.Ling@Sun.COM * For a spare vdev, we only want to boot from the active 19359790SLin.Ling@Sun.COM * spare device. 19369790SLin.Ling@Sun.COM */ 19379790SLin.Ling@Sun.COM if (is_spare) { 19389790SLin.Ling@Sun.COM uint64_t spare = 0; 19399790SLin.Ling@Sun.COM (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 19409790SLin.Ling@Sun.COM &spare); 19419790SLin.Ling@Sun.COM if (!spare) 19429790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19439790SLin.Ling@Sun.COM } 19449790SLin.Ling@Sun.COM 19459790SLin.Ling@Sun.COM if (vdev_online(nv)) { 19469790SLin.Ling@Sun.COM if ((ret = vdev_get_one_physpath(nv, physpath, 19479790SLin.Ling@Sun.COM phypath_size, rsz)) != 0) 19489790SLin.Ling@Sun.COM return (ret); 19499790SLin.Ling@Sun.COM } 19509790SLin.Ling@Sun.COM } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 19519790SLin.Ling@Sun.COM strcmp(type, VDEV_TYPE_REPLACING) == 0 || 19529790SLin.Ling@Sun.COM (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 19539790SLin.Ling@Sun.COM nvlist_t **child; 19549790SLin.Ling@Sun.COM uint_t count; 19559790SLin.Ling@Sun.COM int i, ret; 19569790SLin.Ling@Sun.COM 19579790SLin.Ling@Sun.COM if (nvlist_lookup_nvlist_array(nv, 19589790SLin.Ling@Sun.COM ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 19599790SLin.Ling@Sun.COM return (EZFS_INVALCONFIG); 19609790SLin.Ling@Sun.COM 19619790SLin.Ling@Sun.COM for (i = 0; i < count; i++) { 19629790SLin.Ling@Sun.COM ret = vdev_get_physpaths(child[i], physpath, 19639790SLin.Ling@Sun.COM phypath_size, rsz, is_spare); 19649790SLin.Ling@Sun.COM if (ret == EZFS_NOSPC) 19659790SLin.Ling@Sun.COM return (ret); 19669790SLin.Ling@Sun.COM } 19679790SLin.Ling@Sun.COM } 19689790SLin.Ling@Sun.COM 19699790SLin.Ling@Sun.COM return (EZFS_POOL_INVALARG); 19709790SLin.Ling@Sun.COM } 19719790SLin.Ling@Sun.COM 19729160SSherry.Moore@Sun.COM /* 19739160SSherry.Moore@Sun.COM * Get phys_path for a root pool config. 19749160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 19759160SSherry.Moore@Sun.COM */ 19769160SSherry.Moore@Sun.COM static int 19779160SSherry.Moore@Sun.COM zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 19789160SSherry.Moore@Sun.COM { 19799160SSherry.Moore@Sun.COM size_t rsz; 19807656SSherry.Moore@Sun.COM nvlist_t *vdev_root; 19817656SSherry.Moore@Sun.COM nvlist_t **child; 19827656SSherry.Moore@Sun.COM uint_t count; 19839160SSherry.Moore@Sun.COM char *type; 19849160SSherry.Moore@Sun.COM 19859160SSherry.Moore@Sun.COM rsz = 0; 19869160SSherry.Moore@Sun.COM 19879160SSherry.Moore@Sun.COM if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 19889160SSherry.Moore@Sun.COM &vdev_root) != 0) 19899160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19909160SSherry.Moore@Sun.COM 19919160SSherry.Moore@Sun.COM if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 19929160SSherry.Moore@Sun.COM nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 19939160SSherry.Moore@Sun.COM &child, &count) != 0) 19949160SSherry.Moore@Sun.COM return (EZFS_INVALCONFIG); 19957656SSherry.Moore@Sun.COM 19967656SSherry.Moore@Sun.COM /* 19979160SSherry.Moore@Sun.COM * root pool can not have EFI labeled disks and can only have 19989160SSherry.Moore@Sun.COM * a single top-level vdev. 19997656SSherry.Moore@Sun.COM */ 20009160SSherry.Moore@Sun.COM if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 20019160SSherry.Moore@Sun.COM pool_uses_efi(vdev_root)) 20029160SSherry.Moore@Sun.COM return (EZFS_POOL_INVALARG); 20039160SSherry.Moore@Sun.COM 20049790SLin.Ling@Sun.COM (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 20059790SLin.Ling@Sun.COM B_FALSE); 20067656SSherry.Moore@Sun.COM 20079160SSherry.Moore@Sun.COM /* No online devices */ 20089160SSherry.Moore@Sun.COM if (rsz == 0) 20099160SSherry.Moore@Sun.COM return (EZFS_NODEVICE); 20109160SSherry.Moore@Sun.COM 20117656SSherry.Moore@Sun.COM return (0); 20127656SSherry.Moore@Sun.COM } 20137656SSherry.Moore@Sun.COM 20142468Sek110237 /* 20159160SSherry.Moore@Sun.COM * Get phys_path for a root pool 20169160SSherry.Moore@Sun.COM * Return 0 on success; non-zero on failure. 20179160SSherry.Moore@Sun.COM */ 20189160SSherry.Moore@Sun.COM int 20199160SSherry.Moore@Sun.COM zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 20209160SSherry.Moore@Sun.COM { 20219160SSherry.Moore@Sun.COM return (zpool_get_config_physpath(zhp->zpool_config, physpath, 20229160SSherry.Moore@Sun.COM phypath_size)); 20239160SSherry.Moore@Sun.COM } 20249160SSherry.Moore@Sun.COM 20259160SSherry.Moore@Sun.COM /* 20269816SGeorge.Wilson@Sun.COM * If the device has being dynamically expanded then we need to relabel 20279816SGeorge.Wilson@Sun.COM * the disk to use the new unallocated space. 20289816SGeorge.Wilson@Sun.COM */ 20299816SGeorge.Wilson@Sun.COM static int 20309816SGeorge.Wilson@Sun.COM zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 20319816SGeorge.Wilson@Sun.COM { 20329816SGeorge.Wilson@Sun.COM char path[MAXPATHLEN]; 20339816SGeorge.Wilson@Sun.COM char errbuf[1024]; 20349816SGeorge.Wilson@Sun.COM int fd, error; 20359816SGeorge.Wilson@Sun.COM int (*_efi_use_whole_disk)(int); 20369816SGeorge.Wilson@Sun.COM 20379816SGeorge.Wilson@Sun.COM if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 20389816SGeorge.Wilson@Sun.COM "efi_use_whole_disk")) == NULL) 20399816SGeorge.Wilson@Sun.COM return (-1); 20409816SGeorge.Wilson@Sun.COM 20419816SGeorge.Wilson@Sun.COM (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 20429816SGeorge.Wilson@Sun.COM 20439816SGeorge.Wilson@Sun.COM if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 20449816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 20459816SGeorge.Wilson@Sun.COM "relabel '%s': unable to open device"), name); 20469816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 20479816SGeorge.Wilson@Sun.COM } 20489816SGeorge.Wilson@Sun.COM 20499816SGeorge.Wilson@Sun.COM /* 20509816SGeorge.Wilson@Sun.COM * It's possible that we might encounter an error if the device 20519816SGeorge.Wilson@Sun.COM * does not have any unallocated space left. If so, we simply 20529816SGeorge.Wilson@Sun.COM * ignore that error and continue on. 20539816SGeorge.Wilson@Sun.COM */ 20549816SGeorge.Wilson@Sun.COM error = _efi_use_whole_disk(fd); 20559816SGeorge.Wilson@Sun.COM (void) close(fd); 20569816SGeorge.Wilson@Sun.COM if (error && error != VT_ENOSPC) { 20579816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 20589816SGeorge.Wilson@Sun.COM "relabel '%s': unable to read disk capacity"), name); 20599816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 20609816SGeorge.Wilson@Sun.COM } 20619816SGeorge.Wilson@Sun.COM return (0); 20629816SGeorge.Wilson@Sun.COM } 20639816SGeorge.Wilson@Sun.COM 20649816SGeorge.Wilson@Sun.COM /* 20654451Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 20664451Seschrock * ZFS_ONLINE_* flags. 2067789Sahrens */ 2068789Sahrens int 20694451Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 20704451Seschrock vdev_state_t *newstate) 2071789Sahrens { 2072789Sahrens zfs_cmd_t zc = { 0 }; 2073789Sahrens char msg[1024]; 20742082Seschrock nvlist_t *tgt; 20759816SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 20762082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2077789Sahrens 20789816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND) { 20799816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20809816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 20819816SGeorge.Wilson@Sun.COM } else { 20829816SGeorge.Wilson@Sun.COM (void) snprintf(msg, sizeof (msg), 20839816SGeorge.Wilson@Sun.COM dgettext(TEXT_DOMAIN, "cannot online %s"), path); 20849816SGeorge.Wilson@Sun.COM } 2085789Sahrens 20861544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20877326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 20889816SGeorge.Wilson@Sun.COM &islog)) == NULL) 20892082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2090789Sahrens 20912468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 20922468Sek110237 209310817SEric.Schrock@Sun.COM if (avail_spare) 20942082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 20952082Seschrock 20969816SGeorge.Wilson@Sun.COM if (flags & ZFS_ONLINE_EXPAND || 20979816SGeorge.Wilson@Sun.COM zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 20989816SGeorge.Wilson@Sun.COM char *pathname = NULL; 20999816SGeorge.Wilson@Sun.COM uint64_t wholedisk = 0; 21009816SGeorge.Wilson@Sun.COM 21019816SGeorge.Wilson@Sun.COM (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 21029816SGeorge.Wilson@Sun.COM &wholedisk); 21039816SGeorge.Wilson@Sun.COM verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 21049816SGeorge.Wilson@Sun.COM &pathname) == 0); 21059816SGeorge.Wilson@Sun.COM 21069816SGeorge.Wilson@Sun.COM /* 21079816SGeorge.Wilson@Sun.COM * XXX - L2ARC 1.0 devices can't support expansion. 21089816SGeorge.Wilson@Sun.COM */ 21099816SGeorge.Wilson@Sun.COM if (l2cache) { 21109816SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21119816SGeorge.Wilson@Sun.COM "cannot expand cache devices")); 21129816SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 21139816SGeorge.Wilson@Sun.COM } 21149816SGeorge.Wilson@Sun.COM 21159816SGeorge.Wilson@Sun.COM if (wholedisk) { 21169816SGeorge.Wilson@Sun.COM pathname += strlen(DISK_ROOT) + 1; 21179816SGeorge.Wilson@Sun.COM (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 21189816SGeorge.Wilson@Sun.COM } 21199816SGeorge.Wilson@Sun.COM } 21209816SGeorge.Wilson@Sun.COM 21214451Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 21224451Seschrock zc.zc_obj = flags; 21234451Seschrock 212411422SMark.Musante@Sun.COM if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) { 212511422SMark.Musante@Sun.COM if (errno == EINVAL) { 212611422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split " 212711422SMark.Musante@Sun.COM "from this pool into a new one. Use '%s' " 212811422SMark.Musante@Sun.COM "instead"), "zpool detach"); 212911422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg)); 213011422SMark.Musante@Sun.COM } 21314451Seschrock return (zpool_standard_error(hdl, errno, msg)); 213211422SMark.Musante@Sun.COM } 21334451Seschrock 21344451Seschrock *newstate = zc.zc_cookie; 21354451Seschrock return (0); 2136789Sahrens } 2137789Sahrens 2138789Sahrens /* 2139789Sahrens * Take the specified vdev offline 2140789Sahrens */ 2141789Sahrens int 21424451Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2143789Sahrens { 2144789Sahrens zfs_cmd_t zc = { 0 }; 2145789Sahrens char msg[1024]; 21462082Seschrock nvlist_t *tgt; 21475450Sbrendan boolean_t avail_spare, l2cache; 21482082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2149789Sahrens 21501544Seschrock (void) snprintf(msg, sizeof (msg), 21511544Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 21521544Seschrock 2153789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21547326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 21557326SEric.Schrock@Sun.COM NULL)) == NULL) 21562082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 21572082Seschrock 21582468Sek110237 verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 21592468Sek110237 216010817SEric.Schrock@Sun.COM if (avail_spare) 21612082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 21622082Seschrock 21634451Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 21644451Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 21651485Slling 21664543Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2167789Sahrens return (0); 2168789Sahrens 2169789Sahrens switch (errno) { 21702082Seschrock case EBUSY: 2171789Sahrens 2172789Sahrens /* 2173789Sahrens * There are no other replicas of this device. 2174789Sahrens */ 21752082Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21762082Seschrock 21779701SGeorge.Wilson@Sun.COM case EEXIST: 21789701SGeorge.Wilson@Sun.COM /* 21799701SGeorge.Wilson@Sun.COM * The log device has unplayed logs 21809701SGeorge.Wilson@Sun.COM */ 21819701SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 21829701SGeorge.Wilson@Sun.COM 21832082Seschrock default: 21842082Seschrock return (zpool_standard_error(hdl, errno, msg)); 21852082Seschrock } 21862082Seschrock } 2187789Sahrens 21882082Seschrock /* 21894451Seschrock * Mark the given vdev faulted. 21904451Seschrock */ 21914451Seschrock int 219210817SEric.Schrock@Sun.COM zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21934451Seschrock { 21944451Seschrock zfs_cmd_t zc = { 0 }; 21954451Seschrock char msg[1024]; 21964451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21974451Seschrock 21984451Seschrock (void) snprintf(msg, sizeof (msg), 21994451Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 22004451Seschrock 22014451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22024451Seschrock zc.zc_guid = guid; 22034451Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 220410817SEric.Schrock@Sun.COM zc.zc_obj = aux; 22054451Seschrock 22064451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 22074451Seschrock return (0); 22084451Seschrock 22094451Seschrock switch (errno) { 22104451Seschrock case EBUSY: 22114451Seschrock 22124451Seschrock /* 22134451Seschrock * There are no other replicas of this device. 22144451Seschrock */ 22154451Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 22164451Seschrock 22174451Seschrock default: 22184451Seschrock return (zpool_standard_error(hdl, errno, msg)); 22194451Seschrock } 22204451Seschrock 22214451Seschrock } 22224451Seschrock 22234451Seschrock /* 22244451Seschrock * Mark the given vdev degraded. 22254451Seschrock */ 22264451Seschrock int 222710817SEric.Schrock@Sun.COM zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 22284451Seschrock { 22294451Seschrock zfs_cmd_t zc = { 0 }; 22304451Seschrock char msg[1024]; 22314451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22324451Seschrock 22334451Seschrock (void) snprintf(msg, sizeof (msg), 22344451Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 22354451Seschrock 22364451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 22374451Seschrock zc.zc_guid = guid; 22384451Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 223910817SEric.Schrock@Sun.COM zc.zc_obj = aux; 22404451Seschrock 22414451Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 22424451Seschrock return (0); 22434451Seschrock 22444451Seschrock return (zpool_standard_error(hdl, errno, msg)); 22454451Seschrock } 22464451Seschrock 22474451Seschrock /* 22482082Seschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 22492082Seschrock * a hot spare. 22502082Seschrock */ 22512082Seschrock static boolean_t 22522082Seschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 22532082Seschrock { 22542082Seschrock nvlist_t **child; 22552082Seschrock uint_t c, children; 22562082Seschrock char *type; 22572082Seschrock 22582082Seschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 22592082Seschrock &children) == 0) { 22602082Seschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 22612082Seschrock &type) == 0); 22622082Seschrock 22632082Seschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 22642082Seschrock children == 2 && child[which] == tgt) 22652082Seschrock return (B_TRUE); 22662082Seschrock 22672082Seschrock for (c = 0; c < children; c++) 22682082Seschrock if (is_replacing_spare(child[c], tgt, which)) 22692082Seschrock return (B_TRUE); 2270789Sahrens } 22712082Seschrock 22722082Seschrock return (B_FALSE); 2273789Sahrens } 2274789Sahrens 2275789Sahrens /* 2276789Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 22774527Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2278789Sahrens */ 2279789Sahrens int 2280789Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2281789Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2282789Sahrens { 2283789Sahrens zfs_cmd_t zc = { 0 }; 2284789Sahrens char msg[1024]; 2285789Sahrens int ret; 22862082Seschrock nvlist_t *tgt; 22877326SEric.Schrock@Sun.COM boolean_t avail_spare, l2cache, islog; 22887326SEric.Schrock@Sun.COM uint64_t val; 22897041Seschrock char *path, *newname; 22902082Seschrock nvlist_t **child; 22912082Seschrock uint_t children; 22922082Seschrock nvlist_t *config_root; 22932082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 22947965SGeorge.Wilson@Sun.COM boolean_t rootpool = pool_is_bootable(zhp); 2295789Sahrens 22961544Seschrock if (replacing) 22971544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 22981544Seschrock "cannot replace %s with %s"), old_disk, new_disk); 22991544Seschrock else 23001544Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 23011544Seschrock "cannot attach %s to %s"), new_disk, old_disk); 23021544Seschrock 23037965SGeorge.Wilson@Sun.COM /* 23047965SGeorge.Wilson@Sun.COM * If this is a root pool, make sure that we're not attaching an 23057965SGeorge.Wilson@Sun.COM * EFI labeled device. 23067965SGeorge.Wilson@Sun.COM */ 23077965SGeorge.Wilson@Sun.COM if (rootpool && pool_uses_efi(nvroot)) { 23087965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23097965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root pools.")); 23107965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 23117965SGeorge.Wilson@Sun.COM } 23127965SGeorge.Wilson@Sun.COM 2313789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23147326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 23157326SEric.Schrock@Sun.COM &islog)) == 0) 23162082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 23172082Seschrock 23182468Sek110237 if (avail_spare) 23192082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 23202082Seschrock 23215450Sbrendan if (l2cache) 23225450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 23235450Sbrendan 23242082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 23252082Seschrock zc.zc_cookie = replacing; 23262082Seschrock 23272082Seschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 23282082Seschrock &child, &children) != 0 || children != 1) { 23292082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23302082Seschrock "new device must be a single disk")); 23312082Seschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 23321544Seschrock } 23332082Seschrock 23342082Seschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 23352082Seschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 23362082Seschrock 233710594SGeorge.Wilson@Sun.COM if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 23387041Seschrock return (-1); 23397041Seschrock 23402082Seschrock /* 23412082Seschrock * If the target is a hot spare that has been swapped in, we can only 23422082Seschrock * replace it with another hot spare. 23432082Seschrock */ 23442082Seschrock if (replacing && 23452082Seschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 23467326SEric.Schrock@Sun.COM (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 23477326SEric.Schrock@Sun.COM NULL) == NULL || !avail_spare) && 23487326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 1)) { 23492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23502082Seschrock "can only be replaced by another hot spare")); 23517041Seschrock free(newname); 23522082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 23532082Seschrock } 23542082Seschrock 23552082Seschrock /* 23562082Seschrock * If we are attempting to replace a spare, it canot be applied to an 23572082Seschrock * already spared device. 23582082Seschrock */ 23592082Seschrock if (replacing && 23602082Seschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 23617326SEric.Schrock@Sun.COM zpool_find_vdev(zhp, newname, &avail_spare, 23627326SEric.Schrock@Sun.COM &l2cache, NULL) != NULL && avail_spare && 23637326SEric.Schrock@Sun.COM is_replacing_spare(config_root, tgt, 0)) { 23642082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23652082Seschrock "device has already been replaced with a spare")); 23667041Seschrock free(newname); 23672082Seschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 23682082Seschrock } 2369789Sahrens 23707041Seschrock free(newname); 23717041Seschrock 23725094Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 23732082Seschrock return (-1); 2374789Sahrens 23754543Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2376789Sahrens 23772676Seschrock zcmd_free_nvlists(&zc); 2378789Sahrens 23797965SGeorge.Wilson@Sun.COM if (ret == 0) { 23807965SGeorge.Wilson@Sun.COM if (rootpool) { 23817965SGeorge.Wilson@Sun.COM /* 23827965SGeorge.Wilson@Sun.COM * XXX - This should be removed once we can 23837965SGeorge.Wilson@Sun.COM * automatically install the bootblocks on the 23847965SGeorge.Wilson@Sun.COM * newly attached disk. 23857965SGeorge.Wilson@Sun.COM */ 23867965SGeorge.Wilson@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 23877965SGeorge.Wilson@Sun.COM "be sure to invoke %s to make '%s' bootable.\n"), 23887965SGeorge.Wilson@Sun.COM BOOTCMD, new_disk); 23899790SLin.Ling@Sun.COM 23909790SLin.Ling@Sun.COM /* 23919790SLin.Ling@Sun.COM * XXX need a better way to prevent user from 23929790SLin.Ling@Sun.COM * booting up a half-baked vdev. 23939790SLin.Ling@Sun.COM */ 23949790SLin.Ling@Sun.COM (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 23959790SLin.Ling@Sun.COM "sure to wait until resilver is done " 23969790SLin.Ling@Sun.COM "before rebooting.\n")); 23977965SGeorge.Wilson@Sun.COM } 2398789Sahrens return (0); 23997965SGeorge.Wilson@Sun.COM } 2400789Sahrens 2401789Sahrens switch (errno) { 24021544Seschrock case ENOTSUP: 2403789Sahrens /* 2404789Sahrens * Can't attach to or replace this type of vdev. 2405789Sahrens */ 24064527Sperrin if (replacing) { 24077326SEric.Schrock@Sun.COM if (islog) 24084527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24094527Sperrin "cannot replace a log with a spare")); 24104527Sperrin else 24114527Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24124527Sperrin "cannot replace a replacing device")); 24134527Sperrin } else { 24142082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24152082Seschrock "can only attach to mirrors and top-level " 24162082Seschrock "disks")); 24174527Sperrin } 24182082Seschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2419789Sahrens break; 2420789Sahrens 24211544Seschrock case EINVAL: 2422789Sahrens /* 2423789Sahrens * The new device must be a single disk. 2424789Sahrens */ 24252082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24262082Seschrock "new device must be a single disk")); 24272082Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2428789Sahrens break; 2429789Sahrens 24301544Seschrock case EBUSY: 24312082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 24322082Seschrock new_disk); 24332082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2434789Sahrens break; 2435789Sahrens 24361544Seschrock case EOVERFLOW: 2437789Sahrens /* 2438789Sahrens * The new device is too small. 2439789Sahrens */ 24402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24412082Seschrock "device is too small")); 24422082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2443789Sahrens break; 2444789Sahrens 24451544Seschrock case EDOM: 2446789Sahrens /* 2447789Sahrens * The new device has a different alignment requirement. 2448789Sahrens */ 24492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 24502082Seschrock "devices have different sector alignment")); 24512082Seschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2452789Sahrens break; 2453789Sahrens 24541544Seschrock case ENAMETOOLONG: 2455789Sahrens /* 2456789Sahrens * The resulting top-level vdev spec won't fit in the label. 2457789Sahrens */ 24582082Seschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2459789Sahrens break; 2460789Sahrens 24611544Seschrock default: 24622082Seschrock (void) zpool_standard_error(hdl, errno, msg); 2463789Sahrens } 2464789Sahrens 24652082Seschrock return (-1); 2466789Sahrens } 2467789Sahrens 2468789Sahrens /* 2469789Sahrens * Detach the specified device. 2470789Sahrens */ 2471789Sahrens int 2472789Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2473789Sahrens { 2474789Sahrens zfs_cmd_t zc = { 0 }; 2475789Sahrens char msg[1024]; 24762082Seschrock nvlist_t *tgt; 24775450Sbrendan boolean_t avail_spare, l2cache; 24782082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2479789Sahrens 24801544Seschrock (void) snprintf(msg, sizeof (msg), 24811544Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 24821544Seschrock 2483789Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 24847326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 24857326SEric.Schrock@Sun.COM NULL)) == 0) 24862082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2487789Sahrens 24882468Sek110237 if (avail_spare) 24892082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 24902082Seschrock 24915450Sbrendan if (l2cache) 24925450Sbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 24935450Sbrendan 24942082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 24952082Seschrock 24964543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2497789Sahrens return (0); 2498789Sahrens 2499789Sahrens switch (errno) { 2500789Sahrens 25011544Seschrock case ENOTSUP: 2502789Sahrens /* 2503789Sahrens * Can't detach from this type of vdev. 2504789Sahrens */ 25052082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 25062082Seschrock "applicable to mirror and replacing vdevs")); 25072082Seschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2508789Sahrens break; 2509789Sahrens 25101544Seschrock case EBUSY: 2511789Sahrens /* 2512789Sahrens * There are no other replicas of this device. 2513789Sahrens */ 25142082Seschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2515789Sahrens break; 2516789Sahrens 25171544Seschrock default: 25182082Seschrock (void) zpool_standard_error(hdl, errno, msg); 25191544Seschrock } 25201544Seschrock 25212082Seschrock return (-1); 25222082Seschrock } 25232082Seschrock 25242082Seschrock /* 252511422SMark.Musante@Sun.COM * Find a mirror vdev in the source nvlist. 252611422SMark.Musante@Sun.COM * 252711422SMark.Musante@Sun.COM * The mchild array contains a list of disks in one of the top-level mirrors 252811422SMark.Musante@Sun.COM * of the source pool. The schild array contains a list of disks that the 252911422SMark.Musante@Sun.COM * user specified on the command line. We loop over the mchild array to 253011422SMark.Musante@Sun.COM * see if any entry in the schild array matches. 253111422SMark.Musante@Sun.COM * 253211422SMark.Musante@Sun.COM * If a disk in the mchild array is found in the schild array, we return 253311422SMark.Musante@Sun.COM * the index of that entry. Otherwise we return -1. 253411422SMark.Musante@Sun.COM */ 253511422SMark.Musante@Sun.COM static int 253611422SMark.Musante@Sun.COM find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren, 253711422SMark.Musante@Sun.COM nvlist_t **schild, uint_t schildren) 253811422SMark.Musante@Sun.COM { 253911422SMark.Musante@Sun.COM uint_t mc; 254011422SMark.Musante@Sun.COM 254111422SMark.Musante@Sun.COM for (mc = 0; mc < mchildren; mc++) { 254211422SMark.Musante@Sun.COM uint_t sc; 254311422SMark.Musante@Sun.COM char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp, 254411422SMark.Musante@Sun.COM mchild[mc], B_FALSE); 254511422SMark.Musante@Sun.COM 254611422SMark.Musante@Sun.COM for (sc = 0; sc < schildren; sc++) { 254711422SMark.Musante@Sun.COM char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp, 254811422SMark.Musante@Sun.COM schild[sc], B_FALSE); 254911422SMark.Musante@Sun.COM boolean_t result = (strcmp(mpath, spath) == 0); 255011422SMark.Musante@Sun.COM 255111422SMark.Musante@Sun.COM free(spath); 255211422SMark.Musante@Sun.COM if (result) { 255311422SMark.Musante@Sun.COM free(mpath); 255411422SMark.Musante@Sun.COM return (mc); 255511422SMark.Musante@Sun.COM } 255611422SMark.Musante@Sun.COM } 255711422SMark.Musante@Sun.COM 255811422SMark.Musante@Sun.COM free(mpath); 255911422SMark.Musante@Sun.COM } 256011422SMark.Musante@Sun.COM 256111422SMark.Musante@Sun.COM return (-1); 256211422SMark.Musante@Sun.COM } 256311422SMark.Musante@Sun.COM 256411422SMark.Musante@Sun.COM /* 256511422SMark.Musante@Sun.COM * Split a mirror pool. If newroot points to null, then a new nvlist 256611422SMark.Musante@Sun.COM * is generated and it is the responsibility of the caller to free it. 256711422SMark.Musante@Sun.COM */ 256811422SMark.Musante@Sun.COM int 256911422SMark.Musante@Sun.COM zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot, 257011422SMark.Musante@Sun.COM nvlist_t *props, splitflags_t flags) 257111422SMark.Musante@Sun.COM { 257211422SMark.Musante@Sun.COM zfs_cmd_t zc = { 0 }; 257311422SMark.Musante@Sun.COM char msg[1024]; 257411422SMark.Musante@Sun.COM nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL; 257511422SMark.Musante@Sun.COM nvlist_t **varray = NULL, *zc_props = NULL; 257611422SMark.Musante@Sun.COM uint_t c, children, newchildren, lastlog = 0, vcount, found = 0; 257711422SMark.Musante@Sun.COM libzfs_handle_t *hdl = zhp->zpool_hdl; 257811422SMark.Musante@Sun.COM uint64_t vers; 257911422SMark.Musante@Sun.COM boolean_t freelist = B_FALSE, memory_err = B_TRUE; 258011422SMark.Musante@Sun.COM int retval = 0; 258111422SMark.Musante@Sun.COM 258211422SMark.Musante@Sun.COM (void) snprintf(msg, sizeof (msg), 258311422SMark.Musante@Sun.COM dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name); 258411422SMark.Musante@Sun.COM 258511422SMark.Musante@Sun.COM if (!zpool_name_valid(hdl, B_FALSE, newname)) 258611422SMark.Musante@Sun.COM return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 258711422SMark.Musante@Sun.COM 258811422SMark.Musante@Sun.COM if ((config = zpool_get_config(zhp, NULL)) == NULL) { 258911422SMark.Musante@Sun.COM (void) fprintf(stderr, gettext("Internal error: unable to " 259011422SMark.Musante@Sun.COM "retrieve pool configuration\n")); 259111422SMark.Musante@Sun.COM return (-1); 259211422SMark.Musante@Sun.COM } 259311422SMark.Musante@Sun.COM 259411422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) 259511422SMark.Musante@Sun.COM == 0); 259611422SMark.Musante@Sun.COM verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0); 259711422SMark.Musante@Sun.COM 259811422SMark.Musante@Sun.COM if (props) { 259911422SMark.Musante@Sun.COM if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name, 260011422SMark.Musante@Sun.COM props, vers, B_TRUE, msg)) == NULL) 260111422SMark.Musante@Sun.COM return (-1); 260211422SMark.Musante@Sun.COM } 260311422SMark.Musante@Sun.COM 260411422SMark.Musante@Sun.COM if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, 260511422SMark.Musante@Sun.COM &children) != 0) { 260611422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 260711422SMark.Musante@Sun.COM "Source pool is missing vdev tree")); 260811422SMark.Musante@Sun.COM if (zc_props) 260911422SMark.Musante@Sun.COM nvlist_free(zc_props); 261011422SMark.Musante@Sun.COM return (-1); 261111422SMark.Musante@Sun.COM } 261211422SMark.Musante@Sun.COM 261311422SMark.Musante@Sun.COM varray = zfs_alloc(hdl, children * sizeof (nvlist_t *)); 261411422SMark.Musante@Sun.COM vcount = 0; 261511422SMark.Musante@Sun.COM 261611422SMark.Musante@Sun.COM if (*newroot == NULL || 261711422SMark.Musante@Sun.COM nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, 261811422SMark.Musante@Sun.COM &newchild, &newchildren) != 0) 261911422SMark.Musante@Sun.COM newchildren = 0; 262011422SMark.Musante@Sun.COM 262111422SMark.Musante@Sun.COM for (c = 0; c < children; c++) { 262211422SMark.Musante@Sun.COM uint64_t is_log = B_FALSE, is_hole = B_FALSE; 262311422SMark.Musante@Sun.COM char *type; 262411422SMark.Musante@Sun.COM nvlist_t **mchild, *vdev; 262511422SMark.Musante@Sun.COM uint_t mchildren; 262611422SMark.Musante@Sun.COM int entry; 262711422SMark.Musante@Sun.COM 262811422SMark.Musante@Sun.COM /* 262911422SMark.Musante@Sun.COM * Unlike cache & spares, slogs are stored in the 263011422SMark.Musante@Sun.COM * ZPOOL_CONFIG_CHILDREN array. We filter them out here. 263111422SMark.Musante@Sun.COM */ 263211422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 263311422SMark.Musante@Sun.COM &is_log); 263411422SMark.Musante@Sun.COM (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 263511422SMark.Musante@Sun.COM &is_hole); 263611422SMark.Musante@Sun.COM if (is_log || is_hole) { 263711422SMark.Musante@Sun.COM /* 263811422SMark.Musante@Sun.COM * Create a hole vdev and put it in the config. 263911422SMark.Musante@Sun.COM */ 264011422SMark.Musante@Sun.COM if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0) 264111422SMark.Musante@Sun.COM goto out; 264211422SMark.Musante@Sun.COM if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, 264311422SMark.Musante@Sun.COM VDEV_TYPE_HOLE) != 0) 264411422SMark.Musante@Sun.COM goto out; 264511422SMark.Musante@Sun.COM if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE, 264611422SMark.Musante@Sun.COM 1) != 0) 264711422SMark.Musante@Sun.COM goto out; 264811422SMark.Musante@Sun.COM if (lastlog == 0) 264911422SMark.Musante@Sun.COM lastlog = vcount; 265011422SMark.Musante@Sun.COM varray[vcount++] = vdev; 265111422SMark.Musante@Sun.COM continue; 265211422SMark.Musante@Sun.COM } 265311422SMark.Musante@Sun.COM lastlog = 0; 265411422SMark.Musante@Sun.COM verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type) 265511422SMark.Musante@Sun.COM == 0); 265611422SMark.Musante@Sun.COM if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 265711422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 265811422SMark.Musante@Sun.COM "Source pool must be composed only of mirrors\n")); 265911422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 266011422SMark.Musante@Sun.COM goto out; 266111422SMark.Musante@Sun.COM } 266211422SMark.Musante@Sun.COM 266311422SMark.Musante@Sun.COM verify(nvlist_lookup_nvlist_array(child[c], 266411422SMark.Musante@Sun.COM ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0); 266511422SMark.Musante@Sun.COM 266611422SMark.Musante@Sun.COM /* find or add an entry for this top-level vdev */ 266711422SMark.Musante@Sun.COM if (newchildren > 0 && 266811422SMark.Musante@Sun.COM (entry = find_vdev_entry(zhp, mchild, mchildren, 266911422SMark.Musante@Sun.COM newchild, newchildren)) >= 0) { 267011422SMark.Musante@Sun.COM /* We found a disk that the user specified. */ 267111422SMark.Musante@Sun.COM vdev = mchild[entry]; 267211422SMark.Musante@Sun.COM ++found; 267311422SMark.Musante@Sun.COM } else { 267411422SMark.Musante@Sun.COM /* User didn't specify a disk for this vdev. */ 267511422SMark.Musante@Sun.COM vdev = mchild[mchildren - 1]; 267611422SMark.Musante@Sun.COM } 267711422SMark.Musante@Sun.COM 267811422SMark.Musante@Sun.COM if (nvlist_dup(vdev, &varray[vcount++], 0) != 0) 267911422SMark.Musante@Sun.COM goto out; 268011422SMark.Musante@Sun.COM } 268111422SMark.Musante@Sun.COM 268211422SMark.Musante@Sun.COM /* did we find every disk the user specified? */ 268311422SMark.Musante@Sun.COM if (found != newchildren) { 268411422SMark.Musante@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must " 268511422SMark.Musante@Sun.COM "include at most one disk from each mirror")); 268611422SMark.Musante@Sun.COM retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 268711422SMark.Musante@Sun.COM goto out; 268811422SMark.Musante@Sun.COM } 268911422SMark.Musante@Sun.COM 269011422SMark.Musante@Sun.COM /* Prepare the nvlist for populating. */ 269111422SMark.Musante@Sun.COM if (*newroot == NULL) { 269211422SMark.Musante@Sun.COM if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0) 269311422SMark.Musante@Sun.COM goto out; 269411422SMark.Musante@Sun.COM freelist = B_TRUE; 269511422SMark.Musante@Sun.COM if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE, 269611422SMark.Musante@Sun.COM VDEV_TYPE_ROOT) != 0) 269711422SMark.Musante@Sun.COM goto out; 269811422SMark.Musante@Sun.COM } else { 269911422SMark.Musante@Sun.COM verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0); 270011422SMark.Musante@Sun.COM } 270111422SMark.Musante@Sun.COM 270211422SMark.Musante@Sun.COM /* Add all the children we found */ 270311422SMark.Musante@Sun.COM if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray, 270411422SMark.Musante@Sun.COM lastlog == 0 ? vcount : lastlog) != 0) 270511422SMark.Musante@Sun.COM goto out; 270611422SMark.Musante@Sun.COM 270711422SMark.Musante@Sun.COM /* 270811422SMark.Musante@Sun.COM * If we're just doing a dry run, exit now with success. 270911422SMark.Musante@Sun.COM */ 271011422SMark.Musante@Sun.COM if (flags.dryrun) { 271111422SMark.Musante@Sun.COM memory_err = B_FALSE; 271211422SMark.Musante@Sun.COM freelist = B_FALSE; 271311422SMark.Musante@Sun.COM goto out; 271411422SMark.Musante@Sun.COM } 271511422SMark.Musante@Sun.COM 271611422SMark.Musante@Sun.COM /* now build up the config list & call the ioctl */ 271711422SMark.Musante@Sun.COM if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0) 271811422SMark.Musante@Sun.COM goto out; 271911422SMark.Musante@Sun.COM 272011422SMark.Musante@Sun.COM if (nvlist_add_nvlist(newconfig, 272111422SMark.Musante@Sun.COM ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 || 272211422SMark.Musante@Sun.COM nvlist_add_string(newconfig, 272311422SMark.Musante@Sun.COM ZPOOL_CONFIG_POOL_NAME, newname) != 0 || 272411422SMark.Musante@Sun.COM nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0) 272511422SMark.Musante@Sun.COM goto out; 272611422SMark.Musante@Sun.COM 272711422SMark.Musante@Sun.COM /* 272811422SMark.Musante@Sun.COM * The new pool is automatically part of the namespace unless we 272911422SMark.Musante@Sun.COM * explicitly export it. 273011422SMark.Musante@Sun.COM */ 273111422SMark.Musante@Sun.COM if (!flags.import) 273211422SMark.Musante@Sun.COM zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT; 273311422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 273411422SMark.Musante@Sun.COM (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string)); 273511422SMark.Musante@Sun.COM if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0) 273611422SMark.Musante@Sun.COM goto out; 273711422SMark.Musante@Sun.COM if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 273811422SMark.Musante@Sun.COM goto out; 273911422SMark.Musante@Sun.COM 274011422SMark.Musante@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) { 274111422SMark.Musante@Sun.COM retval = zpool_standard_error(hdl, errno, msg); 274211422SMark.Musante@Sun.COM goto out; 274311422SMark.Musante@Sun.COM } 274411422SMark.Musante@Sun.COM 274511422SMark.Musante@Sun.COM freelist = B_FALSE; 274611422SMark.Musante@Sun.COM memory_err = B_FALSE; 274711422SMark.Musante@Sun.COM 274811422SMark.Musante@Sun.COM out: 274911422SMark.Musante@Sun.COM if (varray != NULL) { 275011422SMark.Musante@Sun.COM int v; 275111422SMark.Musante@Sun.COM 275211422SMark.Musante@Sun.COM for (v = 0; v < vcount; v++) 275311422SMark.Musante@Sun.COM nvlist_free(varray[v]); 275411422SMark.Musante@Sun.COM free(varray); 275511422SMark.Musante@Sun.COM } 275611422SMark.Musante@Sun.COM zcmd_free_nvlists(&zc); 275711422SMark.Musante@Sun.COM if (zc_props) 275811422SMark.Musante@Sun.COM nvlist_free(zc_props); 275911422SMark.Musante@Sun.COM if (newconfig) 276011422SMark.Musante@Sun.COM nvlist_free(newconfig); 276111422SMark.Musante@Sun.COM if (freelist) { 276211422SMark.Musante@Sun.COM nvlist_free(*newroot); 276311422SMark.Musante@Sun.COM *newroot = NULL; 276411422SMark.Musante@Sun.COM } 276511422SMark.Musante@Sun.COM 276611422SMark.Musante@Sun.COM if (retval != 0) 276711422SMark.Musante@Sun.COM return (retval); 276811422SMark.Musante@Sun.COM 276911422SMark.Musante@Sun.COM if (memory_err) 277011422SMark.Musante@Sun.COM return (no_memory(hdl)); 277111422SMark.Musante@Sun.COM 277211422SMark.Musante@Sun.COM return (0); 277311422SMark.Musante@Sun.COM } 277411422SMark.Musante@Sun.COM 277511422SMark.Musante@Sun.COM /* 27765450Sbrendan * Remove the given device. Currently, this is supported only for hot spares 27775450Sbrendan * and level 2 cache devices. 27782082Seschrock */ 27792082Seschrock int 27802082Seschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 27812082Seschrock { 27822082Seschrock zfs_cmd_t zc = { 0 }; 27832082Seschrock char msg[1024]; 27842082Seschrock nvlist_t *tgt; 278510594SGeorge.Wilson@Sun.COM boolean_t avail_spare, l2cache, islog; 27862082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 278710594SGeorge.Wilson@Sun.COM uint64_t version; 27882082Seschrock 27892082Seschrock (void) snprintf(msg, sizeof (msg), 27902082Seschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 27912082Seschrock 27922082Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 27937326SEric.Schrock@Sun.COM if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 279410594SGeorge.Wilson@Sun.COM &islog)) == 0) 27952082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 279610594SGeorge.Wilson@Sun.COM /* 279710594SGeorge.Wilson@Sun.COM * XXX - this should just go away. 279810594SGeorge.Wilson@Sun.COM */ 279910594SGeorge.Wilson@Sun.COM if (!avail_spare && !l2cache && !islog) { 28002082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 280110594SGeorge.Wilson@Sun.COM "only inactive hot spares, cache, top-level, " 280210594SGeorge.Wilson@Sun.COM "or log devices can be removed")); 28032082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 28042082Seschrock } 28052082Seschrock 280610594SGeorge.Wilson@Sun.COM version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 280710594SGeorge.Wilson@Sun.COM if (islog && version < SPA_VERSION_HOLES) { 280810594SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 280910594SGeorge.Wilson@Sun.COM "pool must be upgrade to support log removal")); 281010594SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_BADVERSION, msg)); 281110594SGeorge.Wilson@Sun.COM } 281210594SGeorge.Wilson@Sun.COM 28132082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 28142082Seschrock 28154543Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 28162082Seschrock return (0); 28172082Seschrock 28182082Seschrock return (zpool_standard_error(hdl, errno, msg)); 28191544Seschrock } 28201544Seschrock 28211544Seschrock /* 28221544Seschrock * Clear the errors for the pool, or the particular device if specified. 28231544Seschrock */ 28241544Seschrock int 282510921STim.Haley@Sun.COM zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 28261544Seschrock { 28271544Seschrock zfs_cmd_t zc = { 0 }; 28281544Seschrock char msg[1024]; 28292082Seschrock nvlist_t *tgt; 283010921STim.Haley@Sun.COM zpool_rewind_policy_t policy; 28315450Sbrendan boolean_t avail_spare, l2cache; 28322082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 283310921STim.Haley@Sun.COM nvlist_t *nvi = NULL; 28341544Seschrock 28351544Seschrock if (path) 28361544Seschrock (void) snprintf(msg, sizeof (msg), 28371544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 28382676Seschrock path); 28391544Seschrock else 28401544Seschrock (void) snprintf(msg, sizeof (msg), 28411544Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 28421544Seschrock zhp->zpool_name); 28431544Seschrock 28441544Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 28452082Seschrock if (path) { 28465450Sbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 28477326SEric.Schrock@Sun.COM &l2cache, NULL)) == 0) 28482082Seschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 28492082Seschrock 28505450Sbrendan /* 28515450Sbrendan * Don't allow error clearing for hot spares. Do allow 28525450Sbrendan * error clearing for l2cache devices. 28535450Sbrendan */ 28542468Sek110237 if (avail_spare) 28552082Seschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 28562082Seschrock 28572082Seschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 28582082Seschrock &zc.zc_guid) == 0); 28591544Seschrock } 28601544Seschrock 286110921STim.Haley@Sun.COM zpool_get_rewind_policy(rewindnvl, &policy); 286210921STim.Haley@Sun.COM zc.zc_cookie = policy.zrp_request; 286310921STim.Haley@Sun.COM 286410921STim.Haley@Sun.COM if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0) 286510921STim.Haley@Sun.COM return (-1); 286610921STim.Haley@Sun.COM 286710921STim.Haley@Sun.COM if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0) 286810921STim.Haley@Sun.COM return (-1); 286910921STim.Haley@Sun.COM 287010921STim.Haley@Sun.COM if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 || 287110921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) && 287210921STim.Haley@Sun.COM errno != EPERM && errno != EACCES)) { 287310921STim.Haley@Sun.COM if (policy.zrp_request & 287410921STim.Haley@Sun.COM (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 287510921STim.Haley@Sun.COM (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 287610921STim.Haley@Sun.COM zpool_rewind_exclaim(hdl, zc.zc_name, 287710921STim.Haley@Sun.COM ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 287810921STim.Haley@Sun.COM nvi); 287910921STim.Haley@Sun.COM nvlist_free(nvi); 288010921STim.Haley@Sun.COM } 288110921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 28821544Seschrock return (0); 288310921STim.Haley@Sun.COM } 288410921STim.Haley@Sun.COM 288510921STim.Haley@Sun.COM zcmd_free_nvlists(&zc); 28862082Seschrock return (zpool_standard_error(hdl, errno, msg)); 2887789Sahrens } 2888789Sahrens 28893126Sahl /* 28904451Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 28914451Seschrock */ 28924451Seschrock int 28934451Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 28944451Seschrock { 28954451Seschrock zfs_cmd_t zc = { 0 }; 28964451Seschrock char msg[1024]; 28974451Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 28984451Seschrock 28994451Seschrock (void) snprintf(msg, sizeof (msg), 29004451Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 29014451Seschrock guid); 29024451Seschrock 29034451Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29044451Seschrock zc.zc_guid = guid; 29054451Seschrock 29064451Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 29074451Seschrock return (0); 29084451Seschrock 29094451Seschrock return (zpool_standard_error(hdl, errno, msg)); 29104451Seschrock } 29114451Seschrock 29124451Seschrock /* 29131354Seschrock * Convert from a devid string to a path. 29141354Seschrock */ 29151354Seschrock static char * 29161354Seschrock devid_to_path(char *devid_str) 29171354Seschrock { 29181354Seschrock ddi_devid_t devid; 29191354Seschrock char *minor; 29201354Seschrock char *path; 29211354Seschrock devid_nmlist_t *list = NULL; 29221354Seschrock int ret; 29231354Seschrock 29241354Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 29251354Seschrock return (NULL); 29261354Seschrock 29271354Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 29281354Seschrock 29291354Seschrock devid_str_free(minor); 29301354Seschrock devid_free(devid); 29311354Seschrock 29321354Seschrock if (ret != 0) 29331354Seschrock return (NULL); 29341354Seschrock 29352082Seschrock if ((path = strdup(list[0].devname)) == NULL) 29362082Seschrock return (NULL); 29372082Seschrock 29381354Seschrock devid_free_nmlist(list); 29391354Seschrock 29401354Seschrock return (path); 29411354Seschrock } 29421354Seschrock 29431354Seschrock /* 29441354Seschrock * Convert from a path to a devid string. 29451354Seschrock */ 29461354Seschrock static char * 29471354Seschrock path_to_devid(const char *path) 29481354Seschrock { 29491354Seschrock int fd; 29501354Seschrock ddi_devid_t devid; 29511354Seschrock char *minor, *ret; 29521354Seschrock 29531354Seschrock if ((fd = open(path, O_RDONLY)) < 0) 29541354Seschrock return (NULL); 29551354Seschrock 29561354Seschrock minor = NULL; 29571354Seschrock ret = NULL; 29581354Seschrock if (devid_get(fd, &devid) == 0) { 29591354Seschrock if (devid_get_minor_name(fd, &minor) == 0) 29601354Seschrock ret = devid_str_encode(devid, minor); 29611354Seschrock if (minor != NULL) 29621354Seschrock devid_str_free(minor); 29631354Seschrock devid_free(devid); 29641354Seschrock } 29651354Seschrock (void) close(fd); 29661354Seschrock 29671354Seschrock return (ret); 29681354Seschrock } 29691354Seschrock 29701354Seschrock /* 29711354Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 29721354Seschrock * ignore any failure here, since a common case is for an unprivileged user to 29731354Seschrock * type 'zpool status', and we'll display the correct information anyway. 29741354Seschrock */ 29751354Seschrock static void 29761354Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 29771354Seschrock { 29781354Seschrock zfs_cmd_t zc = { 0 }; 29791354Seschrock 29801354Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29812676Seschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 29821354Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 29831544Seschrock &zc.zc_guid) == 0); 29841354Seschrock 29852082Seschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 29861354Seschrock } 29871354Seschrock 29881354Seschrock /* 29891354Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 29901354Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 29911354Seschrock * We also check if this is a whole disk, in which case we strip off the 29921354Seschrock * trailing 's0' slice name. 29931354Seschrock * 29941354Seschrock * This routine is also responsible for identifying when disks have been 29951354Seschrock * reconfigured in a new location. The kernel will have opened the device by 29961354Seschrock * devid, but the path will still refer to the old location. To catch this, we 29971354Seschrock * first do a path -> devid translation (which is fast for the common case). If 29981354Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 29991354Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 30001354Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 30011354Seschrock * of these checks. 30021354Seschrock */ 30031354Seschrock char * 300410594SGeorge.Wilson@Sun.COM zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 300510594SGeorge.Wilson@Sun.COM boolean_t verbose) 30061354Seschrock { 30071354Seschrock char *path, *devid; 30081544Seschrock uint64_t value; 30091544Seschrock char buf[64]; 30104451Seschrock vdev_stat_t *vs; 30114451Seschrock uint_t vsc; 30121354Seschrock 30131544Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 30141544Seschrock &value) == 0) { 30151544Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 30161544Seschrock &value) == 0); 30172856Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 30182856Snd150628 (u_longlong_t)value); 30191544Seschrock path = buf; 30201544Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 30211354Seschrock 30224451Seschrock /* 30234451Seschrock * If the device is dead (faulted, offline, etc) then don't 30244451Seschrock * bother opening it. Otherwise we may be forcing the user to 30254451Seschrock * open a misbehaving device, which can have undesirable 30264451Seschrock * effects. 30274451Seschrock */ 302812296SLin.Ling@Sun.COM if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 30294451Seschrock (uint64_t **)&vs, &vsc) != 0 || 30304451Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 30314451Seschrock zhp != NULL && 30321354Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 30331354Seschrock /* 30341354Seschrock * Determine if the current path is correct. 30351354Seschrock */ 30361354Seschrock char *newdevid = path_to_devid(path); 30371354Seschrock 30381354Seschrock if (newdevid == NULL || 30391354Seschrock strcmp(devid, newdevid) != 0) { 30401354Seschrock char *newpath; 30411354Seschrock 30421354Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 30431354Seschrock /* 30441354Seschrock * Update the path appropriately. 30451354Seschrock */ 30461354Seschrock set_path(zhp, nv, newpath); 30472082Seschrock if (nvlist_add_string(nv, 30482082Seschrock ZPOOL_CONFIG_PATH, newpath) == 0) 30492082Seschrock verify(nvlist_lookup_string(nv, 30502082Seschrock ZPOOL_CONFIG_PATH, 30512082Seschrock &path) == 0); 30521354Seschrock free(newpath); 30531354Seschrock } 30541354Seschrock } 30551354Seschrock 30562082Seschrock if (newdevid) 30572082Seschrock devid_str_free(newdevid); 30581354Seschrock } 30591354Seschrock 30601354Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 30611354Seschrock path += 9; 30621354Seschrock 30631354Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 30641544Seschrock &value) == 0 && value) { 3065*12383SJohn.Harres@Sun.COM int pathlen = strlen(path); 30662082Seschrock char *tmp = zfs_strdup(hdl, path); 3067*12383SJohn.Harres@Sun.COM 3068*12383SJohn.Harres@Sun.COM /* 3069*12383SJohn.Harres@Sun.COM * If it starts with c#, and ends with "s0", chop 3070*12383SJohn.Harres@Sun.COM * the "s0" off, or if it ends with "s0/old", remove 3071*12383SJohn.Harres@Sun.COM * the "s0" from the middle. 3072*12383SJohn.Harres@Sun.COM */ 3073*12383SJohn.Harres@Sun.COM if (CTD_CHECK(tmp)) { 3074*12383SJohn.Harres@Sun.COM if (strcmp(&tmp[pathlen - 2], "s0") == 0) { 3075*12383SJohn.Harres@Sun.COM tmp[pathlen - 2] = '\0'; 3076*12383SJohn.Harres@Sun.COM } else if (pathlen > 6 && 3077*12383SJohn.Harres@Sun.COM strcmp(&tmp[pathlen - 6], "s0/old") == 0) { 3078*12383SJohn.Harres@Sun.COM (void) strcpy(&tmp[pathlen - 6], 3079*12383SJohn.Harres@Sun.COM "/old"); 3080*12383SJohn.Harres@Sun.COM } 3081*12383SJohn.Harres@Sun.COM } 30821354Seschrock return (tmp); 30831354Seschrock } 30841354Seschrock } else { 30851354Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 30862082Seschrock 30872082Seschrock /* 30882082Seschrock * If it's a raidz device, we need to stick in the parity level. 30892082Seschrock */ 30902082Seschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 30912082Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 30922082Seschrock &value) == 0); 30932082Seschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 30942856Snd150628 (u_longlong_t)value); 30952082Seschrock path = buf; 30962082Seschrock } 309710594SGeorge.Wilson@Sun.COM 309810594SGeorge.Wilson@Sun.COM /* 309910594SGeorge.Wilson@Sun.COM * We identify each top-level vdev by using a <type-id> 310010594SGeorge.Wilson@Sun.COM * naming convention. 310110594SGeorge.Wilson@Sun.COM */ 310210594SGeorge.Wilson@Sun.COM if (verbose) { 310310594SGeorge.Wilson@Sun.COM uint64_t id; 310410594SGeorge.Wilson@Sun.COM 310510594SGeorge.Wilson@Sun.COM verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 310610594SGeorge.Wilson@Sun.COM &id) == 0); 310710594SGeorge.Wilson@Sun.COM (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 310810594SGeorge.Wilson@Sun.COM (u_longlong_t)id); 310910594SGeorge.Wilson@Sun.COM path = buf; 311010594SGeorge.Wilson@Sun.COM } 31111354Seschrock } 31121354Seschrock 31132082Seschrock return (zfs_strdup(hdl, path)); 31141354Seschrock } 31151544Seschrock 31161544Seschrock static int 31171544Seschrock zbookmark_compare(const void *a, const void *b) 31181544Seschrock { 31191544Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 31201544Seschrock } 31211544Seschrock 31221544Seschrock /* 31231544Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 31241544Seschrock * caller. 31251544Seschrock */ 31261544Seschrock int 31273444Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 31281544Seschrock { 31291544Seschrock zfs_cmd_t zc = { 0 }; 31301544Seschrock uint64_t count; 31312676Seschrock zbookmark_t *zb = NULL; 31323444Sek110237 int i; 31331544Seschrock 31341544Seschrock /* 31351544Seschrock * Retrieve the raw error list from the kernel. If the number of errors 31361544Seschrock * has increased, allocate more space and continue until we get the 31371544Seschrock * entire list. 31381544Seschrock */ 31391544Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 31401544Seschrock &count) == 0); 31414820Sek110237 if (count == 0) 31424820Sek110237 return (0); 31432676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 31442856Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 31452082Seschrock return (-1); 31462676Seschrock zc.zc_nvlist_dst_size = count; 31471544Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 31481544Seschrock for (;;) { 31492082Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 31502082Seschrock &zc) != 0) { 31512676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 31521544Seschrock if (errno == ENOMEM) { 31533823Svb160487 count = zc.zc_nvlist_dst_size; 31542676Seschrock if ((zc.zc_nvlist_dst = (uintptr_t) 31553823Svb160487 zfs_alloc(zhp->zpool_hdl, count * 31563823Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 31572082Seschrock return (-1); 31581544Seschrock } else { 31591544Seschrock return (-1); 31601544Seschrock } 31611544Seschrock } else { 31621544Seschrock break; 31631544Seschrock } 31641544Seschrock } 31651544Seschrock 31661544Seschrock /* 31671544Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 31681544Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 31692676Seschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 31701544Seschrock * _not_ copied as part of the process. So we point the start of our 31711544Seschrock * array appropriate and decrement the total number of elements. 31721544Seschrock */ 31732676Seschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 31742676Seschrock zc.zc_nvlist_dst_size; 31752676Seschrock count -= zc.zc_nvlist_dst_size; 31761544Seschrock 31771544Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 31781544Seschrock 31793444Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 31801544Seschrock 31811544Seschrock /* 31823444Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 31831544Seschrock */ 31841544Seschrock for (i = 0; i < count; i++) { 31851544Seschrock nvlist_t *nv; 31861544Seschrock 31873700Sek110237 /* ignoring zb_blkid and zb_level for now */ 31883700Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 31893700Sek110237 zb[i-1].zb_object == zb[i].zb_object) 31901544Seschrock continue; 31911544Seschrock 31923444Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 31933444Sek110237 goto nomem; 31943444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 31953444Sek110237 zb[i].zb_objset) != 0) { 31963444Sek110237 nvlist_free(nv); 31972082Seschrock goto nomem; 31983444Sek110237 } 31993444Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 32003444Sek110237 zb[i].zb_object) != 0) { 32013444Sek110237 nvlist_free(nv); 32023444Sek110237 goto nomem; 32031544Seschrock } 32043444Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 32053444Sek110237 nvlist_free(nv); 32063444Sek110237 goto nomem; 32073444Sek110237 } 32083444Sek110237 nvlist_free(nv); 32091544Seschrock } 32101544Seschrock 32113265Sahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 32121544Seschrock return (0); 32132082Seschrock 32142082Seschrock nomem: 32152676Seschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 32162082Seschrock return (no_memory(zhp->zpool_hdl)); 32171544Seschrock } 32181760Seschrock 32191760Seschrock /* 32201760Seschrock * Upgrade a ZFS pool to the latest on-disk version. 32211760Seschrock */ 32221760Seschrock int 32235094Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 32241760Seschrock { 32251760Seschrock zfs_cmd_t zc = { 0 }; 32262082Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 32271760Seschrock 32281760Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 32295094Slling zc.zc_cookie = new_version; 32305094Slling 32314543Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 32323237Slling return (zpool_standard_error_fmt(hdl, errno, 32332082Seschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 32342082Seschrock zhp->zpool_name)); 32351760Seschrock return (0); 32361760Seschrock } 32372926Sek110237 32384988Sek110237 void 32394988Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 32404988Sek110237 char *history_str) 32414988Sek110237 { 32424988Sek110237 int i; 32434988Sek110237 32444988Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 32454988Sek110237 for (i = 1; i < argc; i++) { 32464988Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 32474988Sek110237 HIS_MAX_RECORD_LEN) 32484988Sek110237 break; 32494988Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 32504988Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 32514988Sek110237 } 32524988Sek110237 } 32534988Sek110237 32542926Sek110237 /* 32554988Sek110237 * Stage command history for logging. 32562926Sek110237 */ 32574988Sek110237 int 32584988Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 32592926Sek110237 { 32604988Sek110237 if (history_str == NULL) 32614988Sek110237 return (EINVAL); 32624988Sek110237 32634988Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 32644988Sek110237 return (EINVAL); 32652926Sek110237 32664715Sek110237 if (hdl->libzfs_log_str != NULL) 32674543Smarks free(hdl->libzfs_log_str); 32682926Sek110237 32694988Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 32704988Sek110237 return (no_memory(hdl)); 32714543Smarks 32724988Sek110237 return (0); 32732926Sek110237 } 32742926Sek110237 32752926Sek110237 /* 32762926Sek110237 * Perform ioctl to get some command history of a pool. 32772926Sek110237 * 32782926Sek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 32792926Sek110237 * logical offset of the history buffer to start reading from. 32802926Sek110237 * 32812926Sek110237 * Upon return, 'off' is the next logical offset to read from and 32822926Sek110237 * 'len' is the actual amount of bytes read into 'buf'. 32832926Sek110237 */ 32842926Sek110237 static int 32852926Sek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 32862926Sek110237 { 32872926Sek110237 zfs_cmd_t zc = { 0 }; 32882926Sek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 32892926Sek110237 32902926Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 32912926Sek110237 32922926Sek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 32932926Sek110237 zc.zc_history_len = *len; 32942926Sek110237 zc.zc_history_offset = *off; 32952926Sek110237 32962926Sek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 32972926Sek110237 switch (errno) { 32982926Sek110237 case EPERM: 32993237Slling return (zfs_error_fmt(hdl, EZFS_PERM, 33003237Slling dgettext(TEXT_DOMAIN, 33012926Sek110237 "cannot show history for pool '%s'"), 33022926Sek110237 zhp->zpool_name)); 33032926Sek110237 case ENOENT: 33043237Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 33052926Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 33062926Sek110237 "'%s'"), zhp->zpool_name)); 33073863Sek110237 case ENOTSUP: 33083863Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 33093863Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 33103863Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 33112926Sek110237 default: 33123237Slling return (zpool_standard_error_fmt(hdl, errno, 33132926Sek110237 dgettext(TEXT_DOMAIN, 33142926Sek110237 "cannot get history for '%s'"), zhp->zpool_name)); 33152926Sek110237 } 33162926Sek110237 } 33172926Sek110237 33182926Sek110237 *len = zc.zc_history_len; 33192926Sek110237 *off = zc.zc_history_offset; 33202926Sek110237 33212926Sek110237 return (0); 33222926Sek110237 } 33232926Sek110237 33242926Sek110237 /* 33252926Sek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 33262926Sek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 33272926Sek110237 * processed as there wasn't a complete record. 33282926Sek110237 */ 332910685SGeorge.Wilson@Sun.COM int 33302926Sek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 33312926Sek110237 nvlist_t ***records, uint_t *numrecords) 33322926Sek110237 { 33332926Sek110237 uint64_t reclen; 33342926Sek110237 nvlist_t *nv; 33352926Sek110237 int i; 33362926Sek110237 33372926Sek110237 while (bytes_read > sizeof (reclen)) { 33382926Sek110237 33392926Sek110237 /* get length of packed record (stored as little endian) */ 33402926Sek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 33412926Sek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 33422926Sek110237 33432926Sek110237 if (bytes_read < sizeof (reclen) + reclen) 33442926Sek110237 break; 33452926Sek110237 33462926Sek110237 /* unpack record */ 33472926Sek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 33482926Sek110237 return (ENOMEM); 33492926Sek110237 bytes_read -= sizeof (reclen) + reclen; 33502926Sek110237 buf += sizeof (reclen) + reclen; 33512926Sek110237 33522926Sek110237 /* add record to nvlist array */ 33532926Sek110237 (*numrecords)++; 33542926Sek110237 if (ISP2(*numrecords + 1)) { 33552926Sek110237 *records = realloc(*records, 33562926Sek110237 *numrecords * 2 * sizeof (nvlist_t *)); 33572926Sek110237 } 33582926Sek110237 (*records)[*numrecords - 1] = nv; 33592926Sek110237 } 33602926Sek110237 33612926Sek110237 *leftover = bytes_read; 33622926Sek110237 return (0); 33632926Sek110237 } 33642926Sek110237 33652926Sek110237 #define HIS_BUF_LEN (128*1024) 33662926Sek110237 33672926Sek110237 /* 33682926Sek110237 * Retrieve the command history of a pool. 33692926Sek110237 */ 33702926Sek110237 int 33712926Sek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 33722926Sek110237 { 33732926Sek110237 char buf[HIS_BUF_LEN]; 33742926Sek110237 uint64_t off = 0; 33752926Sek110237 nvlist_t **records = NULL; 33762926Sek110237 uint_t numrecords = 0; 33772926Sek110237 int err, i; 33782926Sek110237 33792926Sek110237 do { 33802926Sek110237 uint64_t bytes_read = sizeof (buf); 33812926Sek110237 uint64_t leftover; 33822926Sek110237 33832926Sek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 33842926Sek110237 break; 33852926Sek110237 33862926Sek110237 /* if nothing else was read in, we're at EOF, just return */ 33872926Sek110237 if (!bytes_read) 33882926Sek110237 break; 33892926Sek110237 33902926Sek110237 if ((err = zpool_history_unpack(buf, bytes_read, 33912926Sek110237 &leftover, &records, &numrecords)) != 0) 33922926Sek110237 break; 33932926Sek110237 off -= leftover; 33942926Sek110237 33952926Sek110237 /* CONSTCOND */ 33962926Sek110237 } while (1); 33972926Sek110237 33982926Sek110237 if (!err) { 33992926Sek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 34002926Sek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 34012926Sek110237 records, numrecords) == 0); 34022926Sek110237 } 34032926Sek110237 for (i = 0; i < numrecords; i++) 34042926Sek110237 nvlist_free(records[i]); 34052926Sek110237 free(records); 34062926Sek110237 34072926Sek110237 return (err); 34082926Sek110237 } 34093444Sek110237 34103444Sek110237 void 34113444Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 34123444Sek110237 char *pathname, size_t len) 34133444Sek110237 { 34143444Sek110237 zfs_cmd_t zc = { 0 }; 34153444Sek110237 boolean_t mounted = B_FALSE; 34163444Sek110237 char *mntpnt = NULL; 34173444Sek110237 char dsname[MAXNAMELEN]; 34183444Sek110237 34193444Sek110237 if (dsobj == 0) { 34203444Sek110237 /* special case for the MOS */ 34213444Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 34223444Sek110237 return; 34233444Sek110237 } 34243444Sek110237 34253444Sek110237 /* get the dataset's name */ 34263444Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 34273444Sek110237 zc.zc_obj = dsobj; 34283444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 34293444Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 34303444Sek110237 /* just write out a path of two object numbers */ 34313444Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 34323444Sek110237 dsobj, obj); 34333444Sek110237 return; 34343444Sek110237 } 34353444Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 34363444Sek110237 34373444Sek110237 /* find out if the dataset is mounted */ 34383444Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 34393444Sek110237 34403444Sek110237 /* get the corrupted object's path */ 34413444Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 34423444Sek110237 zc.zc_obj = obj; 34433444Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 34443444Sek110237 &zc) == 0) { 34453444Sek110237 if (mounted) { 34463444Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 34473444Sek110237 zc.zc_value); 34483444Sek110237 } else { 34493444Sek110237 (void) snprintf(pathname, len, "%s:%s", 34503444Sek110237 dsname, zc.zc_value); 34513444Sek110237 } 34523444Sek110237 } else { 34533444Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 34543444Sek110237 } 34553444Sek110237 free(mntpnt); 34563444Sek110237 } 34573912Slling 34584276Staylor /* 34597042Sgw25295 * Read the EFI label from the config, if a label does not exist then 34607042Sgw25295 * pass back the error to the caller. If the caller has passed a non-NULL 34617042Sgw25295 * diskaddr argument then we set it to the starting address of the EFI 34627042Sgw25295 * partition. 34637042Sgw25295 */ 34647042Sgw25295 static int 34657042Sgw25295 read_efi_label(nvlist_t *config, diskaddr_t *sb) 34667042Sgw25295 { 34677042Sgw25295 char *path; 34687042Sgw25295 int fd; 34697042Sgw25295 char diskname[MAXPATHLEN]; 34707042Sgw25295 int err = -1; 34717042Sgw25295 34727042Sgw25295 if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 34737042Sgw25295 return (err); 34747042Sgw25295 34757042Sgw25295 (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 34767042Sgw25295 strrchr(path, '/')); 34777042Sgw25295 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 34787042Sgw25295 struct dk_gpt *vtoc; 34797042Sgw25295 34807042Sgw25295 if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 34817042Sgw25295 if (sb != NULL) 34827042Sgw25295 *sb = vtoc->efi_parts[0].p_start; 34837042Sgw25295 efi_free(vtoc); 34847042Sgw25295 } 34857042Sgw25295 (void) close(fd); 34867042Sgw25295 } 34877042Sgw25295 return (err); 34887042Sgw25295 } 34897042Sgw25295 34907042Sgw25295 /* 34914276Staylor * determine where a partition starts on a disk in the current 34924276Staylor * configuration 34934276Staylor */ 34944276Staylor static diskaddr_t 34954276Staylor find_start_block(nvlist_t *config) 34964276Staylor { 34974276Staylor nvlist_t **child; 34984276Staylor uint_t c, children; 34994276Staylor diskaddr_t sb = MAXOFFSET_T; 35004276Staylor uint64_t wholedisk; 35014276Staylor 35024276Staylor if (nvlist_lookup_nvlist_array(config, 35034276Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 35044276Staylor if (nvlist_lookup_uint64(config, 35054276Staylor ZPOOL_CONFIG_WHOLE_DISK, 35064276Staylor &wholedisk) != 0 || !wholedisk) { 35074276Staylor return (MAXOFFSET_T); 35084276Staylor } 35097042Sgw25295 if (read_efi_label(config, &sb) < 0) 35107042Sgw25295 sb = MAXOFFSET_T; 35114276Staylor return (sb); 35124276Staylor } 35134276Staylor 35144276Staylor for (c = 0; c < children; c++) { 35154276Staylor sb = find_start_block(child[c]); 35164276Staylor if (sb != MAXOFFSET_T) { 35174276Staylor return (sb); 35184276Staylor } 35194276Staylor } 35204276Staylor return (MAXOFFSET_T); 35214276Staylor } 35224276Staylor 35234276Staylor /* 35244276Staylor * Label an individual disk. The name provided is the short name, 35254276Staylor * stripped of any leading /dev path. 35264276Staylor */ 35274276Staylor int 35284276Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 35294276Staylor { 35304276Staylor char path[MAXPATHLEN]; 35314276Staylor struct dk_gpt *vtoc; 35324276Staylor int fd; 35334276Staylor size_t resv = EFI_MIN_RESV_SIZE; 35344276Staylor uint64_t slice_size; 35354276Staylor diskaddr_t start_block; 35364276Staylor char errbuf[1024]; 35374276Staylor 35386289Smmusante /* prepare an error message just in case */ 35396289Smmusante (void) snprintf(errbuf, sizeof (errbuf), 35406289Smmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 35416289Smmusante 35424276Staylor if (zhp) { 35434276Staylor nvlist_t *nvroot; 35444276Staylor 35457965SGeorge.Wilson@Sun.COM if (pool_is_bootable(zhp)) { 35467965SGeorge.Wilson@Sun.COM zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35477965SGeorge.Wilson@Sun.COM "EFI labeled devices are not supported on root " 35487965SGeorge.Wilson@Sun.COM "pools.")); 35497965SGeorge.Wilson@Sun.COM return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 35507965SGeorge.Wilson@Sun.COM } 35517965SGeorge.Wilson@Sun.COM 35524276Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 35534276Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 35544276Staylor 35554276Staylor if (zhp->zpool_start_block == 0) 35564276Staylor start_block = find_start_block(nvroot); 35574276Staylor else 35584276Staylor start_block = zhp->zpool_start_block; 35594276Staylor zhp->zpool_start_block = start_block; 35604276Staylor } else { 35614276Staylor /* new pool */ 35624276Staylor start_block = NEW_START_BLOCK; 35634276Staylor } 35644276Staylor 35654276Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 35664276Staylor BACKUP_SLICE); 35674276Staylor 35684276Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 35694276Staylor /* 35704276Staylor * This shouldn't happen. We've long since verified that this 35714276Staylor * is a valid device. 35724276Staylor */ 35736289Smmusante zfs_error_aux(hdl, 35746289Smmusante dgettext(TEXT_DOMAIN, "unable to open device")); 35754276Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 35764276Staylor } 35774276Staylor 35784276Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 35794276Staylor /* 35804276Staylor * The only way this can fail is if we run out of memory, or we 35814276Staylor * were unable to read the disk's capacity 35824276Staylor */ 35834276Staylor if (errno == ENOMEM) 35844276Staylor (void) no_memory(hdl); 35854276Staylor 35864276Staylor (void) close(fd); 35876289Smmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35886289Smmusante "unable to read disk capacity"), name); 35894276Staylor 35904276Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 35914276Staylor } 35924276Staylor 35934276Staylor slice_size = vtoc->efi_last_u_lba + 1; 35944276Staylor slice_size -= EFI_MIN_RESV_SIZE; 35954276Staylor if (start_block == MAXOFFSET_T) 35964276Staylor start_block = NEW_START_BLOCK; 35974276Staylor slice_size -= start_block; 35984276Staylor 35994276Staylor vtoc->efi_parts[0].p_start = start_block; 36004276Staylor vtoc->efi_parts[0].p_size = slice_size; 36014276Staylor 36024276Staylor /* 36034276Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 36044276Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 36054276Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 36064276Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 36074276Staylor * etc. were all pretty specific. V_USR is as close to reality as we 36084276Staylor * can get, in the absence of V_OTHER. 36094276Staylor */ 36104276Staylor vtoc->efi_parts[0].p_tag = V_USR; 36114276Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 36124276Staylor 36134276Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 36144276Staylor vtoc->efi_parts[8].p_size = resv; 36154276Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 36164276Staylor 36174276Staylor if (efi_write(fd, vtoc) != 0) { 36184276Staylor /* 36194276Staylor * Some block drivers (like pcata) may not support EFI 36204276Staylor * GPT labels. Print out a helpful error message dir- 36214276Staylor * ecting the user to manually label the disk and give 36224276Staylor * a specific slice. 36234276Staylor */ 36244276Staylor (void) close(fd); 36254276Staylor efi_free(vtoc); 36264276Staylor 36274276Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36286289Smmusante "try using fdisk(1M) and then provide a specific slice")); 36294276Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 36304276Staylor } 36314276Staylor 36324276Staylor (void) close(fd); 36334276Staylor efi_free(vtoc); 36344276Staylor return (0); 36354276Staylor } 36366423Sgw25295 36376423Sgw25295 static boolean_t 36386423Sgw25295 supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 36396423Sgw25295 { 36406423Sgw25295 char *type; 36416423Sgw25295 nvlist_t **child; 36426423Sgw25295 uint_t children, c; 36436423Sgw25295 36446423Sgw25295 verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 36456423Sgw25295 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 36466423Sgw25295 strcmp(type, VDEV_TYPE_FILE) == 0 || 36476423Sgw25295 strcmp(type, VDEV_TYPE_LOG) == 0 || 364810594SGeorge.Wilson@Sun.COM strcmp(type, VDEV_TYPE_HOLE) == 0 || 36496423Sgw25295 strcmp(type, VDEV_TYPE_MISSING) == 0) { 36506423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36516423Sgw25295 "vdev type '%s' is not supported"), type); 36526423Sgw25295 (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 36536423Sgw25295 return (B_FALSE); 36546423Sgw25295 } 36556423Sgw25295 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 36566423Sgw25295 &child, &children) == 0) { 36576423Sgw25295 for (c = 0; c < children; c++) { 36586423Sgw25295 if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 36596423Sgw25295 return (B_FALSE); 36606423Sgw25295 } 36616423Sgw25295 } 36626423Sgw25295 return (B_TRUE); 36636423Sgw25295 } 36646423Sgw25295 36656423Sgw25295 /* 36666423Sgw25295 * check if this zvol is allowable for use as a dump device; zero if 36676423Sgw25295 * it is, > 0 if it isn't, < 0 if it isn't a zvol 36686423Sgw25295 */ 36696423Sgw25295 int 36706423Sgw25295 zvol_check_dump_config(char *arg) 36716423Sgw25295 { 36726423Sgw25295 zpool_handle_t *zhp = NULL; 36736423Sgw25295 nvlist_t *config, *nvroot; 36746423Sgw25295 char *p, *volname; 36756423Sgw25295 nvlist_t **top; 36766423Sgw25295 uint_t toplevels; 36776423Sgw25295 libzfs_handle_t *hdl; 36786423Sgw25295 char errbuf[1024]; 36796423Sgw25295 char poolname[ZPOOL_MAXNAMELEN]; 36806423Sgw25295 int pathlen = strlen(ZVOL_FULL_DEV_DIR); 36816423Sgw25295 int ret = 1; 36826423Sgw25295 36836423Sgw25295 if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 36846423Sgw25295 return (-1); 36856423Sgw25295 } 36866423Sgw25295 36876423Sgw25295 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 36886423Sgw25295 "dump is not supported on device '%s'"), arg); 36896423Sgw25295 36906423Sgw25295 if ((hdl = libzfs_init()) == NULL) 36916423Sgw25295 return (1); 36926423Sgw25295 libzfs_print_on_error(hdl, B_TRUE); 36936423Sgw25295 36946423Sgw25295 volname = arg + pathlen; 36956423Sgw25295 36966423Sgw25295 /* check the configuration of the pool */ 36976423Sgw25295 if ((p = strchr(volname, '/')) == NULL) { 36986423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36996423Sgw25295 "malformed dataset name")); 37006423Sgw25295 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 37016423Sgw25295 return (1); 37026423Sgw25295 } else if (p - volname >= ZFS_MAXNAMELEN) { 37036423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37046423Sgw25295 "dataset name is too long")); 37056423Sgw25295 (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 37066423Sgw25295 return (1); 37076423Sgw25295 } else { 37086423Sgw25295 (void) strncpy(poolname, volname, p - volname); 37096423Sgw25295 poolname[p - volname] = '\0'; 37106423Sgw25295 } 37116423Sgw25295 37126423Sgw25295 if ((zhp = zpool_open(hdl, poolname)) == NULL) { 37136423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37146423Sgw25295 "could not open pool '%s'"), poolname); 37156423Sgw25295 (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 37166423Sgw25295 goto out; 37176423Sgw25295 } 37186423Sgw25295 config = zpool_get_config(zhp, NULL); 37196423Sgw25295 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 37206423Sgw25295 &nvroot) != 0) { 37216423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37226423Sgw25295 "could not obtain vdev configuration for '%s'"), poolname); 37236423Sgw25295 (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 37246423Sgw25295 goto out; 37256423Sgw25295 } 37266423Sgw25295 37276423Sgw25295 verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 37286423Sgw25295 &top, &toplevels) == 0); 37296423Sgw25295 if (toplevels != 1) { 37306423Sgw25295 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 37316423Sgw25295 "'%s' has multiple top level vdevs"), poolname); 37326423Sgw25295 (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 37336423Sgw25295 goto out; 37346423Sgw25295 } 37356423Sgw25295 37366423Sgw25295 if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 37376423Sgw25295 goto out; 37386423Sgw25295 } 37396423Sgw25295 ret = 0; 37406423Sgw25295 37416423Sgw25295 out: 37426423Sgw25295 if (zhp) 37436423Sgw25295 zpool_close(zhp); 37446423Sgw25295 libzfs_fini(hdl); 37456423Sgw25295 return (ret); 37466423Sgw25295 } 3747