1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 23c6ef114fSmmusante * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27f3861e1aSahl #include <alloca.h> 28fa9e4066Sahrens #include <assert.h> 29fa9e4066Sahrens #include <ctype.h> 30fa9e4066Sahrens #include <errno.h> 31fa9e4066Sahrens #include <devid.h> 32f3861e1aSahl #include <dirent.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libintl.h> 35fa9e4066Sahrens #include <stdio.h> 36fa9e4066Sahrens #include <stdlib.h> 37f3861e1aSahl #include <strings.h> 38fa9e4066Sahrens #include <unistd.h> 390a48a24eStimh #include <zone.h> 408488aeb5Staylor #include <sys/efi_partition.h> 418488aeb5Staylor #include <sys/vtoc.h> 42fa9e4066Sahrens #include <sys/zfs_ioctl.h> 43ea8dc4b6Seschrock #include <sys/zio.h> 4406eeb2adSek #include <strings.h> 45fa9e4066Sahrens 46fa9e4066Sahrens #include "zfs_namecheck.h" 47b1b8ab34Slling #include "zfs_prop.h" 48fa9e4066Sahrens #include "libzfs_impl.h" 49fa9e4066Sahrens 5015e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 51990b4856Slling 52*b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64) 53*b5b76fecSGeorge Wilson #define BOOTCMD "installgrub(1M)" 54*b5b76fecSGeorge Wilson #else 55*b5b76fecSGeorge Wilson #define BOOTCMD "installboot(1M)" 56*b5b76fecSGeorge Wilson #endif 57*b5b76fecSGeorge Wilson 58990b4856Slling /* 59990b4856Slling * ==================================================================== 60990b4856Slling * zpool property functions 61990b4856Slling * ==================================================================== 62990b4856Slling */ 63990b4856Slling 64990b4856Slling static int 65990b4856Slling zpool_get_all_props(zpool_handle_t *zhp) 66990b4856Slling { 67990b4856Slling zfs_cmd_t zc = { 0 }; 68990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 69990b4856Slling 70990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 71990b4856Slling 72990b4856Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 73990b4856Slling return (-1); 74990b4856Slling 75990b4856Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 76990b4856Slling if (errno == ENOMEM) { 77990b4856Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 78990b4856Slling zcmd_free_nvlists(&zc); 79990b4856Slling return (-1); 80990b4856Slling } 81990b4856Slling } else { 82990b4856Slling zcmd_free_nvlists(&zc); 83990b4856Slling return (-1); 84990b4856Slling } 85990b4856Slling } 86990b4856Slling 87990b4856Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 88990b4856Slling zcmd_free_nvlists(&zc); 89990b4856Slling return (-1); 90990b4856Slling } 91990b4856Slling 92990b4856Slling zcmd_free_nvlists(&zc); 93990b4856Slling 94990b4856Slling return (0); 95990b4856Slling } 96990b4856Slling 97990b4856Slling static int 98990b4856Slling zpool_props_refresh(zpool_handle_t *zhp) 99990b4856Slling { 100990b4856Slling nvlist_t *old_props; 101990b4856Slling 102990b4856Slling old_props = zhp->zpool_props; 103990b4856Slling 104990b4856Slling if (zpool_get_all_props(zhp) != 0) 105990b4856Slling return (-1); 106990b4856Slling 107990b4856Slling nvlist_free(old_props); 108990b4856Slling return (0); 109990b4856Slling } 110990b4856Slling 111990b4856Slling static char * 112990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 113990b4856Slling zprop_source_t *src) 114990b4856Slling { 115990b4856Slling nvlist_t *nv, *nvl; 116990b4856Slling uint64_t ival; 117990b4856Slling char *value; 118990b4856Slling zprop_source_t source; 119990b4856Slling 120990b4856Slling nvl = zhp->zpool_props; 121990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 122990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 123990b4856Slling source = ival; 124990b4856Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 125990b4856Slling } else { 126990b4856Slling source = ZPROP_SRC_DEFAULT; 127990b4856Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 128990b4856Slling value = "-"; 129990b4856Slling } 130990b4856Slling 131990b4856Slling if (src) 132990b4856Slling *src = source; 133990b4856Slling 134990b4856Slling return (value); 135990b4856Slling } 136990b4856Slling 137990b4856Slling uint64_t 138990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 139990b4856Slling { 140990b4856Slling nvlist_t *nv, *nvl; 141990b4856Slling uint64_t value; 142990b4856Slling zprop_source_t source; 143990b4856Slling 144b87f3af3Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 145b87f3af3Sperrin /* 146b87f3af3Sperrin * zpool_get_all_props() has most likely failed because 147b87f3af3Sperrin * the pool is faulted, but if all we need is the top level 148b87f3af3Sperrin * vdev's guid then get it from the zhp config nvlist. 149b87f3af3Sperrin */ 150b87f3af3Sperrin if ((prop == ZPOOL_PROP_GUID) && 151b87f3af3Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 152b87f3af3Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 153b87f3af3Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 154b87f3af3Sperrin == 0)) { 155b87f3af3Sperrin return (value); 156b87f3af3Sperrin } 157990b4856Slling return (zpool_prop_default_numeric(prop)); 158b87f3af3Sperrin } 159990b4856Slling 160990b4856Slling nvl = zhp->zpool_props; 161990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 162990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 163990b4856Slling source = value; 164990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 165990b4856Slling } else { 166990b4856Slling source = ZPROP_SRC_DEFAULT; 167990b4856Slling value = zpool_prop_default_numeric(prop); 168990b4856Slling } 169990b4856Slling 170990b4856Slling if (src) 171990b4856Slling *src = source; 172990b4856Slling 173990b4856Slling return (value); 174990b4856Slling } 175990b4856Slling 176990b4856Slling /* 177990b4856Slling * Map VDEV STATE to printed strings. 178990b4856Slling */ 179990b4856Slling char * 180990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 181990b4856Slling { 182990b4856Slling switch (state) { 183990b4856Slling case VDEV_STATE_CLOSED: 184990b4856Slling case VDEV_STATE_OFFLINE: 185990b4856Slling return (gettext("OFFLINE")); 186990b4856Slling case VDEV_STATE_REMOVED: 187990b4856Slling return (gettext("REMOVED")); 188990b4856Slling case VDEV_STATE_CANT_OPEN: 189b87f3af3Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 190990b4856Slling return (gettext("FAULTED")); 191990b4856Slling else 192990b4856Slling return (gettext("UNAVAIL")); 193990b4856Slling case VDEV_STATE_FAULTED: 194990b4856Slling return (gettext("FAULTED")); 195990b4856Slling case VDEV_STATE_DEGRADED: 196990b4856Slling return (gettext("DEGRADED")); 197990b4856Slling case VDEV_STATE_HEALTHY: 198990b4856Slling return (gettext("ONLINE")); 199990b4856Slling } 200990b4856Slling 201990b4856Slling return (gettext("UNKNOWN")); 202990b4856Slling } 203990b4856Slling 204990b4856Slling /* 205990b4856Slling * Get a zpool property value for 'prop' and return the value in 206990b4856Slling * a pre-allocated buffer. 207990b4856Slling */ 208990b4856Slling int 209990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 210990b4856Slling zprop_source_t *srctype) 211990b4856Slling { 212990b4856Slling uint64_t intval; 213990b4856Slling const char *strval; 214990b4856Slling zprop_source_t src = ZPROP_SRC_NONE; 215990b4856Slling nvlist_t *nvroot; 216990b4856Slling vdev_stat_t *vs; 217990b4856Slling uint_t vsc; 218990b4856Slling 219990b4856Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 220990b4856Slling if (prop == ZPOOL_PROP_NAME) 221990b4856Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 222990b4856Slling else if (prop == ZPOOL_PROP_HEALTH) 223990b4856Slling (void) strlcpy(buf, "FAULTED", len); 224990b4856Slling else 225990b4856Slling (void) strlcpy(buf, "-", len); 226990b4856Slling return (0); 227990b4856Slling } 228990b4856Slling 229990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 230990b4856Slling prop != ZPOOL_PROP_NAME) 231990b4856Slling return (-1); 232990b4856Slling 233990b4856Slling switch (zpool_prop_get_type(prop)) { 234990b4856Slling case PROP_TYPE_STRING: 235990b4856Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 236990b4856Slling len); 237990b4856Slling break; 238990b4856Slling 239990b4856Slling case PROP_TYPE_NUMBER: 240990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 241990b4856Slling 242990b4856Slling switch (prop) { 243990b4856Slling case ZPOOL_PROP_SIZE: 244990b4856Slling case ZPOOL_PROP_USED: 245990b4856Slling case ZPOOL_PROP_AVAILABLE: 246990b4856Slling (void) zfs_nicenum(intval, buf, len); 247990b4856Slling break; 248990b4856Slling 249990b4856Slling case ZPOOL_PROP_CAPACITY: 250990b4856Slling (void) snprintf(buf, len, "%llu%%", 251990b4856Slling (u_longlong_t)intval); 252990b4856Slling break; 253990b4856Slling 254990b4856Slling case ZPOOL_PROP_HEALTH: 255990b4856Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 256990b4856Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 257990b4856Slling verify(nvlist_lookup_uint64_array(nvroot, 258990b4856Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 259990b4856Slling 260990b4856Slling (void) strlcpy(buf, zpool_state_to_name(intval, 261990b4856Slling vs->vs_aux), len); 262990b4856Slling break; 263990b4856Slling default: 264990b4856Slling (void) snprintf(buf, len, "%llu", intval); 265990b4856Slling } 266990b4856Slling break; 267990b4856Slling 268990b4856Slling case PROP_TYPE_INDEX: 269990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 270990b4856Slling if (zpool_prop_index_to_string(prop, intval, &strval) 271990b4856Slling != 0) 272990b4856Slling return (-1); 273990b4856Slling (void) strlcpy(buf, strval, len); 274990b4856Slling break; 275990b4856Slling 276990b4856Slling default: 277990b4856Slling abort(); 278990b4856Slling } 279990b4856Slling 280990b4856Slling if (srctype) 281990b4856Slling *srctype = src; 282990b4856Slling 283990b4856Slling return (0); 284990b4856Slling } 285990b4856Slling 286990b4856Slling /* 287990b4856Slling * Check if the bootfs name has the same pool name as it is set to. 288990b4856Slling * Assuming bootfs is a valid dataset name. 289990b4856Slling */ 290990b4856Slling static boolean_t 291990b4856Slling bootfs_name_valid(const char *pool, char *bootfs) 292990b4856Slling { 293990b4856Slling int len = strlen(pool); 294990b4856Slling 295fe3e2633SEric Taylor if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 296990b4856Slling return (B_FALSE); 297990b4856Slling 298990b4856Slling if (strncmp(pool, bootfs, len) == 0 && 299990b4856Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 300990b4856Slling return (B_TRUE); 301990b4856Slling 302990b4856Slling return (B_FALSE); 303990b4856Slling } 304990b4856Slling 30515e6edf1Sgw /* 30615e6edf1Sgw * Inspect the configuration to determine if any of the devices contain 30715e6edf1Sgw * an EFI label. 30815e6edf1Sgw */ 30915e6edf1Sgw static boolean_t 31015e6edf1Sgw pool_uses_efi(nvlist_t *config) 31115e6edf1Sgw { 31215e6edf1Sgw nvlist_t **child; 31315e6edf1Sgw uint_t c, children; 31415e6edf1Sgw 31515e6edf1Sgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 31615e6edf1Sgw &child, &children) != 0) 31715e6edf1Sgw return (read_efi_label(config, NULL) >= 0); 31815e6edf1Sgw 31915e6edf1Sgw for (c = 0; c < children; c++) { 32015e6edf1Sgw if (pool_uses_efi(child[c])) 32115e6edf1Sgw return (B_TRUE); 32215e6edf1Sgw } 32315e6edf1Sgw return (B_FALSE); 32415e6edf1Sgw } 32515e6edf1Sgw 326*b5b76fecSGeorge Wilson static boolean_t 327*b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp) 328*b5b76fecSGeorge Wilson { 329*b5b76fecSGeorge Wilson char bootfs[ZPOOL_MAXNAMELEN]; 330*b5b76fecSGeorge Wilson 331*b5b76fecSGeorge Wilson return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 332*b5b76fecSGeorge Wilson sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 333*b5b76fecSGeorge Wilson sizeof (bootfs)) != 0); 334*b5b76fecSGeorge Wilson } 335*b5b76fecSGeorge Wilson 336*b5b76fecSGeorge Wilson 337990b4856Slling /* 338990b4856Slling * Given an nvlist of zpool properties to be set, validate that they are 339990b4856Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 340990b4856Slling * specified as strings. 341990b4856Slling */ 342990b4856Slling static nvlist_t * 3430a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 344990b4856Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 345990b4856Slling { 346990b4856Slling nvpair_t *elem; 347990b4856Slling nvlist_t *retprops; 348990b4856Slling zpool_prop_t prop; 349990b4856Slling char *strval; 350990b4856Slling uint64_t intval; 3512f8aaab3Seschrock char *slash; 3522f8aaab3Seschrock struct stat64 statbuf; 35315e6edf1Sgw zpool_handle_t *zhp; 35415e6edf1Sgw nvlist_t *nvroot; 355990b4856Slling 356990b4856Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 357990b4856Slling (void) no_memory(hdl); 358990b4856Slling return (NULL); 359990b4856Slling } 360990b4856Slling 361990b4856Slling elem = NULL; 362990b4856Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 363990b4856Slling const char *propname = nvpair_name(elem); 364990b4856Slling 365990b4856Slling /* 366990b4856Slling * Make sure this property is valid and applies to this type. 367990b4856Slling */ 368990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 369990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 370990b4856Slling "invalid property '%s'"), propname); 371990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 372990b4856Slling goto error; 373990b4856Slling } 374990b4856Slling 375990b4856Slling if (zpool_prop_readonly(prop)) { 376990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 377990b4856Slling "is readonly"), propname); 378990b4856Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 379990b4856Slling goto error; 380990b4856Slling } 381990b4856Slling 382990b4856Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 383990b4856Slling &strval, &intval, errbuf) != 0) 384990b4856Slling goto error; 385990b4856Slling 386990b4856Slling /* 387990b4856Slling * Perform additional checking for specific properties. 388990b4856Slling */ 389990b4856Slling switch (prop) { 390990b4856Slling case ZPOOL_PROP_VERSION: 391990b4856Slling if (intval < version || intval > SPA_VERSION) { 392990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 393990b4856Slling "property '%s' number %d is invalid."), 394990b4856Slling propname, intval); 395990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 396990b4856Slling goto error; 397990b4856Slling } 398990b4856Slling break; 399990b4856Slling 400990b4856Slling case ZPOOL_PROP_BOOTFS: 401990b4856Slling if (create_or_import) { 402990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 403990b4856Slling "property '%s' cannot be set at creation " 404990b4856Slling "or import time"), propname); 405990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 406990b4856Slling goto error; 407990b4856Slling } 408990b4856Slling 409990b4856Slling if (version < SPA_VERSION_BOOTFS) { 410990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 411990b4856Slling "pool must be upgraded to support " 412990b4856Slling "'%s' property"), propname); 413990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 414990b4856Slling goto error; 415990b4856Slling } 416990b4856Slling 417990b4856Slling /* 418990b4856Slling * bootfs property value has to be a dataset name and 419990b4856Slling * the dataset has to be in the same pool as it sets to. 420990b4856Slling */ 421990b4856Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 422990b4856Slling strval)) { 423990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 424990b4856Slling "is an invalid name"), strval); 425990b4856Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 426990b4856Slling goto error; 427990b4856Slling } 42815e6edf1Sgw 42915e6edf1Sgw if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 43015e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 43115e6edf1Sgw "could not open pool '%s'"), poolname); 43215e6edf1Sgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 43315e6edf1Sgw goto error; 43415e6edf1Sgw } 43515e6edf1Sgw verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 43615e6edf1Sgw ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 43715e6edf1Sgw 43815e6edf1Sgw /* 43915e6edf1Sgw * bootfs property cannot be set on a disk which has 44015e6edf1Sgw * been EFI labeled. 44115e6edf1Sgw */ 44215e6edf1Sgw if (pool_uses_efi(nvroot)) { 44315e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 44415e6edf1Sgw "property '%s' not supported on " 44515e6edf1Sgw "EFI labeled devices"), propname); 44615e6edf1Sgw (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 44715e6edf1Sgw zpool_close(zhp); 44815e6edf1Sgw goto error; 44915e6edf1Sgw } 45015e6edf1Sgw zpool_close(zhp); 451990b4856Slling break; 452990b4856Slling 4532f8aaab3Seschrock case ZPOOL_PROP_ALTROOT: 454990b4856Slling if (!create_or_import) { 455990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 456990b4856Slling "property '%s' can only be set during pool " 457990b4856Slling "creation or import"), propname); 458990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 459990b4856Slling goto error; 460990b4856Slling } 461990b4856Slling 4622f8aaab3Seschrock if (strval[0] != '/') { 463990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4642f8aaab3Seschrock "bad alternate root '%s'"), strval); 4652f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 466990b4856Slling goto error; 467990b4856Slling } 4682f8aaab3Seschrock break; 4692f8aaab3Seschrock 4702f8aaab3Seschrock case ZPOOL_PROP_CACHEFILE: 4712f8aaab3Seschrock if (strval[0] == '\0') 4722f8aaab3Seschrock break; 4732f8aaab3Seschrock 4742f8aaab3Seschrock if (strcmp(strval, "none") == 0) 4752f8aaab3Seschrock break; 476990b4856Slling 477990b4856Slling if (strval[0] != '/') { 478990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4792f8aaab3Seschrock "property '%s' must be empty, an " 4802f8aaab3Seschrock "absolute path, or 'none'"), propname); 481990b4856Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 482990b4856Slling goto error; 483990b4856Slling } 484990b4856Slling 4852f8aaab3Seschrock slash = strrchr(strval, '/'); 486990b4856Slling 4872f8aaab3Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 4882f8aaab3Seschrock strcmp(slash, "/..") == 0) { 4892f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4902f8aaab3Seschrock "'%s' is not a valid file"), strval); 4912f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 4922f8aaab3Seschrock goto error; 4932f8aaab3Seschrock } 494990b4856Slling 4952f8aaab3Seschrock *slash = '\0'; 4962f8aaab3Seschrock 4972c32020fSeschrock if (strval[0] != '\0' && 4982c32020fSeschrock (stat64(strval, &statbuf) != 0 || 4992c32020fSeschrock !S_ISDIR(statbuf.st_mode))) { 5002f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5012f8aaab3Seschrock "'%s' is not a valid directory"), 5022f8aaab3Seschrock strval); 5032f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5042f8aaab3Seschrock goto error; 5052f8aaab3Seschrock } 5062f8aaab3Seschrock 5072f8aaab3Seschrock *slash = '/'; 5082f8aaab3Seschrock break; 509990b4856Slling } 510990b4856Slling } 511990b4856Slling 512990b4856Slling return (retprops); 513990b4856Slling error: 514990b4856Slling nvlist_free(retprops); 515990b4856Slling return (NULL); 516990b4856Slling } 517990b4856Slling 518990b4856Slling /* 519990b4856Slling * Set zpool property : propname=propval. 520990b4856Slling */ 521990b4856Slling int 522990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 523990b4856Slling { 524990b4856Slling zfs_cmd_t zc = { 0 }; 525990b4856Slling int ret = -1; 526990b4856Slling char errbuf[1024]; 527990b4856Slling nvlist_t *nvl = NULL; 528990b4856Slling nvlist_t *realprops; 529990b4856Slling uint64_t version; 530990b4856Slling 531990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), 532990b4856Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 533990b4856Slling zhp->zpool_name); 534990b4856Slling 535990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) 536990b4856Slling return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, errbuf)); 537990b4856Slling 538990b4856Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 539990b4856Slling return (no_memory(zhp->zpool_hdl)); 540990b4856Slling 541990b4856Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 542990b4856Slling nvlist_free(nvl); 543990b4856Slling return (no_memory(zhp->zpool_hdl)); 544990b4856Slling } 545990b4856Slling 546990b4856Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5470a48a24eStimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 548990b4856Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 549990b4856Slling nvlist_free(nvl); 550990b4856Slling return (-1); 551990b4856Slling } 552990b4856Slling 553990b4856Slling nvlist_free(nvl); 554990b4856Slling nvl = realprops; 555990b4856Slling 556990b4856Slling /* 557990b4856Slling * Execute the corresponding ioctl() to set this property. 558990b4856Slling */ 559990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 560990b4856Slling 561990b4856Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 562990b4856Slling nvlist_free(nvl); 563990b4856Slling return (-1); 564990b4856Slling } 565990b4856Slling 566990b4856Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 567990b4856Slling 568990b4856Slling zcmd_free_nvlists(&zc); 569990b4856Slling nvlist_free(nvl); 570990b4856Slling 571990b4856Slling if (ret) 572990b4856Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 573990b4856Slling else 574990b4856Slling (void) zpool_props_refresh(zhp); 575990b4856Slling 576990b4856Slling return (ret); 577990b4856Slling } 578990b4856Slling 579990b4856Slling int 580990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 581990b4856Slling { 582990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 583990b4856Slling zprop_list_t *entry; 584990b4856Slling char buf[ZFS_MAXPROPLEN]; 585990b4856Slling 586990b4856Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 587990b4856Slling return (-1); 588990b4856Slling 589990b4856Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 590990b4856Slling 591990b4856Slling if (entry->pl_fixed) 592990b4856Slling continue; 593990b4856Slling 594990b4856Slling if (entry->pl_prop != ZPROP_INVAL && 595990b4856Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 596990b4856Slling NULL) == 0) { 597990b4856Slling if (strlen(buf) > entry->pl_width) 598990b4856Slling entry->pl_width = strlen(buf); 599990b4856Slling } 600990b4856Slling } 601990b4856Slling 602990b4856Slling return (0); 603990b4856Slling } 604990b4856Slling 605990b4856Slling 606fa9e4066Sahrens /* 607fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 608fa9e4066Sahrens * 'buf'. 609fa9e4066Sahrens */ 610e7cbe64fSgw boolean_t 61199653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 612fa9e4066Sahrens { 613fa9e4066Sahrens namecheck_err_t why; 614fa9e4066Sahrens char what; 615b468a217Seschrock int ret; 616b468a217Seschrock 617b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 618b468a217Seschrock 619b468a217Seschrock /* 620b468a217Seschrock * The rules for reserved pool names were extended at a later point. 621b468a217Seschrock * But we need to support users with existing pools that may now be 622b468a217Seschrock * invalid. So we only check for this expanded set of names during a 623b468a217Seschrock * create (or import), and only in userland. 624b468a217Seschrock */ 625b468a217Seschrock if (ret == 0 && !isopen && 626b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 627b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 6288654d025Sperrin strncmp(pool, "spare", 5) == 0 || 6298654d025Sperrin strcmp(pool, "log") == 0)) { 630e7cbe64fSgw if (hdl != NULL) 631e7cbe64fSgw zfs_error_aux(hdl, 632e7cbe64fSgw dgettext(TEXT_DOMAIN, "name is reserved")); 63399653d4eSeschrock return (B_FALSE); 634b468a217Seschrock } 635b468a217Seschrock 636fa9e4066Sahrens 637b468a217Seschrock if (ret != 0) { 63899653d4eSeschrock if (hdl != NULL) { 639fa9e4066Sahrens switch (why) { 640b81d61a6Slling case NAME_ERR_TOOLONG: 64199653d4eSeschrock zfs_error_aux(hdl, 642b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 643b81d61a6Slling break; 644b81d61a6Slling 645fa9e4066Sahrens case NAME_ERR_INVALCHAR: 64699653d4eSeschrock zfs_error_aux(hdl, 647fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 648fa9e4066Sahrens "'%c' in pool name"), what); 649fa9e4066Sahrens break; 650fa9e4066Sahrens 651fa9e4066Sahrens case NAME_ERR_NOLETTER: 65299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 65399653d4eSeschrock "name must begin with a letter")); 654fa9e4066Sahrens break; 655fa9e4066Sahrens 656fa9e4066Sahrens case NAME_ERR_RESERVED: 65799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 65899653d4eSeschrock "name is reserved")); 659fa9e4066Sahrens break; 660fa9e4066Sahrens 661fa9e4066Sahrens case NAME_ERR_DISKLIKE: 66299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 66399653d4eSeschrock "pool name is reserved")); 664fa9e4066Sahrens break; 6655ad82045Snd 6665ad82045Snd case NAME_ERR_LEADING_SLASH: 6675ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6685ad82045Snd "leading slash in name")); 6695ad82045Snd break; 6705ad82045Snd 6715ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 6725ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6735ad82045Snd "empty component in name")); 6745ad82045Snd break; 6755ad82045Snd 6765ad82045Snd case NAME_ERR_TRAILING_SLASH: 6775ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6785ad82045Snd "trailing slash in name")); 6795ad82045Snd break; 6805ad82045Snd 6815ad82045Snd case NAME_ERR_MULTIPLE_AT: 6825ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6835ad82045Snd "multiple '@' delimiters in name")); 6845ad82045Snd break; 6855ad82045Snd 686fa9e4066Sahrens } 687fa9e4066Sahrens } 68899653d4eSeschrock return (B_FALSE); 689fa9e4066Sahrens } 690fa9e4066Sahrens 69199653d4eSeschrock return (B_TRUE); 692fa9e4066Sahrens } 693fa9e4066Sahrens 694fa9e4066Sahrens /* 695fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 696fa9e4066Sahrens * state. 697fa9e4066Sahrens */ 698fa9e4066Sahrens zpool_handle_t * 69999653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 700fa9e4066Sahrens { 701fa9e4066Sahrens zpool_handle_t *zhp; 70294de1d4cSeschrock boolean_t missing; 703fa9e4066Sahrens 704fa9e4066Sahrens /* 705fa9e4066Sahrens * Make sure the pool name is valid. 706fa9e4066Sahrens */ 70799653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 708ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 70999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 71099653d4eSeschrock pool); 711fa9e4066Sahrens return (NULL); 712fa9e4066Sahrens } 713fa9e4066Sahrens 71499653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 71599653d4eSeschrock return (NULL); 716fa9e4066Sahrens 71799653d4eSeschrock zhp->zpool_hdl = hdl; 718fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 719fa9e4066Sahrens 72094de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 72194de1d4cSeschrock zpool_close(zhp); 72294de1d4cSeschrock return (NULL); 72394de1d4cSeschrock } 72494de1d4cSeschrock 72594de1d4cSeschrock if (missing) { 726990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 727ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 728990b4856Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 72994de1d4cSeschrock zpool_close(zhp); 73094de1d4cSeschrock return (NULL); 731fa9e4066Sahrens } 732fa9e4066Sahrens 733fa9e4066Sahrens return (zhp); 734fa9e4066Sahrens } 735fa9e4066Sahrens 736fa9e4066Sahrens /* 737fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 738fa9e4066Sahrens * the configuration cache may be out of date). 739fa9e4066Sahrens */ 74094de1d4cSeschrock int 74194de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 742fa9e4066Sahrens { 743fa9e4066Sahrens zpool_handle_t *zhp; 74494de1d4cSeschrock boolean_t missing; 745fa9e4066Sahrens 74694de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 74794de1d4cSeschrock return (-1); 748fa9e4066Sahrens 74999653d4eSeschrock zhp->zpool_hdl = hdl; 750fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 751fa9e4066Sahrens 75294de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 75394de1d4cSeschrock zpool_close(zhp); 75494de1d4cSeschrock return (-1); 755fa9e4066Sahrens } 756fa9e4066Sahrens 75794de1d4cSeschrock if (missing) { 75894de1d4cSeschrock zpool_close(zhp); 75994de1d4cSeschrock *ret = NULL; 76094de1d4cSeschrock return (0); 76194de1d4cSeschrock } 76294de1d4cSeschrock 76394de1d4cSeschrock *ret = zhp; 76494de1d4cSeschrock return (0); 765fa9e4066Sahrens } 766fa9e4066Sahrens 767fa9e4066Sahrens /* 768fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 769fa9e4066Sahrens * state. 770fa9e4066Sahrens */ 771fa9e4066Sahrens zpool_handle_t * 77299653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 773fa9e4066Sahrens { 774fa9e4066Sahrens zpool_handle_t *zhp; 775fa9e4066Sahrens 77699653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 777fa9e4066Sahrens return (NULL); 778fa9e4066Sahrens 779fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 780ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 78199653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 782fa9e4066Sahrens zpool_close(zhp); 783fa9e4066Sahrens return (NULL); 784fa9e4066Sahrens } 785fa9e4066Sahrens 786fa9e4066Sahrens return (zhp); 787fa9e4066Sahrens } 788fa9e4066Sahrens 789fa9e4066Sahrens /* 790fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 791fa9e4066Sahrens */ 792fa9e4066Sahrens void 793fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 794fa9e4066Sahrens { 795fa9e4066Sahrens if (zhp->zpool_config) 796fa9e4066Sahrens nvlist_free(zhp->zpool_config); 797088e9d47Seschrock if (zhp->zpool_old_config) 798088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 799b1b8ab34Slling if (zhp->zpool_props) 800b1b8ab34Slling nvlist_free(zhp->zpool_props); 801fa9e4066Sahrens free(zhp); 802fa9e4066Sahrens } 803fa9e4066Sahrens 804fa9e4066Sahrens /* 805fa9e4066Sahrens * Return the name of the pool. 806fa9e4066Sahrens */ 807fa9e4066Sahrens const char * 808fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 809fa9e4066Sahrens { 810fa9e4066Sahrens return (zhp->zpool_name); 811fa9e4066Sahrens } 812fa9e4066Sahrens 813fa9e4066Sahrens 814fa9e4066Sahrens /* 815fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 816fa9e4066Sahrens */ 817fa9e4066Sahrens int 818fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 819fa9e4066Sahrens { 820fa9e4066Sahrens return (zhp->zpool_state); 821fa9e4066Sahrens } 822fa9e4066Sahrens 823fa9e4066Sahrens /* 824fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 825fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 826fa9e4066Sahrens * don't have to worry about error semantics. 827fa9e4066Sahrens */ 828fa9e4066Sahrens int 82999653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8300a48a24eStimh nvlist_t *props, nvlist_t *fsprops) 831fa9e4066Sahrens { 832fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 8330a48a24eStimh nvlist_t *zc_fsprops = NULL; 8340a48a24eStimh nvlist_t *zc_props = NULL; 83599653d4eSeschrock char msg[1024]; 836990b4856Slling char *altroot; 8370a48a24eStimh int ret = -1; 838fa9e4066Sahrens 83999653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 84099653d4eSeschrock "cannot create '%s'"), pool); 841fa9e4066Sahrens 84299653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 84399653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 844fa9e4066Sahrens 845351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 846990b4856Slling return (-1); 847fa9e4066Sahrens 8480a48a24eStimh if (props) { 8490a48a24eStimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8500a48a24eStimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8510a48a24eStimh goto create_failed; 8520a48a24eStimh } 8530a48a24eStimh } 85499653d4eSeschrock 8550a48a24eStimh if (fsprops) { 8560a48a24eStimh uint64_t zoned; 8570a48a24eStimh char *zonestr; 8580a48a24eStimh 8590a48a24eStimh zoned = ((nvlist_lookup_string(fsprops, 8600a48a24eStimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8610a48a24eStimh strcmp(zonestr, "on") == 0); 8620a48a24eStimh 8630a48a24eStimh if ((zc_fsprops = zfs_valid_proplist(hdl, 8640a48a24eStimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 8650a48a24eStimh goto create_failed; 8660a48a24eStimh } 8670a48a24eStimh if (!zc_props && 8680a48a24eStimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 8690a48a24eStimh goto create_failed; 8700a48a24eStimh } 8710a48a24eStimh if (nvlist_add_nvlist(zc_props, 8720a48a24eStimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 8730a48a24eStimh goto create_failed; 8740a48a24eStimh } 875351420b3Slling } 876fa9e4066Sahrens 8770a48a24eStimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 8780a48a24eStimh goto create_failed; 8790a48a24eStimh 880990b4856Slling (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 881fa9e4066Sahrens 8820a48a24eStimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 883351420b3Slling 884e9dbad6fSeschrock zcmd_free_nvlists(&zc); 8850a48a24eStimh nvlist_free(zc_props); 8860a48a24eStimh nvlist_free(zc_fsprops); 887fa9e4066Sahrens 88899653d4eSeschrock switch (errno) { 889fa9e4066Sahrens case EBUSY: 890fa9e4066Sahrens /* 891fa9e4066Sahrens * This can happen if the user has specified the same 892fa9e4066Sahrens * device multiple times. We can't reliably detect this 893fa9e4066Sahrens * until we try to add it and see we already have a 894fa9e4066Sahrens * label. 895fa9e4066Sahrens */ 89699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 89799653d4eSeschrock "one or more vdevs refer to the same device")); 89899653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 899fa9e4066Sahrens 900fa9e4066Sahrens case EOVERFLOW: 901fa9e4066Sahrens /* 90299653d4eSeschrock * This occurs when one of the devices is below 903fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 904fa9e4066Sahrens * device was the problem device since there's no 905fa9e4066Sahrens * reliable way to determine device size from userland. 906fa9e4066Sahrens */ 907fa9e4066Sahrens { 908fa9e4066Sahrens char buf[64]; 909fa9e4066Sahrens 910fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 911fa9e4066Sahrens 91299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 91399653d4eSeschrock "one or more devices is less than the " 91499653d4eSeschrock "minimum size (%s)"), buf); 915fa9e4066Sahrens } 91699653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 917fa9e4066Sahrens 918fa9e4066Sahrens case ENOSPC: 91999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 92099653d4eSeschrock "one or more devices is out of space")); 92199653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 922fa9e4066Sahrens 923fa94a07fSbrendan case ENOTBLK: 924fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 925fa94a07fSbrendan "cache device must be a disk or disk slice")); 926fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 927fa94a07fSbrendan 928fa9e4066Sahrens default: 92999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 930fa9e4066Sahrens } 931fa9e4066Sahrens } 932fa9e4066Sahrens 933fa9e4066Sahrens /* 934fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 935e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 936fa9e4066Sahrens */ 937990b4856Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 938990b4856Slling &altroot) == 0) { 939fa9e4066Sahrens zfs_handle_t *zhp; 940fa9e4066Sahrens 941990b4856Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 942e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 943e9dbad6fSeschrock "/") == 0); 944fa9e4066Sahrens 945fa9e4066Sahrens zfs_close(zhp); 946fa9e4066Sahrens } 947fa9e4066Sahrens 9480a48a24eStimh create_failed: 949351420b3Slling zcmd_free_nvlists(&zc); 9500a48a24eStimh nvlist_free(zc_props); 9510a48a24eStimh nvlist_free(zc_fsprops); 9520a48a24eStimh return (ret); 953fa9e4066Sahrens } 954fa9e4066Sahrens 955fa9e4066Sahrens /* 956fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 957fa9e4066Sahrens * datasets left in the pool. 958fa9e4066Sahrens */ 959fa9e4066Sahrens int 960fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 961fa9e4066Sahrens { 962fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 963fa9e4066Sahrens zfs_handle_t *zfp = NULL; 96499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 96599653d4eSeschrock char msg[1024]; 966fa9e4066Sahrens 967fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 96899653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 96999653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 970fa9e4066Sahrens return (-1); 971fa9e4066Sahrens 9725ad82045Snd if (zpool_remove_zvol_links(zhp) != 0) 973fa9e4066Sahrens return (-1); 974fa9e4066Sahrens 975fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 976fa9e4066Sahrens 977ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 97899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 97999653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 980fa9e4066Sahrens 98199653d4eSeschrock if (errno == EROFS) { 98299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 98399653d4eSeschrock "one or more devices is read only")); 98499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 98599653d4eSeschrock } else { 98699653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 987fa9e4066Sahrens } 988fa9e4066Sahrens 989fa9e4066Sahrens if (zfp) 990fa9e4066Sahrens zfs_close(zfp); 991fa9e4066Sahrens return (-1); 992fa9e4066Sahrens } 993fa9e4066Sahrens 994fa9e4066Sahrens if (zfp) { 995fa9e4066Sahrens remove_mountpoint(zfp); 996fa9e4066Sahrens zfs_close(zfp); 997fa9e4066Sahrens } 998fa9e4066Sahrens 999fa9e4066Sahrens return (0); 1000fa9e4066Sahrens } 1001fa9e4066Sahrens 1002fa9e4066Sahrens /* 1003fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1004fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1005fa9e4066Sahrens */ 1006fa9e4066Sahrens int 1007fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1008fa9e4066Sahrens { 1009e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 101099653d4eSeschrock int ret; 101199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 101299653d4eSeschrock char msg[1024]; 1013fa94a07fSbrendan nvlist_t **spares, **l2cache; 1014fa94a07fSbrendan uint_t nspares, nl2cache; 101599653d4eSeschrock 101699653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 101799653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 101899653d4eSeschrock 1019fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1020fa94a07fSbrendan SPA_VERSION_SPARES && 102199653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 102299653d4eSeschrock &spares, &nspares) == 0) { 102399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 102499653d4eSeschrock "upgraded to add hot spares")); 102599653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 102699653d4eSeschrock } 1027fa9e4066Sahrens 1028*b5b76fecSGeorge Wilson if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 1029*b5b76fecSGeorge Wilson ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 1030*b5b76fecSGeorge Wilson uint64_t s; 1031*b5b76fecSGeorge Wilson 1032*b5b76fecSGeorge Wilson for (s = 0; s < nspares; s++) { 1033*b5b76fecSGeorge Wilson char *path; 1034*b5b76fecSGeorge Wilson 1035*b5b76fecSGeorge Wilson if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 1036*b5b76fecSGeorge Wilson &path) == 0 && pool_uses_efi(spares[s])) { 1037*b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1038*b5b76fecSGeorge Wilson "device '%s' contains an EFI label and " 1039*b5b76fecSGeorge Wilson "cannot be used on root pools."), 1040*b5b76fecSGeorge Wilson zpool_vdev_name(hdl, NULL, spares[s])); 1041*b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 1042*b5b76fecSGeorge Wilson } 1043*b5b76fecSGeorge Wilson } 1044*b5b76fecSGeorge Wilson } 1045*b5b76fecSGeorge Wilson 1046fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1047fa94a07fSbrendan SPA_VERSION_L2CACHE && 1048fa94a07fSbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1049fa94a07fSbrendan &l2cache, &nl2cache) == 0) { 1050fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 1051fa94a07fSbrendan "upgraded to add cache devices")); 1052fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 1053fa94a07fSbrendan } 1054fa94a07fSbrendan 1055990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 105699653d4eSeschrock return (-1); 1057fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1058fa9e4066Sahrens 1059ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1060fa9e4066Sahrens switch (errno) { 1061fa9e4066Sahrens case EBUSY: 1062fa9e4066Sahrens /* 1063fa9e4066Sahrens * This can happen if the user has specified the same 1064fa9e4066Sahrens * device multiple times. We can't reliably detect this 1065fa9e4066Sahrens * until we try to add it and see we already have a 1066fa9e4066Sahrens * label. 1067fa9e4066Sahrens */ 106899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 106999653d4eSeschrock "one or more vdevs refer to the same device")); 107099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1071fa9e4066Sahrens break; 1072fa9e4066Sahrens 1073fa9e4066Sahrens case EOVERFLOW: 1074fa9e4066Sahrens /* 1075fa9e4066Sahrens * This occurrs when one of the devices is below 1076fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1077fa9e4066Sahrens * device was the problem device since there's no 1078fa9e4066Sahrens * reliable way to determine device size from userland. 1079fa9e4066Sahrens */ 1080fa9e4066Sahrens { 1081fa9e4066Sahrens char buf[64]; 1082fa9e4066Sahrens 1083fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1084fa9e4066Sahrens 108599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 108699653d4eSeschrock "device is less than the minimum " 108799653d4eSeschrock "size (%s)"), buf); 1088fa9e4066Sahrens } 108999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 109099653d4eSeschrock break; 109199653d4eSeschrock 109299653d4eSeschrock case ENOTSUP: 109399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10948654d025Sperrin "pool must be upgraded to add these vdevs")); 109599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1096fa9e4066Sahrens break; 1097fa9e4066Sahrens 1098b1b8ab34Slling case EDOM: 1099b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11008654d025Sperrin "root pool can not have multiple vdevs" 11018654d025Sperrin " or separate logs")); 1102b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 1103b1b8ab34Slling break; 1104b1b8ab34Slling 1105fa94a07fSbrendan case ENOTBLK: 1106fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1107fa94a07fSbrendan "cache device must be a disk or disk slice")); 1108fa94a07fSbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 1109fa94a07fSbrendan break; 1110fa94a07fSbrendan 1111fa9e4066Sahrens default: 111299653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1113fa9e4066Sahrens } 1114fa9e4066Sahrens 111599653d4eSeschrock ret = -1; 111699653d4eSeschrock } else { 111799653d4eSeschrock ret = 0; 1118fa9e4066Sahrens } 1119fa9e4066Sahrens 1120e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1121fa9e4066Sahrens 112299653d4eSeschrock return (ret); 1123fa9e4066Sahrens } 1124fa9e4066Sahrens 1125fa9e4066Sahrens /* 1126fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 1127fa9e4066Sahrens * mounted datasets in the pool. 1128fa9e4066Sahrens */ 1129fa9e4066Sahrens int 113089a89ebfSlling zpool_export(zpool_handle_t *zhp, boolean_t force) 1131fa9e4066Sahrens { 1132fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 113389a89ebfSlling char msg[1024]; 1134fa9e4066Sahrens 1135fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 1136fa9e4066Sahrens return (-1); 1137fa9e4066Sahrens 113889a89ebfSlling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 113989a89ebfSlling "cannot export '%s'"), zhp->zpool_name); 114089a89ebfSlling 1141fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 114289a89ebfSlling zc.zc_cookie = force; 114389a89ebfSlling 114489a89ebfSlling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 114589a89ebfSlling switch (errno) { 114689a89ebfSlling case EXDEV: 114789a89ebfSlling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 114889a89ebfSlling "use '-f' to override the following errors:\n" 114989a89ebfSlling "'%s' has an active shared spare which could be" 115089a89ebfSlling " used by other pools once '%s' is exported."), 115189a89ebfSlling zhp->zpool_name, zhp->zpool_name); 115289a89ebfSlling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 115389a89ebfSlling msg)); 115489a89ebfSlling default: 115589a89ebfSlling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 115689a89ebfSlling msg)); 115789a89ebfSlling } 115889a89ebfSlling } 1159fa9e4066Sahrens 1160fa9e4066Sahrens return (0); 1161fa9e4066Sahrens } 1162fa9e4066Sahrens 1163fa9e4066Sahrens /* 1164990b4856Slling * zpool_import() is a contracted interface. Should be kept the same 1165990b4856Slling * if possible. 1166990b4856Slling * 1167990b4856Slling * Applications should use zpool_import_props() to import a pool with 1168990b4856Slling * new properties value to be set. 1169fa9e4066Sahrens */ 1170fa9e4066Sahrens int 117199653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1172990b4856Slling char *altroot) 1173990b4856Slling { 1174990b4856Slling nvlist_t *props = NULL; 1175990b4856Slling int ret; 1176990b4856Slling 1177990b4856Slling if (altroot != NULL) { 1178990b4856Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1179990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1180990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1181990b4856Slling newname)); 1182990b4856Slling } 1183990b4856Slling 1184990b4856Slling if (nvlist_add_string(props, 1185990b4856Slling zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0) { 1186990b4856Slling nvlist_free(props); 1187990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1188990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1189990b4856Slling newname)); 1190990b4856Slling } 1191990b4856Slling } 1192990b4856Slling 1193c5904d13Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 1194990b4856Slling if (props) 1195990b4856Slling nvlist_free(props); 1196990b4856Slling return (ret); 1197990b4856Slling } 1198990b4856Slling 1199990b4856Slling /* 1200990b4856Slling * Import the given pool using the known configuration and a list of 1201990b4856Slling * properties to be set. The configuration should have come from 1202990b4856Slling * zpool_find_import(). The 'newname' parameters control whether the pool 1203990b4856Slling * is imported with a different name. 1204990b4856Slling */ 1205990b4856Slling int 1206990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1207c5904d13Seschrock nvlist_t *props, boolean_t importfaulted) 1208fa9e4066Sahrens { 1209e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 1210fa9e4066Sahrens char *thename; 1211fa9e4066Sahrens char *origname; 1212fa9e4066Sahrens int ret; 1213990b4856Slling char errbuf[1024]; 1214fa9e4066Sahrens 1215fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1216fa9e4066Sahrens &origname) == 0); 1217fa9e4066Sahrens 1218990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1219990b4856Slling "cannot import pool '%s'"), origname); 1220990b4856Slling 1221fa9e4066Sahrens if (newname != NULL) { 122299653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 1223ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 122499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 122599653d4eSeschrock newname)); 1226fa9e4066Sahrens thename = (char *)newname; 1227fa9e4066Sahrens } else { 1228fa9e4066Sahrens thename = origname; 1229fa9e4066Sahrens } 1230fa9e4066Sahrens 1231990b4856Slling if (props) { 1232990b4856Slling uint64_t version; 1233fa9e4066Sahrens 1234990b4856Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 1235990b4856Slling &version) == 0); 1236fa9e4066Sahrens 12370a48a24eStimh if ((props = zpool_valid_proplist(hdl, origname, 1238351420b3Slling props, version, B_TRUE, errbuf)) == NULL) { 1239990b4856Slling return (-1); 1240351420b3Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 1241351420b3Slling nvlist_free(props); 1242990b4856Slling return (-1); 1243351420b3Slling } 1244990b4856Slling } 1245990b4856Slling 1246990b4856Slling (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1247fa9e4066Sahrens 1248fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1249ea8dc4b6Seschrock &zc.zc_guid) == 0); 1250fa9e4066Sahrens 1251351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 1252351420b3Slling nvlist_free(props); 125399653d4eSeschrock return (-1); 1254351420b3Slling } 1255fa9e4066Sahrens 1256c5904d13Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1257fa9e4066Sahrens ret = 0; 1258ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1259fa9e4066Sahrens char desc[1024]; 1260fa9e4066Sahrens if (newname == NULL) 1261fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1262fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1263fa9e4066Sahrens thename); 1264fa9e4066Sahrens else 1265fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1266fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1267fa9e4066Sahrens origname, thename); 1268fa9e4066Sahrens 1269fa9e4066Sahrens switch (errno) { 1270ea8dc4b6Seschrock case ENOTSUP: 1271ea8dc4b6Seschrock /* 1272ea8dc4b6Seschrock * Unsupported version. 1273ea8dc4b6Seschrock */ 127499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 1275ea8dc4b6Seschrock break; 1276ea8dc4b6Seschrock 1277b5989ec7Seschrock case EINVAL: 1278b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 1279b5989ec7Seschrock break; 1280b5989ec7Seschrock 1281fa9e4066Sahrens default: 128299653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 1283fa9e4066Sahrens } 1284fa9e4066Sahrens 1285fa9e4066Sahrens ret = -1; 1286fa9e4066Sahrens } else { 1287fa9e4066Sahrens zpool_handle_t *zhp; 1288ecd6cf80Smarks 1289fa9e4066Sahrens /* 1290fa9e4066Sahrens * This should never fail, but play it safe anyway. 1291fa9e4066Sahrens */ 129294de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 129394de1d4cSeschrock ret = -1; 129494de1d4cSeschrock } else if (zhp != NULL) { 1295fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 1296fa9e4066Sahrens zpool_close(zhp); 1297fa9e4066Sahrens } 1298ecd6cf80Smarks 1299fa9e4066Sahrens } 1300fa9e4066Sahrens 1301e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1302351420b3Slling nvlist_free(props); 1303351420b3Slling 1304fa9e4066Sahrens return (ret); 1305fa9e4066Sahrens } 1306fa9e4066Sahrens 1307fa9e4066Sahrens /* 1308fa9e4066Sahrens * Scrub the pool. 1309fa9e4066Sahrens */ 1310fa9e4066Sahrens int 1311fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1312fa9e4066Sahrens { 1313fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1314fa9e4066Sahrens char msg[1024]; 131599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1316fa9e4066Sahrens 1317fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1318fa9e4066Sahrens zc.zc_cookie = type; 1319fa9e4066Sahrens 1320ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1321fa9e4066Sahrens return (0); 1322fa9e4066Sahrens 1323fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 1324fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1325fa9e4066Sahrens 132699653d4eSeschrock if (errno == EBUSY) 132799653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 132899653d4eSeschrock else 132999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1330fa9e4066Sahrens } 1331fa9e4066Sahrens 1332a43d325bSek /* 1333a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 1334a43d325bSek * spare; but FALSE if its an INUSE spare. 1335a43d325bSek */ 133699653d4eSeschrock static nvlist_t * 133799653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, 1338ee0eb9f2SEric Schrock boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 1339ea8dc4b6Seschrock { 1340ea8dc4b6Seschrock uint_t c, children; 1341ea8dc4b6Seschrock nvlist_t **child; 134299653d4eSeschrock uint64_t theguid, present; 1343ea8dc4b6Seschrock char *path; 1344ea8dc4b6Seschrock uint64_t wholedisk = 0; 134599653d4eSeschrock nvlist_t *ret; 1346ee0eb9f2SEric Schrock uint64_t is_log; 1347ea8dc4b6Seschrock 134899653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0); 1349ea8dc4b6Seschrock 1350ea8dc4b6Seschrock if (search == NULL && 1351ea8dc4b6Seschrock nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) { 1352ea8dc4b6Seschrock /* 1353ea8dc4b6Seschrock * If the device has never been present since import, the only 1354ea8dc4b6Seschrock * reliable way to match the vdev is by GUID. 1355ea8dc4b6Seschrock */ 135699653d4eSeschrock if (theguid == guid) 135799653d4eSeschrock return (nv); 1358ea8dc4b6Seschrock } else if (search != NULL && 1359ea8dc4b6Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 1360ea8dc4b6Seschrock (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1361ea8dc4b6Seschrock &wholedisk); 1362ea8dc4b6Seschrock if (wholedisk) { 1363ea8dc4b6Seschrock /* 1364ea8dc4b6Seschrock * For whole disks, the internal path has 's0', but the 1365ea8dc4b6Seschrock * path passed in by the user doesn't. 1366ea8dc4b6Seschrock */ 1367ea8dc4b6Seschrock if (strlen(search) == strlen(path) - 2 && 1368ea8dc4b6Seschrock strncmp(search, path, strlen(search)) == 0) 136999653d4eSeschrock return (nv); 1370ea8dc4b6Seschrock } else if (strcmp(search, path) == 0) { 137199653d4eSeschrock return (nv); 1372ea8dc4b6Seschrock } 1373ea8dc4b6Seschrock } 1374ea8dc4b6Seschrock 1375ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1376ea8dc4b6Seschrock &child, &children) != 0) 137799653d4eSeschrock return (NULL); 1378ea8dc4b6Seschrock 1379ee0eb9f2SEric Schrock for (c = 0; c < children; c++) { 138099653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 1381ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1382ee0eb9f2SEric Schrock /* 1383ee0eb9f2SEric Schrock * The 'is_log' value is only set for the toplevel 1384ee0eb9f2SEric Schrock * vdev, not the leaf vdevs. So we always lookup the 1385ee0eb9f2SEric Schrock * log device from the root of the vdev tree (where 1386ee0eb9f2SEric Schrock * 'log' is non-NULL). 1387ee0eb9f2SEric Schrock */ 1388ee0eb9f2SEric Schrock if (log != NULL && 1389ee0eb9f2SEric Schrock nvlist_lookup_uint64(child[c], 1390ee0eb9f2SEric Schrock ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 1391ee0eb9f2SEric Schrock is_log) { 1392ee0eb9f2SEric Schrock *log = B_TRUE; 1393ee0eb9f2SEric Schrock } 1394ea8dc4b6Seschrock return (ret); 1395ee0eb9f2SEric Schrock } 1396ee0eb9f2SEric Schrock } 1397ea8dc4b6Seschrock 139899653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 139999653d4eSeschrock &child, &children) == 0) { 140099653d4eSeschrock for (c = 0; c < children; c++) { 140199653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 1402ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1403a43d325bSek *avail_spare = B_TRUE; 140499653d4eSeschrock return (ret); 140599653d4eSeschrock } 140699653d4eSeschrock } 140799653d4eSeschrock } 140899653d4eSeschrock 1409fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1410fa94a07fSbrendan &child, &children) == 0) { 1411fa94a07fSbrendan for (c = 0; c < children; c++) { 1412fa94a07fSbrendan if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 1413ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1414fa94a07fSbrendan *l2cache = B_TRUE; 1415fa94a07fSbrendan return (ret); 1416fa94a07fSbrendan } 1417fa94a07fSbrendan } 1418fa94a07fSbrendan } 1419fa94a07fSbrendan 142099653d4eSeschrock return (NULL); 1421ea8dc4b6Seschrock } 1422ea8dc4b6Seschrock 142399653d4eSeschrock nvlist_t * 1424fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 1425ee0eb9f2SEric Schrock boolean_t *l2cache, boolean_t *log) 1426ea8dc4b6Seschrock { 1427ea8dc4b6Seschrock char buf[MAXPATHLEN]; 1428ea8dc4b6Seschrock const char *search; 1429ea8dc4b6Seschrock char *end; 1430ea8dc4b6Seschrock nvlist_t *nvroot; 1431ea8dc4b6Seschrock uint64_t guid; 1432ea8dc4b6Seschrock 14330917b783Seschrock guid = strtoull(path, &end, 10); 1434ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 1435ea8dc4b6Seschrock search = NULL; 1436ea8dc4b6Seschrock } else if (path[0] != '/') { 1437ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 1438ea8dc4b6Seschrock search = buf; 1439ea8dc4b6Seschrock } else { 1440ea8dc4b6Seschrock search = path; 1441ea8dc4b6Seschrock } 1442ea8dc4b6Seschrock 1443ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1444ea8dc4b6Seschrock &nvroot) == 0); 1445ea8dc4b6Seschrock 1446a43d325bSek *avail_spare = B_FALSE; 1447fa94a07fSbrendan *l2cache = B_FALSE; 1448ee0eb9f2SEric Schrock if (log != NULL) 1449ee0eb9f2SEric Schrock *log = B_FALSE; 1450fa94a07fSbrendan return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare, 1451ee0eb9f2SEric Schrock l2cache, log)); 1452a43d325bSek } 1453a43d325bSek 145419397407SSherry Moore static int 145519397407SSherry Moore vdev_online(nvlist_t *nv) 145619397407SSherry Moore { 145719397407SSherry Moore uint64_t ival; 145819397407SSherry Moore 145919397407SSherry Moore if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 146019397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 146119397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 146219397407SSherry Moore return (0); 146319397407SSherry Moore 146419397407SSherry Moore return (1); 146519397407SSherry Moore } 146619397407SSherry Moore 146719397407SSherry Moore /* 146819397407SSherry Moore * Get phys_path for a root pool 146919397407SSherry Moore * Return 0 on success; non-zeron on failure. 147019397407SSherry Moore */ 147119397407SSherry Moore int 147219397407SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath) 147319397407SSherry Moore { 147419397407SSherry Moore nvlist_t *vdev_root; 147519397407SSherry Moore nvlist_t **child; 147619397407SSherry Moore uint_t count; 147719397407SSherry Moore int i; 147819397407SSherry Moore 147919397407SSherry Moore /* 148019397407SSherry Moore * Make sure this is a root pool, as phys_path doesn't mean 148119397407SSherry Moore * anything to a non-root pool. 148219397407SSherry Moore */ 1483*b5b76fecSGeorge Wilson if (!pool_is_bootable(zhp)) 148419397407SSherry Moore return (-1); 148519397407SSherry Moore 148619397407SSherry Moore verify(nvlist_lookup_nvlist(zhp->zpool_config, 148719397407SSherry Moore ZPOOL_CONFIG_VDEV_TREE, &vdev_root) == 0); 148819397407SSherry Moore 148919397407SSherry Moore if (nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 149019397407SSherry Moore &child, &count) != 0) 149119397407SSherry Moore return (-2); 149219397407SSherry Moore 149319397407SSherry Moore for (i = 0; i < count; i++) { 149419397407SSherry Moore nvlist_t **child2; 149519397407SSherry Moore uint_t count2; 149619397407SSherry Moore char *type; 149719397407SSherry Moore char *tmppath; 149819397407SSherry Moore int j; 149919397407SSherry Moore 150019397407SSherry Moore if (nvlist_lookup_string(child[i], ZPOOL_CONFIG_TYPE, &type) 150119397407SSherry Moore != 0) 150219397407SSherry Moore return (-3); 150319397407SSherry Moore 150419397407SSherry Moore if (strcmp(type, VDEV_TYPE_DISK) == 0) { 150519397407SSherry Moore if (!vdev_online(child[i])) 150619397407SSherry Moore return (-8); 150719397407SSherry Moore verify(nvlist_lookup_string(child[i], 150819397407SSherry Moore ZPOOL_CONFIG_PHYS_PATH, &tmppath) == 0); 150919397407SSherry Moore (void) strncpy(physpath, tmppath, strlen(tmppath)); 151019397407SSherry Moore } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) { 151119397407SSherry Moore if (nvlist_lookup_nvlist_array(child[i], 151219397407SSherry Moore ZPOOL_CONFIG_CHILDREN, &child2, &count2) != 0) 151319397407SSherry Moore return (-4); 151419397407SSherry Moore 151519397407SSherry Moore for (j = 0; j < count2; j++) { 151619397407SSherry Moore if (!vdev_online(child2[j])) 151719397407SSherry Moore return (-8); 151819397407SSherry Moore if (nvlist_lookup_string(child2[j], 151919397407SSherry Moore ZPOOL_CONFIG_PHYS_PATH, &tmppath) != 0) 152019397407SSherry Moore return (-5); 152119397407SSherry Moore 152219397407SSherry Moore if ((strlen(physpath) + strlen(tmppath)) > 152319397407SSherry Moore MAXNAMELEN) 152419397407SSherry Moore return (-6); 152519397407SSherry Moore 152619397407SSherry Moore if (strlen(physpath) == 0) { 152719397407SSherry Moore (void) strncpy(physpath, tmppath, 152819397407SSherry Moore strlen(tmppath)); 152919397407SSherry Moore } else { 153019397407SSherry Moore (void) strcat(physpath, " "); 153119397407SSherry Moore (void) strcat(physpath, tmppath); 153219397407SSherry Moore } 153319397407SSherry Moore } 153419397407SSherry Moore } else { 153519397407SSherry Moore return (-7); 153619397407SSherry Moore } 153719397407SSherry Moore } 153819397407SSherry Moore 153919397407SSherry Moore return (0); 154019397407SSherry Moore } 154119397407SSherry Moore 1542a43d325bSek /* 1543fa94a07fSbrendan * Returns TRUE if the given guid corresponds to the given type. 1544fa94a07fSbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 1545fa94a07fSbrendan * devices. 1546a43d325bSek */ 1547a43d325bSek static boolean_t 1548fa94a07fSbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 1549a43d325bSek { 1550fa94a07fSbrendan uint64_t target_guid; 1551a43d325bSek nvlist_t *nvroot; 1552fa94a07fSbrendan nvlist_t **list; 1553fa94a07fSbrendan uint_t count; 1554a43d325bSek int i; 1555a43d325bSek 1556a43d325bSek verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1557a43d325bSek &nvroot) == 0); 1558fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 1559fa94a07fSbrendan for (i = 0; i < count; i++) { 1560fa94a07fSbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 1561fa94a07fSbrendan &target_guid) == 0); 1562fa94a07fSbrendan if (guid == target_guid) 1563a43d325bSek return (B_TRUE); 1564a43d325bSek } 1565a43d325bSek } 1566a43d325bSek 1567a43d325bSek return (B_FALSE); 1568ea8dc4b6Seschrock } 1569ea8dc4b6Seschrock 1570fa9e4066Sahrens /* 15713d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 15723d7072f8Seschrock * ZFS_ONLINE_* flags. 1573fa9e4066Sahrens */ 1574fa9e4066Sahrens int 15753d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 15763d7072f8Seschrock vdev_state_t *newstate) 1577fa9e4066Sahrens { 1578fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1579fa9e4066Sahrens char msg[1024]; 158099653d4eSeschrock nvlist_t *tgt; 1581fa94a07fSbrendan boolean_t avail_spare, l2cache; 158299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1583fa9e4066Sahrens 1584ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1585ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot online %s"), path); 1586ea8dc4b6Seschrock 1587fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1588ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1589ee0eb9f2SEric Schrock NULL)) == NULL) 159099653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1591fa9e4066Sahrens 159299653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1593fa9e4066Sahrens 1594fa94a07fSbrendan if (avail_spare || 1595fa94a07fSbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 1596a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1597a43d325bSek 15983d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 15993d7072f8Seschrock zc.zc_obj = flags; 1600fa9e4066Sahrens 1601ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 16023d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 16033d7072f8Seschrock 16043d7072f8Seschrock *newstate = zc.zc_cookie; 16053d7072f8Seschrock return (0); 1606fa9e4066Sahrens } 1607fa9e4066Sahrens 1608fa9e4066Sahrens /* 1609fa9e4066Sahrens * Take the specified vdev offline 1610fa9e4066Sahrens */ 1611fa9e4066Sahrens int 16123d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1613fa9e4066Sahrens { 1614fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1615fa9e4066Sahrens char msg[1024]; 161699653d4eSeschrock nvlist_t *tgt; 1617fa94a07fSbrendan boolean_t avail_spare, l2cache; 161899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1619fa9e4066Sahrens 1620ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1621ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 1622ea8dc4b6Seschrock 1623fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1624ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1625ee0eb9f2SEric Schrock NULL)) == NULL) 162699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 162799653d4eSeschrock 162899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1629fa9e4066Sahrens 1630fa94a07fSbrendan if (avail_spare || 1631fa94a07fSbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 1632a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1633a43d325bSek 16343d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 16353d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 16363d7072f8Seschrock 1637ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 16383d7072f8Seschrock return (0); 16393d7072f8Seschrock 16403d7072f8Seschrock switch (errno) { 16413d7072f8Seschrock case EBUSY: 16423d7072f8Seschrock 16433d7072f8Seschrock /* 16443d7072f8Seschrock * There are no other replicas of this device. 16453d7072f8Seschrock */ 16463d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 16473d7072f8Seschrock 16483d7072f8Seschrock default: 16493d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 16503d7072f8Seschrock } 16513d7072f8Seschrock } 16523d7072f8Seschrock 16533d7072f8Seschrock /* 16543d7072f8Seschrock * Mark the given vdev faulted. 16553d7072f8Seschrock */ 16563d7072f8Seschrock int 16573d7072f8Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 16583d7072f8Seschrock { 16593d7072f8Seschrock zfs_cmd_t zc = { 0 }; 16603d7072f8Seschrock char msg[1024]; 16613d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 16623d7072f8Seschrock 16633d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 16643d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 1665441d80aaSlling 16663d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 16673d7072f8Seschrock zc.zc_guid = guid; 16683d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 16693d7072f8Seschrock 16703d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1671fa9e4066Sahrens return (0); 1672fa9e4066Sahrens 1673fa9e4066Sahrens switch (errno) { 167499653d4eSeschrock case EBUSY: 1675fa9e4066Sahrens 1676fa9e4066Sahrens /* 1677fa9e4066Sahrens * There are no other replicas of this device. 1678fa9e4066Sahrens */ 167999653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 1680fa9e4066Sahrens 168199653d4eSeschrock default: 168299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1683fa9e4066Sahrens } 16843d7072f8Seschrock 16853d7072f8Seschrock } 16863d7072f8Seschrock 16873d7072f8Seschrock /* 16883d7072f8Seschrock * Mark the given vdev degraded. 16893d7072f8Seschrock */ 16903d7072f8Seschrock int 16913d7072f8Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 16923d7072f8Seschrock { 16933d7072f8Seschrock zfs_cmd_t zc = { 0 }; 16943d7072f8Seschrock char msg[1024]; 16953d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 16963d7072f8Seschrock 16973d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 16983d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 16993d7072f8Seschrock 17003d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 17013d7072f8Seschrock zc.zc_guid = guid; 17023d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 17033d7072f8Seschrock 17043d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 17053d7072f8Seschrock return (0); 17063d7072f8Seschrock 17073d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 170899653d4eSeschrock } 170999653d4eSeschrock 171099653d4eSeschrock /* 171199653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 171299653d4eSeschrock * a hot spare. 171399653d4eSeschrock */ 171499653d4eSeschrock static boolean_t 171599653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 171699653d4eSeschrock { 171799653d4eSeschrock nvlist_t **child; 171899653d4eSeschrock uint_t c, children; 171999653d4eSeschrock char *type; 172099653d4eSeschrock 172199653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 172299653d4eSeschrock &children) == 0) { 172399653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 172499653d4eSeschrock &type) == 0); 172599653d4eSeschrock 172699653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 172799653d4eSeschrock children == 2 && child[which] == tgt) 172899653d4eSeschrock return (B_TRUE); 172999653d4eSeschrock 173099653d4eSeschrock for (c = 0; c < children; c++) 173199653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 173299653d4eSeschrock return (B_TRUE); 173399653d4eSeschrock } 173499653d4eSeschrock 173599653d4eSeschrock return (B_FALSE); 1736fa9e4066Sahrens } 1737fa9e4066Sahrens 1738fa9e4066Sahrens /* 1739fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 17408654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 1741fa9e4066Sahrens */ 1742fa9e4066Sahrens int 1743fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 1744fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 1745fa9e4066Sahrens { 1746fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1747fa9e4066Sahrens char msg[1024]; 1748fa9e4066Sahrens int ret; 174999653d4eSeschrock nvlist_t *tgt; 1750ee0eb9f2SEric Schrock boolean_t avail_spare, l2cache, islog; 1751ee0eb9f2SEric Schrock uint64_t val; 17520430f8daSeschrock char *path, *newname; 175399653d4eSeschrock nvlist_t **child; 175499653d4eSeschrock uint_t children; 175599653d4eSeschrock nvlist_t *config_root; 175699653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1757*b5b76fecSGeorge Wilson boolean_t rootpool = pool_is_bootable(zhp); 1758fa9e4066Sahrens 1759ea8dc4b6Seschrock if (replacing) 1760ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 1761ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 1762ea8dc4b6Seschrock else 1763ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 1764ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 1765ea8dc4b6Seschrock 1766*b5b76fecSGeorge Wilson /* 1767*b5b76fecSGeorge Wilson * If this is a root pool, make sure that we're not attaching an 1768*b5b76fecSGeorge Wilson * EFI labeled device. 1769*b5b76fecSGeorge Wilson */ 1770*b5b76fecSGeorge Wilson if (rootpool && pool_uses_efi(nvroot)) { 1771*b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1772*b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root pools.")); 1773*b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 1774*b5b76fecSGeorge Wilson } 1775*b5b76fecSGeorge Wilson 1776fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1777ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 1778ee0eb9f2SEric Schrock &islog)) == 0) 177999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 178099653d4eSeschrock 1781a43d325bSek if (avail_spare) 178299653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 178399653d4eSeschrock 1784fa94a07fSbrendan if (l2cache) 1785fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 1786fa94a07fSbrendan 178799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1788fa9e4066Sahrens zc.zc_cookie = replacing; 1789fa9e4066Sahrens 179099653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 179199653d4eSeschrock &child, &children) != 0 || children != 1) { 179299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 179399653d4eSeschrock "new device must be a single disk")); 179499653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 179599653d4eSeschrock } 179699653d4eSeschrock 179799653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 179899653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 179999653d4eSeschrock 18000430f8daSeschrock if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL) 18010430f8daSeschrock return (-1); 18020430f8daSeschrock 180399653d4eSeschrock /* 180499653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 180599653d4eSeschrock * replace it with another hot spare. 180699653d4eSeschrock */ 180799653d4eSeschrock if (replacing && 180899653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 1809ee0eb9f2SEric Schrock (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 1810ee0eb9f2SEric Schrock NULL) == NULL || !avail_spare) && 1811ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 1)) { 181299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 181399653d4eSeschrock "can only be replaced by another hot spare")); 18140430f8daSeschrock free(newname); 181599653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 181699653d4eSeschrock } 181799653d4eSeschrock 181899653d4eSeschrock /* 181999653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 182099653d4eSeschrock * already spared device. 182199653d4eSeschrock */ 182299653d4eSeschrock if (replacing && 182399653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1824ee0eb9f2SEric Schrock zpool_find_vdev(zhp, newname, &avail_spare, 1825ee0eb9f2SEric Schrock &l2cache, NULL) != NULL && avail_spare && 1826ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 0)) { 182799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 182899653d4eSeschrock "device has already been replaced with a spare")); 18290430f8daSeschrock free(newname); 183099653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 183199653d4eSeschrock } 183299653d4eSeschrock 18330430f8daSeschrock free(newname); 18340430f8daSeschrock 1835990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 183699653d4eSeschrock return (-1); 1837fa9e4066Sahrens 1838ecd6cf80Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 1839fa9e4066Sahrens 1840e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1841fa9e4066Sahrens 1842*b5b76fecSGeorge Wilson if (ret == 0) { 1843*b5b76fecSGeorge Wilson if (rootpool) { 1844*b5b76fecSGeorge Wilson /* 1845*b5b76fecSGeorge Wilson * XXX - This should be removed once we can 1846*b5b76fecSGeorge Wilson * automatically install the bootblocks on the 1847*b5b76fecSGeorge Wilson * newly attached disk. 1848*b5b76fecSGeorge Wilson */ 1849*b5b76fecSGeorge Wilson (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 1850*b5b76fecSGeorge Wilson "be sure to invoke %s to make '%s' bootable.\n"), 1851*b5b76fecSGeorge Wilson BOOTCMD, new_disk); 1852*b5b76fecSGeorge Wilson } 1853fa9e4066Sahrens return (0); 1854*b5b76fecSGeorge Wilson } 1855fa9e4066Sahrens 1856fa9e4066Sahrens switch (errno) { 1857ea8dc4b6Seschrock case ENOTSUP: 1858fa9e4066Sahrens /* 1859fa9e4066Sahrens * Can't attach to or replace this type of vdev. 1860fa9e4066Sahrens */ 18618654d025Sperrin if (replacing) { 1862ee0eb9f2SEric Schrock if (islog) 18638654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18648654d025Sperrin "cannot replace a log with a spare")); 18658654d025Sperrin else 18668654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 18678654d025Sperrin "cannot replace a replacing device")); 18688654d025Sperrin } else { 186999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 187099653d4eSeschrock "can only attach to mirrors and top-level " 187199653d4eSeschrock "disks")); 18728654d025Sperrin } 187399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 1874fa9e4066Sahrens break; 1875fa9e4066Sahrens 1876ea8dc4b6Seschrock case EINVAL: 1877fa9e4066Sahrens /* 1878fa9e4066Sahrens * The new device must be a single disk. 1879fa9e4066Sahrens */ 188099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 188199653d4eSeschrock "new device must be a single disk")); 188299653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 1883fa9e4066Sahrens break; 1884fa9e4066Sahrens 1885ea8dc4b6Seschrock case EBUSY: 188699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 188799653d4eSeschrock new_disk); 188899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1889fa9e4066Sahrens break; 1890fa9e4066Sahrens 1891ea8dc4b6Seschrock case EOVERFLOW: 1892fa9e4066Sahrens /* 1893fa9e4066Sahrens * The new device is too small. 1894fa9e4066Sahrens */ 189599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 189699653d4eSeschrock "device is too small")); 189799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1898fa9e4066Sahrens break; 1899fa9e4066Sahrens 1900ea8dc4b6Seschrock case EDOM: 1901fa9e4066Sahrens /* 1902fa9e4066Sahrens * The new device has a different alignment requirement. 1903fa9e4066Sahrens */ 190499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 190599653d4eSeschrock "devices have different sector alignment")); 190699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1907fa9e4066Sahrens break; 1908fa9e4066Sahrens 1909ea8dc4b6Seschrock case ENAMETOOLONG: 1910fa9e4066Sahrens /* 1911fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 1912fa9e4066Sahrens */ 191399653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 1914fa9e4066Sahrens break; 1915fa9e4066Sahrens 1916ea8dc4b6Seschrock default: 191799653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1918fa9e4066Sahrens } 1919fa9e4066Sahrens 192099653d4eSeschrock return (-1); 1921fa9e4066Sahrens } 1922fa9e4066Sahrens 1923fa9e4066Sahrens /* 1924fa9e4066Sahrens * Detach the specified device. 1925fa9e4066Sahrens */ 1926fa9e4066Sahrens int 1927fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 1928fa9e4066Sahrens { 1929fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1930fa9e4066Sahrens char msg[1024]; 193199653d4eSeschrock nvlist_t *tgt; 1932fa94a07fSbrendan boolean_t avail_spare, l2cache; 193399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1934fa9e4066Sahrens 1935ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1936ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 1937ea8dc4b6Seschrock 1938fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1939ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1940ee0eb9f2SEric Schrock NULL)) == 0) 194199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1942fa9e4066Sahrens 1943a43d325bSek if (avail_spare) 194499653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 194599653d4eSeschrock 1946fa94a07fSbrendan if (l2cache) 1947fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 1948fa94a07fSbrendan 194999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 195099653d4eSeschrock 1951ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 1952fa9e4066Sahrens return (0); 1953fa9e4066Sahrens 1954fa9e4066Sahrens switch (errno) { 1955fa9e4066Sahrens 1956ea8dc4b6Seschrock case ENOTSUP: 1957fa9e4066Sahrens /* 1958fa9e4066Sahrens * Can't detach from this type of vdev. 1959fa9e4066Sahrens */ 196099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 196199653d4eSeschrock "applicable to mirror and replacing vdevs")); 196299653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 1963fa9e4066Sahrens break; 1964fa9e4066Sahrens 1965ea8dc4b6Seschrock case EBUSY: 1966fa9e4066Sahrens /* 1967fa9e4066Sahrens * There are no other replicas of this device. 1968fa9e4066Sahrens */ 196999653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 1970fa9e4066Sahrens break; 1971fa9e4066Sahrens 1972ea8dc4b6Seschrock default: 197399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1974ea8dc4b6Seschrock } 1975ea8dc4b6Seschrock 197699653d4eSeschrock return (-1); 197799653d4eSeschrock } 197899653d4eSeschrock 197999653d4eSeschrock /* 1980fa94a07fSbrendan * Remove the given device. Currently, this is supported only for hot spares 1981fa94a07fSbrendan * and level 2 cache devices. 198299653d4eSeschrock */ 198399653d4eSeschrock int 198499653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 198599653d4eSeschrock { 198699653d4eSeschrock zfs_cmd_t zc = { 0 }; 198799653d4eSeschrock char msg[1024]; 198899653d4eSeschrock nvlist_t *tgt; 1989fa94a07fSbrendan boolean_t avail_spare, l2cache; 199099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 199199653d4eSeschrock 199299653d4eSeschrock (void) snprintf(msg, sizeof (msg), 199399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 199499653d4eSeschrock 199599653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1996ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1997ee0eb9f2SEric Schrock NULL)) == 0) 199899653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 199999653d4eSeschrock 2000fa94a07fSbrendan if (!avail_spare && !l2cache) { 200199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2002fa94a07fSbrendan "only inactive hot spares or cache devices " 2003fa94a07fSbrendan "can be removed")); 200499653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 200599653d4eSeschrock } 200699653d4eSeschrock 200799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 200899653d4eSeschrock 2009ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 201099653d4eSeschrock return (0); 201199653d4eSeschrock 201299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2013ea8dc4b6Seschrock } 2014ea8dc4b6Seschrock 2015ea8dc4b6Seschrock /* 2016ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 2017ea8dc4b6Seschrock */ 2018ea8dc4b6Seschrock int 2019ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 2020ea8dc4b6Seschrock { 2021ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2022ea8dc4b6Seschrock char msg[1024]; 202399653d4eSeschrock nvlist_t *tgt; 2024fa94a07fSbrendan boolean_t avail_spare, l2cache; 202599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2026ea8dc4b6Seschrock 2027ea8dc4b6Seschrock if (path) 2028ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2029ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2030e9dbad6fSeschrock path); 2031ea8dc4b6Seschrock else 2032ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2033ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2034ea8dc4b6Seschrock zhp->zpool_name); 2035ea8dc4b6Seschrock 2036ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 203799653d4eSeschrock if (path) { 2038fa94a07fSbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 2039ee0eb9f2SEric Schrock &l2cache, NULL)) == 0) 204099653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2041ea8dc4b6Seschrock 2042fa94a07fSbrendan /* 2043fa94a07fSbrendan * Don't allow error clearing for hot spares. Do allow 2044fa94a07fSbrendan * error clearing for l2cache devices. 2045fa94a07fSbrendan */ 2046a43d325bSek if (avail_spare) 204799653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2048ea8dc4b6Seschrock 204999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 205099653d4eSeschrock &zc.zc_guid) == 0); 2051fa9e4066Sahrens } 2052fa9e4066Sahrens 2053ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 205499653d4eSeschrock return (0); 205599653d4eSeschrock 205699653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2057fa9e4066Sahrens } 2058fa9e4066Sahrens 20593d7072f8Seschrock /* 20603d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 20613d7072f8Seschrock */ 20623d7072f8Seschrock int 20633d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 20643d7072f8Seschrock { 20653d7072f8Seschrock zfs_cmd_t zc = { 0 }; 20663d7072f8Seschrock char msg[1024]; 20673d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 20683d7072f8Seschrock 20693d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 20703d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 20713d7072f8Seschrock guid); 20723d7072f8Seschrock 20733d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20743d7072f8Seschrock zc.zc_guid = guid; 20753d7072f8Seschrock 20763d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 20773d7072f8Seschrock return (0); 20783d7072f8Seschrock 20793d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 20803d7072f8Seschrock } 20813d7072f8Seschrock 2082f3861e1aSahl /* 2083f3861e1aSahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 2084f3861e1aSahl * hierarchy. 2085f3861e1aSahl */ 2086f3861e1aSahl int 2087f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 2088f3861e1aSahl void *data) 2089fa9e4066Sahrens { 2090f3861e1aSahl libzfs_handle_t *hdl = zhp->zpool_hdl; 2091f3861e1aSahl char (*paths)[MAXPATHLEN]; 2092f3861e1aSahl size_t size = 4; 2093f3861e1aSahl int curr, fd, base, ret = 0; 2094f3861e1aSahl DIR *dirp; 2095f3861e1aSahl struct dirent *dp; 2096f3861e1aSahl struct stat st; 2097f3861e1aSahl 2098f3861e1aSahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 2099f3861e1aSahl return (errno == ENOENT ? 0 : -1); 2100f3861e1aSahl 2101f3861e1aSahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 2102f3861e1aSahl int err = errno; 2103f3861e1aSahl (void) close(base); 2104f3861e1aSahl return (err == ENOENT ? 0 : -1); 2105f3861e1aSahl } 2106fa9e4066Sahrens 2107fa9e4066Sahrens /* 2108f3861e1aSahl * Oddly this wasn't a directory -- ignore that failure since we 2109f3861e1aSahl * know there are no links lower in the (non-existant) hierarchy. 2110fa9e4066Sahrens */ 2111f3861e1aSahl if (!S_ISDIR(st.st_mode)) { 2112f3861e1aSahl (void) close(base); 2113f3861e1aSahl return (0); 2114fa9e4066Sahrens } 2115fa9e4066Sahrens 2116f3861e1aSahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 2117f3861e1aSahl (void) close(base); 2118f3861e1aSahl return (-1); 2119f3861e1aSahl } 2120f3861e1aSahl 2121f3861e1aSahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 2122f3861e1aSahl curr = 0; 2123f3861e1aSahl 2124f3861e1aSahl while (curr >= 0) { 2125f3861e1aSahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 2126f3861e1aSahl goto err; 2127f3861e1aSahl 2128f3861e1aSahl if (S_ISDIR(st.st_mode)) { 2129f3861e1aSahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 2130f3861e1aSahl goto err; 2131f3861e1aSahl 2132f3861e1aSahl if ((dirp = fdopendir(fd)) == NULL) { 2133f3861e1aSahl (void) close(fd); 2134f3861e1aSahl goto err; 2135f3861e1aSahl } 2136f3861e1aSahl 2137f3861e1aSahl while ((dp = readdir(dirp)) != NULL) { 2138f3861e1aSahl if (dp->d_name[0] == '.') 2139f3861e1aSahl continue; 2140f3861e1aSahl 2141f3861e1aSahl if (curr + 1 == size) { 2142f3861e1aSahl paths = zfs_realloc(hdl, paths, 2143f3861e1aSahl size * sizeof (paths[0]), 2144f3861e1aSahl size * 2 * sizeof (paths[0])); 2145f3861e1aSahl if (paths == NULL) { 2146f3861e1aSahl (void) closedir(dirp); 2147f3861e1aSahl (void) close(fd); 2148f3861e1aSahl goto err; 2149f3861e1aSahl } 2150f3861e1aSahl 2151f3861e1aSahl size *= 2; 2152f3861e1aSahl } 2153f3861e1aSahl 2154f3861e1aSahl (void) strlcpy(paths[curr + 1], paths[curr], 2155f3861e1aSahl sizeof (paths[curr + 1])); 2156f3861e1aSahl (void) strlcat(paths[curr], "/", 2157f3861e1aSahl sizeof (paths[curr])); 2158f3861e1aSahl (void) strlcat(paths[curr], dp->d_name, 2159f3861e1aSahl sizeof (paths[curr])); 2160f3861e1aSahl curr++; 2161f3861e1aSahl } 2162f3861e1aSahl 2163f3861e1aSahl (void) closedir(dirp); 2164f3861e1aSahl 2165f3861e1aSahl } else { 2166f3861e1aSahl if ((ret = cb(paths[curr], data)) != 0) 2167f3861e1aSahl break; 2168f3861e1aSahl } 2169f3861e1aSahl 2170f3861e1aSahl curr--; 2171f3861e1aSahl } 2172f3861e1aSahl 2173f3861e1aSahl free(paths); 2174f3861e1aSahl (void) close(base); 2175f3861e1aSahl 2176f3861e1aSahl return (ret); 2177f3861e1aSahl 2178f3861e1aSahl err: 2179f3861e1aSahl free(paths); 2180f3861e1aSahl (void) close(base); 2181f3861e1aSahl return (-1); 2182f3861e1aSahl } 2183f3861e1aSahl 2184f3861e1aSahl typedef struct zvol_cb { 2185f3861e1aSahl zpool_handle_t *zcb_pool; 2186f3861e1aSahl boolean_t zcb_create; 2187f3861e1aSahl } zvol_cb_t; 2188f3861e1aSahl 2189f3861e1aSahl /*ARGSUSED*/ 2190f3861e1aSahl static int 2191f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data) 2192f3861e1aSahl { 21933aefe2c7Sahrens int ret = 0; 2194f3861e1aSahl 21953aefe2c7Sahrens if (ZFS_IS_VOLUME(zhp)) { 2196f3861e1aSahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 21973aefe2c7Sahrens ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL); 21983aefe2c7Sahrens } 2199f3861e1aSahl 22003aefe2c7Sahrens if (ret == 0) 22013aefe2c7Sahrens ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL); 2202fa9e4066Sahrens 2203fa9e4066Sahrens zfs_close(zhp); 2204f3861e1aSahl 2205fa9e4066Sahrens return (ret); 2206fa9e4066Sahrens } 2207fa9e4066Sahrens 2208fa9e4066Sahrens /* 2209fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 2210fa9e4066Sahrens */ 2211fa9e4066Sahrens int 2212fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 2213fa9e4066Sahrens { 2214fa9e4066Sahrens zfs_handle_t *zfp; 2215fa9e4066Sahrens int ret; 2216fa9e4066Sahrens 2217fa9e4066Sahrens /* 2218fa9e4066Sahrens * If the pool is unavailable, just return success. 2219fa9e4066Sahrens */ 222099653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 222199653d4eSeschrock zhp->zpool_name)) == NULL) 2222fa9e4066Sahrens return (0); 2223fa9e4066Sahrens 22243aefe2c7Sahrens ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL); 2225fa9e4066Sahrens 2226fa9e4066Sahrens zfs_close(zfp); 2227fa9e4066Sahrens return (ret); 2228fa9e4066Sahrens } 2229fa9e4066Sahrens 2230f3861e1aSahl static int 2231f3861e1aSahl do_zvol_remove(const char *dataset, void *data) 2232f3861e1aSahl { 2233f3861e1aSahl zpool_handle_t *zhp = data; 2234f3861e1aSahl 2235f3861e1aSahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 2236f3861e1aSahl } 2237f3861e1aSahl 2238fa9e4066Sahrens /* 2239f3861e1aSahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 2240f3861e1aSahl * by examining the /dev links so that a corrupted pool doesn't impede this 2241f3861e1aSahl * operation. 2242fa9e4066Sahrens */ 2243fa9e4066Sahrens int 2244fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 2245fa9e4066Sahrens { 2246f3861e1aSahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 2247fa9e4066Sahrens } 2248c67d9675Seschrock 2249c67d9675Seschrock /* 2250c67d9675Seschrock * Convert from a devid string to a path. 2251c67d9675Seschrock */ 2252c67d9675Seschrock static char * 2253c67d9675Seschrock devid_to_path(char *devid_str) 2254c67d9675Seschrock { 2255c67d9675Seschrock ddi_devid_t devid; 2256c67d9675Seschrock char *minor; 2257c67d9675Seschrock char *path; 2258c67d9675Seschrock devid_nmlist_t *list = NULL; 2259c67d9675Seschrock int ret; 2260c67d9675Seschrock 2261c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 2262c67d9675Seschrock return (NULL); 2263c67d9675Seschrock 2264c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 2265c67d9675Seschrock 2266c67d9675Seschrock devid_str_free(minor); 2267c67d9675Seschrock devid_free(devid); 2268c67d9675Seschrock 2269c67d9675Seschrock if (ret != 0) 2270c67d9675Seschrock return (NULL); 2271c67d9675Seschrock 227299653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 227399653d4eSeschrock return (NULL); 227499653d4eSeschrock 2275c67d9675Seschrock devid_free_nmlist(list); 2276c67d9675Seschrock 2277c67d9675Seschrock return (path); 2278c67d9675Seschrock } 2279c67d9675Seschrock 2280c67d9675Seschrock /* 2281c67d9675Seschrock * Convert from a path to a devid string. 2282c67d9675Seschrock */ 2283c67d9675Seschrock static char * 2284c67d9675Seschrock path_to_devid(const char *path) 2285c67d9675Seschrock { 2286c67d9675Seschrock int fd; 2287c67d9675Seschrock ddi_devid_t devid; 2288c67d9675Seschrock char *minor, *ret; 2289c67d9675Seschrock 2290c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 2291c67d9675Seschrock return (NULL); 2292c67d9675Seschrock 2293c67d9675Seschrock minor = NULL; 2294c67d9675Seschrock ret = NULL; 2295c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 2296c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 2297c67d9675Seschrock ret = devid_str_encode(devid, minor); 2298c67d9675Seschrock if (minor != NULL) 2299c67d9675Seschrock devid_str_free(minor); 2300c67d9675Seschrock devid_free(devid); 2301c67d9675Seschrock } 2302c67d9675Seschrock (void) close(fd); 2303c67d9675Seschrock 2304c67d9675Seschrock return (ret); 2305c67d9675Seschrock } 2306c67d9675Seschrock 2307c67d9675Seschrock /* 2308c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 2309c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 2310c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 2311c67d9675Seschrock */ 2312c67d9675Seschrock static void 2313c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 2314c67d9675Seschrock { 2315c67d9675Seschrock zfs_cmd_t zc = { 0 }; 2316c67d9675Seschrock 2317c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2318e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 2319c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2320ea8dc4b6Seschrock &zc.zc_guid) == 0); 2321c67d9675Seschrock 232299653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 2323c67d9675Seschrock } 2324c67d9675Seschrock 2325c67d9675Seschrock /* 2326c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 2327c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 2328c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 2329c67d9675Seschrock * trailing 's0' slice name. 2330c67d9675Seschrock * 2331c67d9675Seschrock * This routine is also responsible for identifying when disks have been 2332c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 2333c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 2334c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 2335c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 2336c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 2337c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 2338c67d9675Seschrock * of these checks. 2339c67d9675Seschrock */ 2340c67d9675Seschrock char * 234199653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 2342c67d9675Seschrock { 2343c67d9675Seschrock char *path, *devid; 2344ea8dc4b6Seschrock uint64_t value; 2345ea8dc4b6Seschrock char buf[64]; 23463d7072f8Seschrock vdev_stat_t *vs; 23473d7072f8Seschrock uint_t vsc; 2348c67d9675Seschrock 2349ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2350ea8dc4b6Seschrock &value) == 0) { 2351ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2352ea8dc4b6Seschrock &value) == 0); 23535ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 23545ad82045Snd (u_longlong_t)value); 2355ea8dc4b6Seschrock path = buf; 2356ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 2357c67d9675Seschrock 23583d7072f8Seschrock /* 23593d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 23603d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 23613d7072f8Seschrock * open a misbehaving device, which can have undesirable 23623d7072f8Seschrock * effects. 23633d7072f8Seschrock */ 23643d7072f8Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 23653d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 23663d7072f8Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 23673d7072f8Seschrock zhp != NULL && 2368c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 2369c67d9675Seschrock /* 2370c67d9675Seschrock * Determine if the current path is correct. 2371c67d9675Seschrock */ 2372c67d9675Seschrock char *newdevid = path_to_devid(path); 2373c67d9675Seschrock 2374c67d9675Seschrock if (newdevid == NULL || 2375c67d9675Seschrock strcmp(devid, newdevid) != 0) { 2376c67d9675Seschrock char *newpath; 2377c67d9675Seschrock 2378c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 2379c67d9675Seschrock /* 2380c67d9675Seschrock * Update the path appropriately. 2381c67d9675Seschrock */ 2382c67d9675Seschrock set_path(zhp, nv, newpath); 238399653d4eSeschrock if (nvlist_add_string(nv, 238499653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 238599653d4eSeschrock verify(nvlist_lookup_string(nv, 238699653d4eSeschrock ZPOOL_CONFIG_PATH, 238799653d4eSeschrock &path) == 0); 2388c67d9675Seschrock free(newpath); 2389c67d9675Seschrock } 2390c67d9675Seschrock } 2391c67d9675Seschrock 239299653d4eSeschrock if (newdevid) 239399653d4eSeschrock devid_str_free(newdevid); 2394c67d9675Seschrock } 2395c67d9675Seschrock 2396c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 2397c67d9675Seschrock path += 9; 2398c67d9675Seschrock 2399c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 2400ea8dc4b6Seschrock &value) == 0 && value) { 240199653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 240299653d4eSeschrock if (tmp == NULL) 240399653d4eSeschrock return (NULL); 2404c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 2405c67d9675Seschrock return (tmp); 2406c67d9675Seschrock } 2407c67d9675Seschrock } else { 2408c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 240999653d4eSeschrock 241099653d4eSeschrock /* 241199653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 241299653d4eSeschrock */ 241399653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 241499653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 241599653d4eSeschrock &value) == 0); 241699653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 24175ad82045Snd (u_longlong_t)value); 241899653d4eSeschrock path = buf; 241999653d4eSeschrock } 2420c67d9675Seschrock } 2421c67d9675Seschrock 242299653d4eSeschrock return (zfs_strdup(hdl, path)); 2423c67d9675Seschrock } 2424ea8dc4b6Seschrock 2425ea8dc4b6Seschrock static int 2426ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 2427ea8dc4b6Seschrock { 2428ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 2429ea8dc4b6Seschrock } 2430ea8dc4b6Seschrock 2431ea8dc4b6Seschrock /* 2432ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 2433ea8dc4b6Seschrock * caller. 2434ea8dc4b6Seschrock */ 2435ea8dc4b6Seschrock int 243655434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 2437ea8dc4b6Seschrock { 2438ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2439ea8dc4b6Seschrock uint64_t count; 2440e9dbad6fSeschrock zbookmark_t *zb = NULL; 244155434c77Sek int i; 2442ea8dc4b6Seschrock 2443ea8dc4b6Seschrock /* 2444ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 2445ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 2446ea8dc4b6Seschrock * entire list. 2447ea8dc4b6Seschrock */ 2448ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 2449ea8dc4b6Seschrock &count) == 0); 245075519f38Sek if (count == 0) 245175519f38Sek return (0); 2452e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 24535ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 245499653d4eSeschrock return (-1); 2455e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 2456ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2457ea8dc4b6Seschrock for (;;) { 245899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 245999653d4eSeschrock &zc) != 0) { 2460e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 2461ea8dc4b6Seschrock if (errno == ENOMEM) { 2462bf561db0Svb count = zc.zc_nvlist_dst_size; 2463e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 2464bf561db0Svb zfs_alloc(zhp->zpool_hdl, count * 2465bf561db0Svb sizeof (zbookmark_t))) == (uintptr_t)NULL) 246699653d4eSeschrock return (-1); 2467ea8dc4b6Seschrock } else { 2468ea8dc4b6Seschrock return (-1); 2469ea8dc4b6Seschrock } 2470ea8dc4b6Seschrock } else { 2471ea8dc4b6Seschrock break; 2472ea8dc4b6Seschrock } 2473ea8dc4b6Seschrock } 2474ea8dc4b6Seschrock 2475ea8dc4b6Seschrock /* 2476ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 2477ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 2478e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 2479ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 2480ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 2481ea8dc4b6Seschrock */ 2482e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 2483e9dbad6fSeschrock zc.zc_nvlist_dst_size; 2484e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 2485ea8dc4b6Seschrock 2486ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 2487ea8dc4b6Seschrock 248855434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 2489ea8dc4b6Seschrock 2490ea8dc4b6Seschrock /* 249155434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 2492ea8dc4b6Seschrock */ 2493ea8dc4b6Seschrock for (i = 0; i < count; i++) { 2494ea8dc4b6Seschrock nvlist_t *nv; 2495ea8dc4b6Seschrock 2496c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 2497c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 2498c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 2499ea8dc4b6Seschrock continue; 2500ea8dc4b6Seschrock 250155434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 250255434c77Sek goto nomem; 250355434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 250455434c77Sek zb[i].zb_objset) != 0) { 250555434c77Sek nvlist_free(nv); 250699653d4eSeschrock goto nomem; 2507ea8dc4b6Seschrock } 250855434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 250955434c77Sek zb[i].zb_object) != 0) { 251055434c77Sek nvlist_free(nv); 251155434c77Sek goto nomem; 251255434c77Sek } 251355434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 251455434c77Sek nvlist_free(nv); 251555434c77Sek goto nomem; 251655434c77Sek } 251755434c77Sek nvlist_free(nv); 2518ea8dc4b6Seschrock } 2519ea8dc4b6Seschrock 25203ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 2521ea8dc4b6Seschrock return (0); 252299653d4eSeschrock 252399653d4eSeschrock nomem: 2524e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 252599653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 2526ea8dc4b6Seschrock } 2527eaca9bbdSeschrock 2528eaca9bbdSeschrock /* 2529eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 2530eaca9bbdSeschrock */ 2531eaca9bbdSeschrock int 2532990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 2533eaca9bbdSeschrock { 2534eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 253599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2536eaca9bbdSeschrock 2537eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2538990b4856Slling zc.zc_cookie = new_version; 2539990b4856Slling 2540ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 2541ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 254299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 254399653d4eSeschrock zhp->zpool_name)); 2544eaca9bbdSeschrock return (0); 2545eaca9bbdSeschrock } 254606eeb2adSek 254706eeb2adSek void 25482a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv, 25492a6b87f0Sek char *history_str) 255006eeb2adSek { 255106eeb2adSek int i; 255206eeb2adSek 25532a6b87f0Sek (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 25542a6b87f0Sek for (i = 1; i < argc; i++) { 25552a6b87f0Sek if (strlen(history_str) + 1 + strlen(argv[i]) > 25562a6b87f0Sek HIS_MAX_RECORD_LEN) 25572a6b87f0Sek break; 25582a6b87f0Sek (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 25592a6b87f0Sek (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 25602a6b87f0Sek } 25612a6b87f0Sek } 25622a6b87f0Sek 25632a6b87f0Sek /* 25642a6b87f0Sek * Stage command history for logging. 25652a6b87f0Sek */ 25662a6b87f0Sek int 25672a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 25682a6b87f0Sek { 25692a6b87f0Sek if (history_str == NULL) 25702a6b87f0Sek return (EINVAL); 25712a6b87f0Sek 25722a6b87f0Sek if (strlen(history_str) > HIS_MAX_RECORD_LEN) 25732a6b87f0Sek return (EINVAL); 25742a6b87f0Sek 2575228975ccSek if (hdl->libzfs_log_str != NULL) 2576ecd6cf80Smarks free(hdl->libzfs_log_str); 257706eeb2adSek 25782a6b87f0Sek if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 25792a6b87f0Sek return (no_memory(hdl)); 258006eeb2adSek 25812a6b87f0Sek return (0); 258206eeb2adSek } 258306eeb2adSek 258406eeb2adSek /* 258506eeb2adSek * Perform ioctl to get some command history of a pool. 258606eeb2adSek * 258706eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 258806eeb2adSek * logical offset of the history buffer to start reading from. 258906eeb2adSek * 259006eeb2adSek * Upon return, 'off' is the next logical offset to read from and 259106eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 259206eeb2adSek */ 259306eeb2adSek static int 259406eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 259506eeb2adSek { 259606eeb2adSek zfs_cmd_t zc = { 0 }; 259706eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 259806eeb2adSek 259906eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 260006eeb2adSek 260106eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 260206eeb2adSek zc.zc_history_len = *len; 260306eeb2adSek zc.zc_history_offset = *off; 260406eeb2adSek 260506eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 260606eeb2adSek switch (errno) { 260706eeb2adSek case EPERM: 2608ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 2609ece3d9b3Slling dgettext(TEXT_DOMAIN, 261006eeb2adSek "cannot show history for pool '%s'"), 261106eeb2adSek zhp->zpool_name)); 261206eeb2adSek case ENOENT: 2613ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 261406eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 261506eeb2adSek "'%s'"), zhp->zpool_name)); 2616d7306b64Sek case ENOTSUP: 2617d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 2618d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 2619d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 262006eeb2adSek default: 2621ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 262206eeb2adSek dgettext(TEXT_DOMAIN, 262306eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 262406eeb2adSek } 262506eeb2adSek } 262606eeb2adSek 262706eeb2adSek *len = zc.zc_history_len; 262806eeb2adSek *off = zc.zc_history_offset; 262906eeb2adSek 263006eeb2adSek return (0); 263106eeb2adSek } 263206eeb2adSek 263306eeb2adSek /* 263406eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 263506eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 263606eeb2adSek * processed as there wasn't a complete record. 263706eeb2adSek */ 263806eeb2adSek static int 263906eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 264006eeb2adSek nvlist_t ***records, uint_t *numrecords) 264106eeb2adSek { 264206eeb2adSek uint64_t reclen; 264306eeb2adSek nvlist_t *nv; 264406eeb2adSek int i; 264506eeb2adSek 264606eeb2adSek while (bytes_read > sizeof (reclen)) { 264706eeb2adSek 264806eeb2adSek /* get length of packed record (stored as little endian) */ 264906eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 265006eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 265106eeb2adSek 265206eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 265306eeb2adSek break; 265406eeb2adSek 265506eeb2adSek /* unpack record */ 265606eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 265706eeb2adSek return (ENOMEM); 265806eeb2adSek bytes_read -= sizeof (reclen) + reclen; 265906eeb2adSek buf += sizeof (reclen) + reclen; 266006eeb2adSek 266106eeb2adSek /* add record to nvlist array */ 266206eeb2adSek (*numrecords)++; 266306eeb2adSek if (ISP2(*numrecords + 1)) { 266406eeb2adSek *records = realloc(*records, 266506eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 266606eeb2adSek } 266706eeb2adSek (*records)[*numrecords - 1] = nv; 266806eeb2adSek } 266906eeb2adSek 267006eeb2adSek *leftover = bytes_read; 267106eeb2adSek return (0); 267206eeb2adSek } 267306eeb2adSek 267406eeb2adSek #define HIS_BUF_LEN (128*1024) 267506eeb2adSek 267606eeb2adSek /* 267706eeb2adSek * Retrieve the command history of a pool. 267806eeb2adSek */ 267906eeb2adSek int 268006eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 268106eeb2adSek { 268206eeb2adSek char buf[HIS_BUF_LEN]; 268306eeb2adSek uint64_t off = 0; 268406eeb2adSek nvlist_t **records = NULL; 268506eeb2adSek uint_t numrecords = 0; 268606eeb2adSek int err, i; 268706eeb2adSek 268806eeb2adSek do { 268906eeb2adSek uint64_t bytes_read = sizeof (buf); 269006eeb2adSek uint64_t leftover; 269106eeb2adSek 269206eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 269306eeb2adSek break; 269406eeb2adSek 269506eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 269606eeb2adSek if (!bytes_read) 269706eeb2adSek break; 269806eeb2adSek 269906eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 270006eeb2adSek &leftover, &records, &numrecords)) != 0) 270106eeb2adSek break; 270206eeb2adSek off -= leftover; 270306eeb2adSek 270406eeb2adSek /* CONSTCOND */ 270506eeb2adSek } while (1); 270606eeb2adSek 270706eeb2adSek if (!err) { 270806eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 270906eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 271006eeb2adSek records, numrecords) == 0); 271106eeb2adSek } 271206eeb2adSek for (i = 0; i < numrecords; i++) 271306eeb2adSek nvlist_free(records[i]); 271406eeb2adSek free(records); 271506eeb2adSek 271606eeb2adSek return (err); 271706eeb2adSek } 271855434c77Sek 271955434c77Sek void 272055434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 272155434c77Sek char *pathname, size_t len) 272255434c77Sek { 272355434c77Sek zfs_cmd_t zc = { 0 }; 272455434c77Sek boolean_t mounted = B_FALSE; 272555434c77Sek char *mntpnt = NULL; 272655434c77Sek char dsname[MAXNAMELEN]; 272755434c77Sek 272855434c77Sek if (dsobj == 0) { 272955434c77Sek /* special case for the MOS */ 273055434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 273155434c77Sek return; 273255434c77Sek } 273355434c77Sek 273455434c77Sek /* get the dataset's name */ 273555434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 273655434c77Sek zc.zc_obj = dsobj; 273755434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 273855434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 273955434c77Sek /* just write out a path of two object numbers */ 274055434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 274155434c77Sek dsobj, obj); 274255434c77Sek return; 274355434c77Sek } 274455434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 274555434c77Sek 274655434c77Sek /* find out if the dataset is mounted */ 274755434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 274855434c77Sek 274955434c77Sek /* get the corrupted object's path */ 275055434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 275155434c77Sek zc.zc_obj = obj; 275255434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 275355434c77Sek &zc) == 0) { 275455434c77Sek if (mounted) { 275555434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 275655434c77Sek zc.zc_value); 275755434c77Sek } else { 275855434c77Sek (void) snprintf(pathname, len, "%s:%s", 275955434c77Sek dsname, zc.zc_value); 276055434c77Sek } 276155434c77Sek } else { 276255434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 276355434c77Sek } 276455434c77Sek free(mntpnt); 276555434c77Sek } 2766b1b8ab34Slling 27678488aeb5Staylor #define RDISK_ROOT "/dev/rdsk" 27688488aeb5Staylor #define BACKUP_SLICE "s2" 27698488aeb5Staylor /* 27708488aeb5Staylor * Don't start the slice at the default block of 34; many storage 27718488aeb5Staylor * devices will use a stripe width of 128k, so start there instead. 27728488aeb5Staylor */ 27738488aeb5Staylor #define NEW_START_BLOCK 256 27748488aeb5Staylor 277515e6edf1Sgw /* 277615e6edf1Sgw * Read the EFI label from the config, if a label does not exist then 277715e6edf1Sgw * pass back the error to the caller. If the caller has passed a non-NULL 277815e6edf1Sgw * diskaddr argument then we set it to the starting address of the EFI 277915e6edf1Sgw * partition. 278015e6edf1Sgw */ 278115e6edf1Sgw static int 278215e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb) 278315e6edf1Sgw { 278415e6edf1Sgw char *path; 278515e6edf1Sgw int fd; 278615e6edf1Sgw char diskname[MAXPATHLEN]; 278715e6edf1Sgw int err = -1; 278815e6edf1Sgw 278915e6edf1Sgw if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 279015e6edf1Sgw return (err); 279115e6edf1Sgw 279215e6edf1Sgw (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 279315e6edf1Sgw strrchr(path, '/')); 279415e6edf1Sgw if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 279515e6edf1Sgw struct dk_gpt *vtoc; 279615e6edf1Sgw 279715e6edf1Sgw if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 279815e6edf1Sgw if (sb != NULL) 279915e6edf1Sgw *sb = vtoc->efi_parts[0].p_start; 280015e6edf1Sgw efi_free(vtoc); 280115e6edf1Sgw } 280215e6edf1Sgw (void) close(fd); 280315e6edf1Sgw } 280415e6edf1Sgw return (err); 280515e6edf1Sgw } 280615e6edf1Sgw 28078488aeb5Staylor /* 28088488aeb5Staylor * determine where a partition starts on a disk in the current 28098488aeb5Staylor * configuration 28108488aeb5Staylor */ 28118488aeb5Staylor static diskaddr_t 28128488aeb5Staylor find_start_block(nvlist_t *config) 28138488aeb5Staylor { 28148488aeb5Staylor nvlist_t **child; 28158488aeb5Staylor uint_t c, children; 28168488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 28178488aeb5Staylor uint64_t wholedisk; 28188488aeb5Staylor 28198488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 28208488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 28218488aeb5Staylor if (nvlist_lookup_uint64(config, 28228488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 28238488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 28248488aeb5Staylor return (MAXOFFSET_T); 28258488aeb5Staylor } 282615e6edf1Sgw if (read_efi_label(config, &sb) < 0) 282715e6edf1Sgw sb = MAXOFFSET_T; 28288488aeb5Staylor return (sb); 28298488aeb5Staylor } 28308488aeb5Staylor 28318488aeb5Staylor for (c = 0; c < children; c++) { 28328488aeb5Staylor sb = find_start_block(child[c]); 28338488aeb5Staylor if (sb != MAXOFFSET_T) { 28348488aeb5Staylor return (sb); 28358488aeb5Staylor } 28368488aeb5Staylor } 28378488aeb5Staylor return (MAXOFFSET_T); 28388488aeb5Staylor } 28398488aeb5Staylor 28408488aeb5Staylor /* 28418488aeb5Staylor * Label an individual disk. The name provided is the short name, 28428488aeb5Staylor * stripped of any leading /dev path. 28438488aeb5Staylor */ 28448488aeb5Staylor int 28458488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 28468488aeb5Staylor { 28478488aeb5Staylor char path[MAXPATHLEN]; 28488488aeb5Staylor struct dk_gpt *vtoc; 28498488aeb5Staylor int fd; 28508488aeb5Staylor size_t resv = EFI_MIN_RESV_SIZE; 28518488aeb5Staylor uint64_t slice_size; 28528488aeb5Staylor diskaddr_t start_block; 28538488aeb5Staylor char errbuf[1024]; 28548488aeb5Staylor 2855c6ef114fSmmusante /* prepare an error message just in case */ 2856c6ef114fSmmusante (void) snprintf(errbuf, sizeof (errbuf), 2857c6ef114fSmmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 2858c6ef114fSmmusante 28598488aeb5Staylor if (zhp) { 28608488aeb5Staylor nvlist_t *nvroot; 28618488aeb5Staylor 2862*b5b76fecSGeorge Wilson if (pool_is_bootable(zhp)) { 2863*b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2864*b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root " 2865*b5b76fecSGeorge Wilson "pools.")); 2866*b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 2867*b5b76fecSGeorge Wilson } 2868*b5b76fecSGeorge Wilson 28698488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 28708488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 28718488aeb5Staylor 28728488aeb5Staylor if (zhp->zpool_start_block == 0) 28738488aeb5Staylor start_block = find_start_block(nvroot); 28748488aeb5Staylor else 28758488aeb5Staylor start_block = zhp->zpool_start_block; 28768488aeb5Staylor zhp->zpool_start_block = start_block; 28778488aeb5Staylor } else { 28788488aeb5Staylor /* new pool */ 28798488aeb5Staylor start_block = NEW_START_BLOCK; 28808488aeb5Staylor } 28818488aeb5Staylor 28828488aeb5Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 28838488aeb5Staylor BACKUP_SLICE); 28848488aeb5Staylor 28858488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 28868488aeb5Staylor /* 28878488aeb5Staylor * This shouldn't happen. We've long since verified that this 28888488aeb5Staylor * is a valid device. 28898488aeb5Staylor */ 2890c6ef114fSmmusante zfs_error_aux(hdl, 2891c6ef114fSmmusante dgettext(TEXT_DOMAIN, "unable to open device")); 28928488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 28938488aeb5Staylor } 28948488aeb5Staylor 28958488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 28968488aeb5Staylor /* 28978488aeb5Staylor * The only way this can fail is if we run out of memory, or we 28988488aeb5Staylor * were unable to read the disk's capacity 28998488aeb5Staylor */ 29008488aeb5Staylor if (errno == ENOMEM) 29018488aeb5Staylor (void) no_memory(hdl); 29028488aeb5Staylor 29038488aeb5Staylor (void) close(fd); 2904c6ef114fSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2905c6ef114fSmmusante "unable to read disk capacity"), name); 29068488aeb5Staylor 29078488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 29088488aeb5Staylor } 29098488aeb5Staylor 29108488aeb5Staylor slice_size = vtoc->efi_last_u_lba + 1; 29118488aeb5Staylor slice_size -= EFI_MIN_RESV_SIZE; 29128488aeb5Staylor if (start_block == MAXOFFSET_T) 29138488aeb5Staylor start_block = NEW_START_BLOCK; 29148488aeb5Staylor slice_size -= start_block; 29158488aeb5Staylor 29168488aeb5Staylor vtoc->efi_parts[0].p_start = start_block; 29178488aeb5Staylor vtoc->efi_parts[0].p_size = slice_size; 29188488aeb5Staylor 29198488aeb5Staylor /* 29208488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 29218488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 29228488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 29238488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 29248488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 29258488aeb5Staylor * can get, in the absence of V_OTHER. 29268488aeb5Staylor */ 29278488aeb5Staylor vtoc->efi_parts[0].p_tag = V_USR; 29288488aeb5Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 29298488aeb5Staylor 29308488aeb5Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 29318488aeb5Staylor vtoc->efi_parts[8].p_size = resv; 29328488aeb5Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 29338488aeb5Staylor 29348488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 29358488aeb5Staylor /* 29368488aeb5Staylor * Some block drivers (like pcata) may not support EFI 29378488aeb5Staylor * GPT labels. Print out a helpful error message dir- 29388488aeb5Staylor * ecting the user to manually label the disk and give 29398488aeb5Staylor * a specific slice. 29408488aeb5Staylor */ 29418488aeb5Staylor (void) close(fd); 29428488aeb5Staylor efi_free(vtoc); 29438488aeb5Staylor 29448488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2945c6ef114fSmmusante "try using fdisk(1M) and then provide a specific slice")); 29468488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 29478488aeb5Staylor } 29488488aeb5Staylor 29498488aeb5Staylor (void) close(fd); 29508488aeb5Staylor efi_free(vtoc); 29518488aeb5Staylor return (0); 29528488aeb5Staylor } 2953e7cbe64fSgw 2954e7cbe64fSgw static boolean_t 2955e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 2956e7cbe64fSgw { 2957e7cbe64fSgw char *type; 2958e7cbe64fSgw nvlist_t **child; 2959e7cbe64fSgw uint_t children, c; 2960e7cbe64fSgw 2961e7cbe64fSgw verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 2962e7cbe64fSgw if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 2963e7cbe64fSgw strcmp(type, VDEV_TYPE_FILE) == 0 || 2964e7cbe64fSgw strcmp(type, VDEV_TYPE_LOG) == 0 || 2965e7cbe64fSgw strcmp(type, VDEV_TYPE_MISSING) == 0) { 2966e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2967e7cbe64fSgw "vdev type '%s' is not supported"), type); 2968e7cbe64fSgw (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 2969e7cbe64fSgw return (B_FALSE); 2970e7cbe64fSgw } 2971e7cbe64fSgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 2972e7cbe64fSgw &child, &children) == 0) { 2973e7cbe64fSgw for (c = 0; c < children; c++) { 2974e7cbe64fSgw if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 2975e7cbe64fSgw return (B_FALSE); 2976e7cbe64fSgw } 2977e7cbe64fSgw } 2978e7cbe64fSgw return (B_TRUE); 2979e7cbe64fSgw } 2980e7cbe64fSgw 2981e7cbe64fSgw /* 2982e7cbe64fSgw * check if this zvol is allowable for use as a dump device; zero if 2983e7cbe64fSgw * it is, > 0 if it isn't, < 0 if it isn't a zvol 2984e7cbe64fSgw */ 2985e7cbe64fSgw int 2986e7cbe64fSgw zvol_check_dump_config(char *arg) 2987e7cbe64fSgw { 2988e7cbe64fSgw zpool_handle_t *zhp = NULL; 2989e7cbe64fSgw nvlist_t *config, *nvroot; 2990e7cbe64fSgw char *p, *volname; 2991e7cbe64fSgw nvlist_t **top; 2992e7cbe64fSgw uint_t toplevels; 2993e7cbe64fSgw libzfs_handle_t *hdl; 2994e7cbe64fSgw char errbuf[1024]; 2995e7cbe64fSgw char poolname[ZPOOL_MAXNAMELEN]; 2996e7cbe64fSgw int pathlen = strlen(ZVOL_FULL_DEV_DIR); 2997e7cbe64fSgw int ret = 1; 2998e7cbe64fSgw 2999e7cbe64fSgw if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 3000e7cbe64fSgw return (-1); 3001e7cbe64fSgw } 3002e7cbe64fSgw 3003e7cbe64fSgw (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3004e7cbe64fSgw "dump is not supported on device '%s'"), arg); 3005e7cbe64fSgw 3006e7cbe64fSgw if ((hdl = libzfs_init()) == NULL) 3007e7cbe64fSgw return (1); 3008e7cbe64fSgw libzfs_print_on_error(hdl, B_TRUE); 3009e7cbe64fSgw 3010e7cbe64fSgw volname = arg + pathlen; 3011e7cbe64fSgw 3012e7cbe64fSgw /* check the configuration of the pool */ 3013e7cbe64fSgw if ((p = strchr(volname, '/')) == NULL) { 3014e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3015e7cbe64fSgw "malformed dataset name")); 3016e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 3017e7cbe64fSgw return (1); 3018e7cbe64fSgw } else if (p - volname >= ZFS_MAXNAMELEN) { 3019e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3020e7cbe64fSgw "dataset name is too long")); 3021e7cbe64fSgw (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 3022e7cbe64fSgw return (1); 3023e7cbe64fSgw } else { 3024e7cbe64fSgw (void) strncpy(poolname, volname, p - volname); 3025e7cbe64fSgw poolname[p - volname] = '\0'; 3026e7cbe64fSgw } 3027e7cbe64fSgw 3028e7cbe64fSgw if ((zhp = zpool_open(hdl, poolname)) == NULL) { 3029e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3030e7cbe64fSgw "could not open pool '%s'"), poolname); 3031e7cbe64fSgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 3032e7cbe64fSgw goto out; 3033e7cbe64fSgw } 3034e7cbe64fSgw config = zpool_get_config(zhp, NULL); 3035e7cbe64fSgw if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3036e7cbe64fSgw &nvroot) != 0) { 3037e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3038e7cbe64fSgw "could not obtain vdev configuration for '%s'"), poolname); 3039e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 3040e7cbe64fSgw goto out; 3041e7cbe64fSgw } 3042e7cbe64fSgw 3043e7cbe64fSgw verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 3044e7cbe64fSgw &top, &toplevels) == 0); 3045e7cbe64fSgw if (toplevels != 1) { 3046e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3047e7cbe64fSgw "'%s' has multiple top level vdevs"), poolname); 3048e7cbe64fSgw (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 3049e7cbe64fSgw goto out; 3050e7cbe64fSgw } 3051e7cbe64fSgw 3052e7cbe64fSgw if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 3053e7cbe64fSgw goto out; 3054e7cbe64fSgw } 3055e7cbe64fSgw ret = 0; 3056e7cbe64fSgw 3057e7cbe64fSgw out: 3058e7cbe64fSgw if (zhp) 3059e7cbe64fSgw zpool_close(zhp); 3060e7cbe64fSgw libzfs_fini(hdl); 3061e7cbe64fSgw return (ret); 3062e7cbe64fSgw } 3063