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 /* 23379c004dSEric Schrock * Copyright 2009 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> 45*573ca77eSGeorge Wilson #include <dlfcn.h> 46fa9e4066Sahrens 47fa9e4066Sahrens #include "zfs_namecheck.h" 48b1b8ab34Slling #include "zfs_prop.h" 49fa9e4066Sahrens #include "libzfs_impl.h" 50fa9e4066Sahrens 5115e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 52990b4856Slling 53b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64) 54b5b76fecSGeorge Wilson #define BOOTCMD "installgrub(1M)" 55b5b76fecSGeorge Wilson #else 56b5b76fecSGeorge Wilson #define BOOTCMD "installboot(1M)" 57b5b76fecSGeorge Wilson #endif 58b5b76fecSGeorge Wilson 59*573ca77eSGeorge Wilson #define DISK_ROOT "/dev/dsk" 60*573ca77eSGeorge Wilson #define RDISK_ROOT "/dev/rdsk" 61*573ca77eSGeorge Wilson #define BACKUP_SLICE "s2" 62*573ca77eSGeorge Wilson 63990b4856Slling /* 64990b4856Slling * ==================================================================== 65990b4856Slling * zpool property functions 66990b4856Slling * ==================================================================== 67990b4856Slling */ 68990b4856Slling 69990b4856Slling static int 70990b4856Slling zpool_get_all_props(zpool_handle_t *zhp) 71990b4856Slling { 72990b4856Slling zfs_cmd_t zc = { 0 }; 73990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 74990b4856Slling 75990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 76990b4856Slling 77990b4856Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 78990b4856Slling return (-1); 79990b4856Slling 80990b4856Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 81990b4856Slling if (errno == ENOMEM) { 82990b4856Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 83990b4856Slling zcmd_free_nvlists(&zc); 84990b4856Slling return (-1); 85990b4856Slling } 86990b4856Slling } else { 87990b4856Slling zcmd_free_nvlists(&zc); 88990b4856Slling return (-1); 89990b4856Slling } 90990b4856Slling } 91990b4856Slling 92990b4856Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 93990b4856Slling zcmd_free_nvlists(&zc); 94990b4856Slling return (-1); 95990b4856Slling } 96990b4856Slling 97990b4856Slling zcmd_free_nvlists(&zc); 98990b4856Slling 99990b4856Slling return (0); 100990b4856Slling } 101990b4856Slling 102990b4856Slling static int 103990b4856Slling zpool_props_refresh(zpool_handle_t *zhp) 104990b4856Slling { 105990b4856Slling nvlist_t *old_props; 106990b4856Slling 107990b4856Slling old_props = zhp->zpool_props; 108990b4856Slling 109990b4856Slling if (zpool_get_all_props(zhp) != 0) 110990b4856Slling return (-1); 111990b4856Slling 112990b4856Slling nvlist_free(old_props); 113990b4856Slling return (0); 114990b4856Slling } 115990b4856Slling 116990b4856Slling static char * 117990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 118990b4856Slling zprop_source_t *src) 119990b4856Slling { 120990b4856Slling nvlist_t *nv, *nvl; 121990b4856Slling uint64_t ival; 122990b4856Slling char *value; 123990b4856Slling zprop_source_t source; 124990b4856Slling 125990b4856Slling nvl = zhp->zpool_props; 126990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 127990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 128990b4856Slling source = ival; 129990b4856Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 130990b4856Slling } else { 131990b4856Slling source = ZPROP_SRC_DEFAULT; 132990b4856Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 133990b4856Slling value = "-"; 134990b4856Slling } 135990b4856Slling 136990b4856Slling if (src) 137990b4856Slling *src = source; 138990b4856Slling 139990b4856Slling return (value); 140990b4856Slling } 141990b4856Slling 142990b4856Slling uint64_t 143990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 144990b4856Slling { 145990b4856Slling nvlist_t *nv, *nvl; 146990b4856Slling uint64_t value; 147990b4856Slling zprop_source_t source; 148990b4856Slling 149b87f3af3Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 150b87f3af3Sperrin /* 151b87f3af3Sperrin * zpool_get_all_props() has most likely failed because 152b87f3af3Sperrin * the pool is faulted, but if all we need is the top level 153b87f3af3Sperrin * vdev's guid then get it from the zhp config nvlist. 154b87f3af3Sperrin */ 155b87f3af3Sperrin if ((prop == ZPOOL_PROP_GUID) && 156b87f3af3Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 157b87f3af3Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 158b87f3af3Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 159b87f3af3Sperrin == 0)) { 160b87f3af3Sperrin return (value); 161b87f3af3Sperrin } 162990b4856Slling return (zpool_prop_default_numeric(prop)); 163b87f3af3Sperrin } 164990b4856Slling 165990b4856Slling nvl = zhp->zpool_props; 166990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 167990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 168990b4856Slling source = value; 169990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 170990b4856Slling } else { 171990b4856Slling source = ZPROP_SRC_DEFAULT; 172990b4856Slling value = zpool_prop_default_numeric(prop); 173990b4856Slling } 174990b4856Slling 175990b4856Slling if (src) 176990b4856Slling *src = source; 177990b4856Slling 178990b4856Slling return (value); 179990b4856Slling } 180990b4856Slling 181990b4856Slling /* 182990b4856Slling * Map VDEV STATE to printed strings. 183990b4856Slling */ 184990b4856Slling char * 185990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 186990b4856Slling { 187990b4856Slling switch (state) { 188990b4856Slling case VDEV_STATE_CLOSED: 189990b4856Slling case VDEV_STATE_OFFLINE: 190990b4856Slling return (gettext("OFFLINE")); 191990b4856Slling case VDEV_STATE_REMOVED: 192990b4856Slling return (gettext("REMOVED")); 193990b4856Slling case VDEV_STATE_CANT_OPEN: 194b87f3af3Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 195990b4856Slling return (gettext("FAULTED")); 196990b4856Slling else 197990b4856Slling return (gettext("UNAVAIL")); 198990b4856Slling case VDEV_STATE_FAULTED: 199990b4856Slling return (gettext("FAULTED")); 200990b4856Slling case VDEV_STATE_DEGRADED: 201990b4856Slling return (gettext("DEGRADED")); 202990b4856Slling case VDEV_STATE_HEALTHY: 203990b4856Slling return (gettext("ONLINE")); 204990b4856Slling } 205990b4856Slling 206990b4856Slling return (gettext("UNKNOWN")); 207990b4856Slling } 208990b4856Slling 209990b4856Slling /* 210990b4856Slling * Get a zpool property value for 'prop' and return the value in 211990b4856Slling * a pre-allocated buffer. 212990b4856Slling */ 213990b4856Slling int 214990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 215990b4856Slling zprop_source_t *srctype) 216990b4856Slling { 217990b4856Slling uint64_t intval; 218990b4856Slling const char *strval; 219990b4856Slling zprop_source_t src = ZPROP_SRC_NONE; 220990b4856Slling nvlist_t *nvroot; 221990b4856Slling vdev_stat_t *vs; 222990b4856Slling uint_t vsc; 223990b4856Slling 224990b4856Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 225379c004dSEric Schrock switch (prop) { 226379c004dSEric Schrock case ZPOOL_PROP_NAME: 227990b4856Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 228379c004dSEric Schrock break; 229379c004dSEric Schrock 230379c004dSEric Schrock case ZPOOL_PROP_HEALTH: 231990b4856Slling (void) strlcpy(buf, "FAULTED", len); 232379c004dSEric Schrock break; 233379c004dSEric Schrock 234379c004dSEric Schrock case ZPOOL_PROP_GUID: 235379c004dSEric Schrock intval = zpool_get_prop_int(zhp, prop, &src); 236379c004dSEric Schrock (void) snprintf(buf, len, "%llu", intval); 237379c004dSEric Schrock break; 238379c004dSEric Schrock 239379c004dSEric Schrock case ZPOOL_PROP_ALTROOT: 240379c004dSEric Schrock case ZPOOL_PROP_CACHEFILE: 241379c004dSEric Schrock if (zhp->zpool_props != NULL || 242379c004dSEric Schrock zpool_get_all_props(zhp) == 0) { 243379c004dSEric Schrock (void) strlcpy(buf, 244379c004dSEric Schrock zpool_get_prop_string(zhp, prop, &src), 245379c004dSEric Schrock len); 246379c004dSEric Schrock if (srctype != NULL) 247379c004dSEric Schrock *srctype = src; 248379c004dSEric Schrock return (0); 249379c004dSEric Schrock } 250379c004dSEric Schrock /* FALLTHROUGH */ 251379c004dSEric Schrock default: 252990b4856Slling (void) strlcpy(buf, "-", len); 253379c004dSEric Schrock break; 254379c004dSEric Schrock } 255379c004dSEric Schrock 256379c004dSEric Schrock if (srctype != NULL) 257379c004dSEric Schrock *srctype = src; 258990b4856Slling return (0); 259990b4856Slling } 260990b4856Slling 261990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 262990b4856Slling prop != ZPOOL_PROP_NAME) 263990b4856Slling return (-1); 264990b4856Slling 265990b4856Slling switch (zpool_prop_get_type(prop)) { 266990b4856Slling case PROP_TYPE_STRING: 267990b4856Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 268990b4856Slling len); 269990b4856Slling break; 270990b4856Slling 271990b4856Slling case PROP_TYPE_NUMBER: 272990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 273990b4856Slling 274990b4856Slling switch (prop) { 275990b4856Slling case ZPOOL_PROP_SIZE: 276990b4856Slling case ZPOOL_PROP_USED: 277990b4856Slling case ZPOOL_PROP_AVAILABLE: 278990b4856Slling (void) zfs_nicenum(intval, buf, len); 279990b4856Slling break; 280990b4856Slling 281990b4856Slling case ZPOOL_PROP_CAPACITY: 282990b4856Slling (void) snprintf(buf, len, "%llu%%", 283990b4856Slling (u_longlong_t)intval); 284990b4856Slling break; 285990b4856Slling 286990b4856Slling case ZPOOL_PROP_HEALTH: 287990b4856Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 288990b4856Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 289990b4856Slling verify(nvlist_lookup_uint64_array(nvroot, 290990b4856Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 291990b4856Slling 292990b4856Slling (void) strlcpy(buf, zpool_state_to_name(intval, 293990b4856Slling vs->vs_aux), len); 294990b4856Slling break; 295990b4856Slling default: 296990b4856Slling (void) snprintf(buf, len, "%llu", intval); 297990b4856Slling } 298990b4856Slling break; 299990b4856Slling 300990b4856Slling case PROP_TYPE_INDEX: 301990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 302990b4856Slling if (zpool_prop_index_to_string(prop, intval, &strval) 303990b4856Slling != 0) 304990b4856Slling return (-1); 305990b4856Slling (void) strlcpy(buf, strval, len); 306990b4856Slling break; 307990b4856Slling 308990b4856Slling default: 309990b4856Slling abort(); 310990b4856Slling } 311990b4856Slling 312990b4856Slling if (srctype) 313990b4856Slling *srctype = src; 314990b4856Slling 315990b4856Slling return (0); 316990b4856Slling } 317990b4856Slling 318990b4856Slling /* 319990b4856Slling * Check if the bootfs name has the same pool name as it is set to. 320990b4856Slling * Assuming bootfs is a valid dataset name. 321990b4856Slling */ 322990b4856Slling static boolean_t 323990b4856Slling bootfs_name_valid(const char *pool, char *bootfs) 324990b4856Slling { 325990b4856Slling int len = strlen(pool); 326990b4856Slling 327fe3e2633SEric Taylor if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 328990b4856Slling return (B_FALSE); 329990b4856Slling 330990b4856Slling if (strncmp(pool, bootfs, len) == 0 && 331990b4856Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 332990b4856Slling return (B_TRUE); 333990b4856Slling 334990b4856Slling return (B_FALSE); 335990b4856Slling } 336990b4856Slling 33715e6edf1Sgw /* 33815e6edf1Sgw * Inspect the configuration to determine if any of the devices contain 33915e6edf1Sgw * an EFI label. 34015e6edf1Sgw */ 34115e6edf1Sgw static boolean_t 34215e6edf1Sgw pool_uses_efi(nvlist_t *config) 34315e6edf1Sgw { 34415e6edf1Sgw nvlist_t **child; 34515e6edf1Sgw uint_t c, children; 34615e6edf1Sgw 34715e6edf1Sgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 34815e6edf1Sgw &child, &children) != 0) 34915e6edf1Sgw return (read_efi_label(config, NULL) >= 0); 35015e6edf1Sgw 35115e6edf1Sgw for (c = 0; c < children; c++) { 35215e6edf1Sgw if (pool_uses_efi(child[c])) 35315e6edf1Sgw return (B_TRUE); 35415e6edf1Sgw } 35515e6edf1Sgw return (B_FALSE); 35615e6edf1Sgw } 35715e6edf1Sgw 358b5b76fecSGeorge Wilson static boolean_t 359b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp) 360b5b76fecSGeorge Wilson { 361b5b76fecSGeorge Wilson char bootfs[ZPOOL_MAXNAMELEN]; 362b5b76fecSGeorge Wilson 363b5b76fecSGeorge Wilson return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 364b5b76fecSGeorge Wilson sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 365b5b76fecSGeorge Wilson sizeof (bootfs)) != 0); 366b5b76fecSGeorge Wilson } 367b5b76fecSGeorge Wilson 368b5b76fecSGeorge Wilson 369990b4856Slling /* 370990b4856Slling * Given an nvlist of zpool properties to be set, validate that they are 371990b4856Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 372990b4856Slling * specified as strings. 373990b4856Slling */ 374990b4856Slling static nvlist_t * 3750a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 376990b4856Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 377990b4856Slling { 378990b4856Slling nvpair_t *elem; 379990b4856Slling nvlist_t *retprops; 380990b4856Slling zpool_prop_t prop; 381990b4856Slling char *strval; 382990b4856Slling uint64_t intval; 3832f8aaab3Seschrock char *slash; 3842f8aaab3Seschrock struct stat64 statbuf; 38515e6edf1Sgw zpool_handle_t *zhp; 38615e6edf1Sgw nvlist_t *nvroot; 387990b4856Slling 388990b4856Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 389990b4856Slling (void) no_memory(hdl); 390990b4856Slling return (NULL); 391990b4856Slling } 392990b4856Slling 393990b4856Slling elem = NULL; 394990b4856Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 395990b4856Slling const char *propname = nvpair_name(elem); 396990b4856Slling 397990b4856Slling /* 398990b4856Slling * Make sure this property is valid and applies to this type. 399990b4856Slling */ 400990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 401990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 402990b4856Slling "invalid property '%s'"), propname); 403990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 404990b4856Slling goto error; 405990b4856Slling } 406990b4856Slling 407990b4856Slling if (zpool_prop_readonly(prop)) { 408990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 409990b4856Slling "is readonly"), propname); 410990b4856Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 411990b4856Slling goto error; 412990b4856Slling } 413990b4856Slling 414990b4856Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 415990b4856Slling &strval, &intval, errbuf) != 0) 416990b4856Slling goto error; 417990b4856Slling 418990b4856Slling /* 419990b4856Slling * Perform additional checking for specific properties. 420990b4856Slling */ 421990b4856Slling switch (prop) { 422990b4856Slling case ZPOOL_PROP_VERSION: 423990b4856Slling if (intval < version || intval > SPA_VERSION) { 424990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 425990b4856Slling "property '%s' number %d is invalid."), 426990b4856Slling propname, intval); 427990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 428990b4856Slling goto error; 429990b4856Slling } 430990b4856Slling break; 431990b4856Slling 432990b4856Slling case ZPOOL_PROP_BOOTFS: 433990b4856Slling if (create_or_import) { 434990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 435990b4856Slling "property '%s' cannot be set at creation " 436990b4856Slling "or import time"), propname); 437990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 438990b4856Slling goto error; 439990b4856Slling } 440990b4856Slling 441990b4856Slling if (version < SPA_VERSION_BOOTFS) { 442990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 443990b4856Slling "pool must be upgraded to support " 444990b4856Slling "'%s' property"), propname); 445990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 446990b4856Slling goto error; 447990b4856Slling } 448990b4856Slling 449990b4856Slling /* 450990b4856Slling * bootfs property value has to be a dataset name and 451990b4856Slling * the dataset has to be in the same pool as it sets to. 452990b4856Slling */ 453990b4856Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 454990b4856Slling strval)) { 455990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 456990b4856Slling "is an invalid name"), strval); 457990b4856Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 458990b4856Slling goto error; 459990b4856Slling } 46015e6edf1Sgw 46115e6edf1Sgw if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 46215e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 46315e6edf1Sgw "could not open pool '%s'"), poolname); 46415e6edf1Sgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 46515e6edf1Sgw goto error; 46615e6edf1Sgw } 46715e6edf1Sgw verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 46815e6edf1Sgw ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 46915e6edf1Sgw 47015e6edf1Sgw /* 47115e6edf1Sgw * bootfs property cannot be set on a disk which has 47215e6edf1Sgw * been EFI labeled. 47315e6edf1Sgw */ 47415e6edf1Sgw if (pool_uses_efi(nvroot)) { 47515e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 47615e6edf1Sgw "property '%s' not supported on " 47715e6edf1Sgw "EFI labeled devices"), propname); 47815e6edf1Sgw (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 47915e6edf1Sgw zpool_close(zhp); 48015e6edf1Sgw goto error; 48115e6edf1Sgw } 48215e6edf1Sgw zpool_close(zhp); 483990b4856Slling break; 484990b4856Slling 4852f8aaab3Seschrock case ZPOOL_PROP_ALTROOT: 486990b4856Slling if (!create_or_import) { 487990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 488990b4856Slling "property '%s' can only be set during pool " 489990b4856Slling "creation or import"), propname); 490990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 491990b4856Slling goto error; 492990b4856Slling } 493990b4856Slling 4942f8aaab3Seschrock if (strval[0] != '/') { 495990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4962f8aaab3Seschrock "bad alternate root '%s'"), strval); 4972f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 498990b4856Slling goto error; 499990b4856Slling } 5002f8aaab3Seschrock break; 5012f8aaab3Seschrock 5022f8aaab3Seschrock case ZPOOL_PROP_CACHEFILE: 5032f8aaab3Seschrock if (strval[0] == '\0') 5042f8aaab3Seschrock break; 5052f8aaab3Seschrock 5062f8aaab3Seschrock if (strcmp(strval, "none") == 0) 5072f8aaab3Seschrock break; 508990b4856Slling 509990b4856Slling if (strval[0] != '/') { 510990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5112f8aaab3Seschrock "property '%s' must be empty, an " 5122f8aaab3Seschrock "absolute path, or 'none'"), propname); 513990b4856Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 514990b4856Slling goto error; 515990b4856Slling } 516990b4856Slling 5172f8aaab3Seschrock slash = strrchr(strval, '/'); 518990b4856Slling 5192f8aaab3Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5202f8aaab3Seschrock strcmp(slash, "/..") == 0) { 5212f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5222f8aaab3Seschrock "'%s' is not a valid file"), strval); 5232f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5242f8aaab3Seschrock goto error; 5252f8aaab3Seschrock } 526990b4856Slling 5272f8aaab3Seschrock *slash = '\0'; 5282f8aaab3Seschrock 5292c32020fSeschrock if (strval[0] != '\0' && 5302c32020fSeschrock (stat64(strval, &statbuf) != 0 || 5312c32020fSeschrock !S_ISDIR(statbuf.st_mode))) { 5322f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5332f8aaab3Seschrock "'%s' is not a valid directory"), 5342f8aaab3Seschrock strval); 5352f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5362f8aaab3Seschrock goto error; 5372f8aaab3Seschrock } 5382f8aaab3Seschrock 5392f8aaab3Seschrock *slash = '/'; 5402f8aaab3Seschrock break; 541990b4856Slling } 542990b4856Slling } 543990b4856Slling 544990b4856Slling return (retprops); 545990b4856Slling error: 546990b4856Slling nvlist_free(retprops); 547990b4856Slling return (NULL); 548990b4856Slling } 549990b4856Slling 550990b4856Slling /* 551990b4856Slling * Set zpool property : propname=propval. 552990b4856Slling */ 553990b4856Slling int 554990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 555990b4856Slling { 556990b4856Slling zfs_cmd_t zc = { 0 }; 557990b4856Slling int ret = -1; 558990b4856Slling char errbuf[1024]; 559990b4856Slling nvlist_t *nvl = NULL; 560990b4856Slling nvlist_t *realprops; 561990b4856Slling uint64_t version; 562990b4856Slling 563990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), 564990b4856Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 565990b4856Slling zhp->zpool_name); 566990b4856Slling 567990b4856Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 568990b4856Slling return (no_memory(zhp->zpool_hdl)); 569990b4856Slling 570990b4856Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 571990b4856Slling nvlist_free(nvl); 572990b4856Slling return (no_memory(zhp->zpool_hdl)); 573990b4856Slling } 574990b4856Slling 575990b4856Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5760a48a24eStimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 577990b4856Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 578990b4856Slling nvlist_free(nvl); 579990b4856Slling return (-1); 580990b4856Slling } 581990b4856Slling 582990b4856Slling nvlist_free(nvl); 583990b4856Slling nvl = realprops; 584990b4856Slling 585990b4856Slling /* 586990b4856Slling * Execute the corresponding ioctl() to set this property. 587990b4856Slling */ 588990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 589990b4856Slling 590990b4856Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 591990b4856Slling nvlist_free(nvl); 592990b4856Slling return (-1); 593990b4856Slling } 594990b4856Slling 595990b4856Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 596990b4856Slling 597990b4856Slling zcmd_free_nvlists(&zc); 598990b4856Slling nvlist_free(nvl); 599990b4856Slling 600990b4856Slling if (ret) 601990b4856Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 602990b4856Slling else 603990b4856Slling (void) zpool_props_refresh(zhp); 604990b4856Slling 605990b4856Slling return (ret); 606990b4856Slling } 607990b4856Slling 608990b4856Slling int 609990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 610990b4856Slling { 611990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 612990b4856Slling zprop_list_t *entry; 613990b4856Slling char buf[ZFS_MAXPROPLEN]; 614990b4856Slling 615990b4856Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 616990b4856Slling return (-1); 617990b4856Slling 618990b4856Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 619990b4856Slling 620990b4856Slling if (entry->pl_fixed) 621990b4856Slling continue; 622990b4856Slling 623990b4856Slling if (entry->pl_prop != ZPROP_INVAL && 624990b4856Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 625990b4856Slling NULL) == 0) { 626990b4856Slling if (strlen(buf) > entry->pl_width) 627990b4856Slling entry->pl_width = strlen(buf); 628990b4856Slling } 629990b4856Slling } 630990b4856Slling 631990b4856Slling return (0); 632990b4856Slling } 633990b4856Slling 634990b4856Slling 635*573ca77eSGeorge Wilson /* 636*573ca77eSGeorge Wilson * Don't start the slice at the default block of 34; many storage 637*573ca77eSGeorge Wilson * devices will use a stripe width of 128k, so start there instead. 638*573ca77eSGeorge Wilson */ 639*573ca77eSGeorge Wilson #define NEW_START_BLOCK 256 640*573ca77eSGeorge Wilson 641fa9e4066Sahrens /* 642fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 643fa9e4066Sahrens * 'buf'. 644fa9e4066Sahrens */ 645e7cbe64fSgw boolean_t 64699653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 647fa9e4066Sahrens { 648fa9e4066Sahrens namecheck_err_t why; 649fa9e4066Sahrens char what; 650b468a217Seschrock int ret; 651b468a217Seschrock 652b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 653b468a217Seschrock 654b468a217Seschrock /* 655b468a217Seschrock * The rules for reserved pool names were extended at a later point. 656b468a217Seschrock * But we need to support users with existing pools that may now be 657b468a217Seschrock * invalid. So we only check for this expanded set of names during a 658b468a217Seschrock * create (or import), and only in userland. 659b468a217Seschrock */ 660b468a217Seschrock if (ret == 0 && !isopen && 661b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 662b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 6638654d025Sperrin strncmp(pool, "spare", 5) == 0 || 6648654d025Sperrin strcmp(pool, "log") == 0)) { 665e7cbe64fSgw if (hdl != NULL) 666e7cbe64fSgw zfs_error_aux(hdl, 667e7cbe64fSgw dgettext(TEXT_DOMAIN, "name is reserved")); 66899653d4eSeschrock return (B_FALSE); 669b468a217Seschrock } 670b468a217Seschrock 671fa9e4066Sahrens 672b468a217Seschrock if (ret != 0) { 67399653d4eSeschrock if (hdl != NULL) { 674fa9e4066Sahrens switch (why) { 675b81d61a6Slling case NAME_ERR_TOOLONG: 67699653d4eSeschrock zfs_error_aux(hdl, 677b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 678b81d61a6Slling break; 679b81d61a6Slling 680fa9e4066Sahrens case NAME_ERR_INVALCHAR: 68199653d4eSeschrock zfs_error_aux(hdl, 682fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 683fa9e4066Sahrens "'%c' in pool name"), what); 684fa9e4066Sahrens break; 685fa9e4066Sahrens 686fa9e4066Sahrens case NAME_ERR_NOLETTER: 68799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 68899653d4eSeschrock "name must begin with a letter")); 689fa9e4066Sahrens break; 690fa9e4066Sahrens 691fa9e4066Sahrens case NAME_ERR_RESERVED: 69299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 69399653d4eSeschrock "name is reserved")); 694fa9e4066Sahrens break; 695fa9e4066Sahrens 696fa9e4066Sahrens case NAME_ERR_DISKLIKE: 69799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 69899653d4eSeschrock "pool name is reserved")); 699fa9e4066Sahrens break; 7005ad82045Snd 7015ad82045Snd case NAME_ERR_LEADING_SLASH: 7025ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7035ad82045Snd "leading slash in name")); 7045ad82045Snd break; 7055ad82045Snd 7065ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 7075ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7085ad82045Snd "empty component in name")); 7095ad82045Snd break; 7105ad82045Snd 7115ad82045Snd case NAME_ERR_TRAILING_SLASH: 7125ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7135ad82045Snd "trailing slash in name")); 7145ad82045Snd break; 7155ad82045Snd 7165ad82045Snd case NAME_ERR_MULTIPLE_AT: 7175ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7185ad82045Snd "multiple '@' delimiters in name")); 7195ad82045Snd break; 7205ad82045Snd 721fa9e4066Sahrens } 722fa9e4066Sahrens } 72399653d4eSeschrock return (B_FALSE); 724fa9e4066Sahrens } 725fa9e4066Sahrens 72699653d4eSeschrock return (B_TRUE); 727fa9e4066Sahrens } 728fa9e4066Sahrens 729fa9e4066Sahrens /* 730fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 731fa9e4066Sahrens * state. 732fa9e4066Sahrens */ 733fa9e4066Sahrens zpool_handle_t * 73499653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 735fa9e4066Sahrens { 736fa9e4066Sahrens zpool_handle_t *zhp; 73794de1d4cSeschrock boolean_t missing; 738fa9e4066Sahrens 739fa9e4066Sahrens /* 740fa9e4066Sahrens * Make sure the pool name is valid. 741fa9e4066Sahrens */ 74299653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 743ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 74499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 74599653d4eSeschrock pool); 746fa9e4066Sahrens return (NULL); 747fa9e4066Sahrens } 748fa9e4066Sahrens 74999653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 75099653d4eSeschrock return (NULL); 751fa9e4066Sahrens 75299653d4eSeschrock zhp->zpool_hdl = hdl; 753fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 754fa9e4066Sahrens 75594de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 75694de1d4cSeschrock zpool_close(zhp); 75794de1d4cSeschrock return (NULL); 75894de1d4cSeschrock } 75994de1d4cSeschrock 76094de1d4cSeschrock if (missing) { 761990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 762ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 763990b4856Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 76494de1d4cSeschrock zpool_close(zhp); 76594de1d4cSeschrock return (NULL); 766fa9e4066Sahrens } 767fa9e4066Sahrens 768fa9e4066Sahrens return (zhp); 769fa9e4066Sahrens } 770fa9e4066Sahrens 771fa9e4066Sahrens /* 772fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 773fa9e4066Sahrens * the configuration cache may be out of date). 774fa9e4066Sahrens */ 77594de1d4cSeschrock int 77694de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 777fa9e4066Sahrens { 778fa9e4066Sahrens zpool_handle_t *zhp; 77994de1d4cSeschrock boolean_t missing; 780fa9e4066Sahrens 78194de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 78294de1d4cSeschrock return (-1); 783fa9e4066Sahrens 78499653d4eSeschrock zhp->zpool_hdl = hdl; 785fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 786fa9e4066Sahrens 78794de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 78894de1d4cSeschrock zpool_close(zhp); 78994de1d4cSeschrock return (-1); 790fa9e4066Sahrens } 791fa9e4066Sahrens 79294de1d4cSeschrock if (missing) { 79394de1d4cSeschrock zpool_close(zhp); 79494de1d4cSeschrock *ret = NULL; 79594de1d4cSeschrock return (0); 79694de1d4cSeschrock } 79794de1d4cSeschrock 79894de1d4cSeschrock *ret = zhp; 79994de1d4cSeschrock return (0); 800fa9e4066Sahrens } 801fa9e4066Sahrens 802fa9e4066Sahrens /* 803fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 804fa9e4066Sahrens * state. 805fa9e4066Sahrens */ 806fa9e4066Sahrens zpool_handle_t * 80799653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 808fa9e4066Sahrens { 809fa9e4066Sahrens zpool_handle_t *zhp; 810fa9e4066Sahrens 81199653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 812fa9e4066Sahrens return (NULL); 813fa9e4066Sahrens 814fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 815ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 81699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 817fa9e4066Sahrens zpool_close(zhp); 818fa9e4066Sahrens return (NULL); 819fa9e4066Sahrens } 820fa9e4066Sahrens 821fa9e4066Sahrens return (zhp); 822fa9e4066Sahrens } 823fa9e4066Sahrens 824fa9e4066Sahrens /* 825fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 826fa9e4066Sahrens */ 827fa9e4066Sahrens void 828fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 829fa9e4066Sahrens { 830fa9e4066Sahrens if (zhp->zpool_config) 831fa9e4066Sahrens nvlist_free(zhp->zpool_config); 832088e9d47Seschrock if (zhp->zpool_old_config) 833088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 834b1b8ab34Slling if (zhp->zpool_props) 835b1b8ab34Slling nvlist_free(zhp->zpool_props); 836fa9e4066Sahrens free(zhp); 837fa9e4066Sahrens } 838fa9e4066Sahrens 839fa9e4066Sahrens /* 840fa9e4066Sahrens * Return the name of the pool. 841fa9e4066Sahrens */ 842fa9e4066Sahrens const char * 843fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 844fa9e4066Sahrens { 845fa9e4066Sahrens return (zhp->zpool_name); 846fa9e4066Sahrens } 847fa9e4066Sahrens 848fa9e4066Sahrens 849fa9e4066Sahrens /* 850fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 851fa9e4066Sahrens */ 852fa9e4066Sahrens int 853fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 854fa9e4066Sahrens { 855fa9e4066Sahrens return (zhp->zpool_state); 856fa9e4066Sahrens } 857fa9e4066Sahrens 858fa9e4066Sahrens /* 859fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 860fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 861fa9e4066Sahrens * don't have to worry about error semantics. 862fa9e4066Sahrens */ 863fa9e4066Sahrens int 86499653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 8650a48a24eStimh nvlist_t *props, nvlist_t *fsprops) 866fa9e4066Sahrens { 867fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 8680a48a24eStimh nvlist_t *zc_fsprops = NULL; 8690a48a24eStimh nvlist_t *zc_props = NULL; 87099653d4eSeschrock char msg[1024]; 871990b4856Slling char *altroot; 8720a48a24eStimh int ret = -1; 873fa9e4066Sahrens 87499653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 87599653d4eSeschrock "cannot create '%s'"), pool); 876fa9e4066Sahrens 87799653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 87899653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 879fa9e4066Sahrens 880351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 881990b4856Slling return (-1); 882fa9e4066Sahrens 8830a48a24eStimh if (props) { 8840a48a24eStimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 8850a48a24eStimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 8860a48a24eStimh goto create_failed; 8870a48a24eStimh } 8880a48a24eStimh } 88999653d4eSeschrock 8900a48a24eStimh if (fsprops) { 8910a48a24eStimh uint64_t zoned; 8920a48a24eStimh char *zonestr; 8930a48a24eStimh 8940a48a24eStimh zoned = ((nvlist_lookup_string(fsprops, 8950a48a24eStimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 8960a48a24eStimh strcmp(zonestr, "on") == 0); 8970a48a24eStimh 8980a48a24eStimh if ((zc_fsprops = zfs_valid_proplist(hdl, 8990a48a24eStimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9000a48a24eStimh goto create_failed; 9010a48a24eStimh } 9020a48a24eStimh if (!zc_props && 9030a48a24eStimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9040a48a24eStimh goto create_failed; 9050a48a24eStimh } 9060a48a24eStimh if (nvlist_add_nvlist(zc_props, 9070a48a24eStimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9080a48a24eStimh goto create_failed; 9090a48a24eStimh } 910351420b3Slling } 911fa9e4066Sahrens 9120a48a24eStimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9130a48a24eStimh goto create_failed; 9140a48a24eStimh 915990b4856Slling (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 916fa9e4066Sahrens 9170a48a24eStimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 918351420b3Slling 919e9dbad6fSeschrock zcmd_free_nvlists(&zc); 9200a48a24eStimh nvlist_free(zc_props); 9210a48a24eStimh nvlist_free(zc_fsprops); 922fa9e4066Sahrens 92399653d4eSeschrock switch (errno) { 924fa9e4066Sahrens case EBUSY: 925fa9e4066Sahrens /* 926fa9e4066Sahrens * This can happen if the user has specified the same 927fa9e4066Sahrens * device multiple times. We can't reliably detect this 928fa9e4066Sahrens * until we try to add it and see we already have a 929fa9e4066Sahrens * label. 930fa9e4066Sahrens */ 93199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 93299653d4eSeschrock "one or more vdevs refer to the same device")); 93399653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 934fa9e4066Sahrens 935fa9e4066Sahrens case EOVERFLOW: 936fa9e4066Sahrens /* 93799653d4eSeschrock * This occurs when one of the devices is below 938fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 939fa9e4066Sahrens * device was the problem device since there's no 940fa9e4066Sahrens * reliable way to determine device size from userland. 941fa9e4066Sahrens */ 942fa9e4066Sahrens { 943fa9e4066Sahrens char buf[64]; 944fa9e4066Sahrens 945fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 946fa9e4066Sahrens 94799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 94899653d4eSeschrock "one or more devices is less than the " 94999653d4eSeschrock "minimum size (%s)"), buf); 950fa9e4066Sahrens } 95199653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 952fa9e4066Sahrens 953fa9e4066Sahrens case ENOSPC: 95499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 95599653d4eSeschrock "one or more devices is out of space")); 95699653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 957fa9e4066Sahrens 958fa94a07fSbrendan case ENOTBLK: 959fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 960fa94a07fSbrendan "cache device must be a disk or disk slice")); 961fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 962fa94a07fSbrendan 963fa9e4066Sahrens default: 96499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 965fa9e4066Sahrens } 966fa9e4066Sahrens } 967fa9e4066Sahrens 968fa9e4066Sahrens /* 969fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 970e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 971fa9e4066Sahrens */ 972990b4856Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 973990b4856Slling &altroot) == 0) { 974fa9e4066Sahrens zfs_handle_t *zhp; 975fa9e4066Sahrens 976990b4856Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 977e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 978e9dbad6fSeschrock "/") == 0); 979fa9e4066Sahrens 980fa9e4066Sahrens zfs_close(zhp); 981fa9e4066Sahrens } 982fa9e4066Sahrens 9830a48a24eStimh create_failed: 984351420b3Slling zcmd_free_nvlists(&zc); 9850a48a24eStimh nvlist_free(zc_props); 9860a48a24eStimh nvlist_free(zc_fsprops); 9870a48a24eStimh return (ret); 988fa9e4066Sahrens } 989fa9e4066Sahrens 990fa9e4066Sahrens /* 991fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 992fa9e4066Sahrens * datasets left in the pool. 993fa9e4066Sahrens */ 994fa9e4066Sahrens int 995fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 996fa9e4066Sahrens { 997fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 998fa9e4066Sahrens zfs_handle_t *zfp = NULL; 99999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 100099653d4eSeschrock char msg[1024]; 1001fa9e4066Sahrens 1002fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 100399653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 100499653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1005fa9e4066Sahrens return (-1); 1006fa9e4066Sahrens 10075ad82045Snd if (zpool_remove_zvol_links(zhp) != 0) 1008fa9e4066Sahrens return (-1); 1009fa9e4066Sahrens 1010fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1011fa9e4066Sahrens 1012ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 101399653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 101499653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 1015fa9e4066Sahrens 101699653d4eSeschrock if (errno == EROFS) { 101799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 101899653d4eSeschrock "one or more devices is read only")); 101999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 102099653d4eSeschrock } else { 102199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1022fa9e4066Sahrens } 1023fa9e4066Sahrens 1024fa9e4066Sahrens if (zfp) 1025fa9e4066Sahrens zfs_close(zfp); 1026fa9e4066Sahrens return (-1); 1027fa9e4066Sahrens } 1028fa9e4066Sahrens 1029fa9e4066Sahrens if (zfp) { 1030fa9e4066Sahrens remove_mountpoint(zfp); 1031fa9e4066Sahrens zfs_close(zfp); 1032fa9e4066Sahrens } 1033fa9e4066Sahrens 1034fa9e4066Sahrens return (0); 1035fa9e4066Sahrens } 1036fa9e4066Sahrens 1037fa9e4066Sahrens /* 1038fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1039fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1040fa9e4066Sahrens */ 1041fa9e4066Sahrens int 1042fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1043fa9e4066Sahrens { 1044e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 104599653d4eSeschrock int ret; 104699653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 104799653d4eSeschrock char msg[1024]; 1048fa94a07fSbrendan nvlist_t **spares, **l2cache; 1049fa94a07fSbrendan uint_t nspares, nl2cache; 105099653d4eSeschrock 105199653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 105299653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 105399653d4eSeschrock 1054fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1055fa94a07fSbrendan SPA_VERSION_SPARES && 105699653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 105799653d4eSeschrock &spares, &nspares) == 0) { 105899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 105999653d4eSeschrock "upgraded to add hot spares")); 106099653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 106199653d4eSeschrock } 1062fa9e4066Sahrens 1063b5b76fecSGeorge Wilson if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 1064b5b76fecSGeorge Wilson ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 1065b5b76fecSGeorge Wilson uint64_t s; 1066b5b76fecSGeorge Wilson 1067b5b76fecSGeorge Wilson for (s = 0; s < nspares; s++) { 1068b5b76fecSGeorge Wilson char *path; 1069b5b76fecSGeorge Wilson 1070b5b76fecSGeorge Wilson if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 1071b5b76fecSGeorge Wilson &path) == 0 && pool_uses_efi(spares[s])) { 1072b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1073b5b76fecSGeorge Wilson "device '%s' contains an EFI label and " 1074b5b76fecSGeorge Wilson "cannot be used on root pools."), 1075b5b76fecSGeorge Wilson zpool_vdev_name(hdl, NULL, spares[s])); 1076b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 1077b5b76fecSGeorge Wilson } 1078b5b76fecSGeorge Wilson } 1079b5b76fecSGeorge Wilson } 1080b5b76fecSGeorge Wilson 1081fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1082fa94a07fSbrendan SPA_VERSION_L2CACHE && 1083fa94a07fSbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1084fa94a07fSbrendan &l2cache, &nl2cache) == 0) { 1085fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 1086fa94a07fSbrendan "upgraded to add cache devices")); 1087fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 1088fa94a07fSbrendan } 1089fa94a07fSbrendan 1090990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 109199653d4eSeschrock return (-1); 1092fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1093fa9e4066Sahrens 1094ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1095fa9e4066Sahrens switch (errno) { 1096fa9e4066Sahrens case EBUSY: 1097fa9e4066Sahrens /* 1098fa9e4066Sahrens * This can happen if the user has specified the same 1099fa9e4066Sahrens * device multiple times. We can't reliably detect this 1100fa9e4066Sahrens * until we try to add it and see we already have a 1101fa9e4066Sahrens * label. 1102fa9e4066Sahrens */ 110399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 110499653d4eSeschrock "one or more vdevs refer to the same device")); 110599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1106fa9e4066Sahrens break; 1107fa9e4066Sahrens 1108fa9e4066Sahrens case EOVERFLOW: 1109fa9e4066Sahrens /* 1110fa9e4066Sahrens * This occurrs when one of the devices is below 1111fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1112fa9e4066Sahrens * device was the problem device since there's no 1113fa9e4066Sahrens * reliable way to determine device size from userland. 1114fa9e4066Sahrens */ 1115fa9e4066Sahrens { 1116fa9e4066Sahrens char buf[64]; 1117fa9e4066Sahrens 1118fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1119fa9e4066Sahrens 112099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 112199653d4eSeschrock "device is less than the minimum " 112299653d4eSeschrock "size (%s)"), buf); 1123fa9e4066Sahrens } 112499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 112599653d4eSeschrock break; 112699653d4eSeschrock 112799653d4eSeschrock case ENOTSUP: 112899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11298654d025Sperrin "pool must be upgraded to add these vdevs")); 113099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1131fa9e4066Sahrens break; 1132fa9e4066Sahrens 1133b1b8ab34Slling case EDOM: 1134b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11358654d025Sperrin "root pool can not have multiple vdevs" 11368654d025Sperrin " or separate logs")); 1137b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 1138b1b8ab34Slling break; 1139b1b8ab34Slling 1140fa94a07fSbrendan case ENOTBLK: 1141fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1142fa94a07fSbrendan "cache device must be a disk or disk slice")); 1143fa94a07fSbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 1144fa94a07fSbrendan break; 1145fa94a07fSbrendan 1146fa9e4066Sahrens default: 114799653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1148fa9e4066Sahrens } 1149fa9e4066Sahrens 115099653d4eSeschrock ret = -1; 115199653d4eSeschrock } else { 115299653d4eSeschrock ret = 0; 1153fa9e4066Sahrens } 1154fa9e4066Sahrens 1155e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1156fa9e4066Sahrens 115799653d4eSeschrock return (ret); 1158fa9e4066Sahrens } 1159fa9e4066Sahrens 1160fa9e4066Sahrens /* 1161fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 1162fa9e4066Sahrens * mounted datasets in the pool. 1163fa9e4066Sahrens */ 1164fa9e4066Sahrens int 1165394ab0cbSGeorge Wilson zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1166fa9e4066Sahrens { 1167fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 116889a89ebfSlling char msg[1024]; 1169fa9e4066Sahrens 1170fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 1171fa9e4066Sahrens return (-1); 1172fa9e4066Sahrens 117389a89ebfSlling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 117489a89ebfSlling "cannot export '%s'"), zhp->zpool_name); 117589a89ebfSlling 1176fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 117789a89ebfSlling zc.zc_cookie = force; 1178394ab0cbSGeorge Wilson zc.zc_guid = hardforce; 117989a89ebfSlling 118089a89ebfSlling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 118189a89ebfSlling switch (errno) { 118289a89ebfSlling case EXDEV: 118389a89ebfSlling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 118489a89ebfSlling "use '-f' to override the following errors:\n" 118589a89ebfSlling "'%s' has an active shared spare which could be" 118689a89ebfSlling " used by other pools once '%s' is exported."), 118789a89ebfSlling zhp->zpool_name, zhp->zpool_name); 118889a89ebfSlling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 118989a89ebfSlling msg)); 119089a89ebfSlling default: 119189a89ebfSlling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 119289a89ebfSlling msg)); 119389a89ebfSlling } 119489a89ebfSlling } 1195fa9e4066Sahrens 1196fa9e4066Sahrens return (0); 1197fa9e4066Sahrens } 1198fa9e4066Sahrens 1199394ab0cbSGeorge Wilson int 1200394ab0cbSGeorge Wilson zpool_export(zpool_handle_t *zhp, boolean_t force) 1201394ab0cbSGeorge Wilson { 1202394ab0cbSGeorge Wilson return (zpool_export_common(zhp, force, B_FALSE)); 1203394ab0cbSGeorge Wilson } 1204394ab0cbSGeorge Wilson 1205394ab0cbSGeorge Wilson int 1206394ab0cbSGeorge Wilson zpool_export_force(zpool_handle_t *zhp) 1207394ab0cbSGeorge Wilson { 1208394ab0cbSGeorge Wilson return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 1209394ab0cbSGeorge Wilson } 1210394ab0cbSGeorge Wilson 1211fa9e4066Sahrens /* 1212990b4856Slling * zpool_import() is a contracted interface. Should be kept the same 1213990b4856Slling * if possible. 1214990b4856Slling * 1215990b4856Slling * Applications should use zpool_import_props() to import a pool with 1216990b4856Slling * new properties value to be set. 1217fa9e4066Sahrens */ 1218fa9e4066Sahrens int 121999653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1220990b4856Slling char *altroot) 1221990b4856Slling { 1222990b4856Slling nvlist_t *props = NULL; 1223990b4856Slling int ret; 1224990b4856Slling 1225990b4856Slling if (altroot != NULL) { 1226990b4856Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1227990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1228990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1229990b4856Slling newname)); 1230990b4856Slling } 1231990b4856Slling 1232990b4856Slling if (nvlist_add_string(props, 1233352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 1234352d8027SGeorge Wilson nvlist_add_string(props, 1235352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 1236990b4856Slling nvlist_free(props); 1237990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1238990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1239990b4856Slling newname)); 1240990b4856Slling } 1241990b4856Slling } 1242990b4856Slling 1243c5904d13Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 1244990b4856Slling if (props) 1245990b4856Slling nvlist_free(props); 1246990b4856Slling return (ret); 1247990b4856Slling } 1248990b4856Slling 1249990b4856Slling /* 1250990b4856Slling * Import the given pool using the known configuration and a list of 1251990b4856Slling * properties to be set. The configuration should have come from 1252990b4856Slling * zpool_find_import(). The 'newname' parameters control whether the pool 1253990b4856Slling * is imported with a different name. 1254990b4856Slling */ 1255990b4856Slling int 1256990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1257c5904d13Seschrock nvlist_t *props, boolean_t importfaulted) 1258fa9e4066Sahrens { 1259e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 1260fa9e4066Sahrens char *thename; 1261fa9e4066Sahrens char *origname; 1262fa9e4066Sahrens int ret; 1263990b4856Slling char errbuf[1024]; 1264fa9e4066Sahrens 1265fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1266fa9e4066Sahrens &origname) == 0); 1267fa9e4066Sahrens 1268990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1269990b4856Slling "cannot import pool '%s'"), origname); 1270990b4856Slling 1271fa9e4066Sahrens if (newname != NULL) { 127299653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 1273ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 127499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 127599653d4eSeschrock newname)); 1276fa9e4066Sahrens thename = (char *)newname; 1277fa9e4066Sahrens } else { 1278fa9e4066Sahrens thename = origname; 1279fa9e4066Sahrens } 1280fa9e4066Sahrens 1281990b4856Slling if (props) { 1282990b4856Slling uint64_t version; 1283fa9e4066Sahrens 1284990b4856Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 1285990b4856Slling &version) == 0); 1286fa9e4066Sahrens 12870a48a24eStimh if ((props = zpool_valid_proplist(hdl, origname, 1288351420b3Slling props, version, B_TRUE, errbuf)) == NULL) { 1289990b4856Slling return (-1); 1290351420b3Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 1291351420b3Slling nvlist_free(props); 1292990b4856Slling return (-1); 1293351420b3Slling } 1294990b4856Slling } 1295990b4856Slling 1296990b4856Slling (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1297fa9e4066Sahrens 1298fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1299ea8dc4b6Seschrock &zc.zc_guid) == 0); 1300fa9e4066Sahrens 1301351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 1302351420b3Slling nvlist_free(props); 130399653d4eSeschrock return (-1); 1304351420b3Slling } 1305fa9e4066Sahrens 1306c5904d13Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1307fa9e4066Sahrens ret = 0; 1308ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1309fa9e4066Sahrens char desc[1024]; 1310fa9e4066Sahrens if (newname == NULL) 1311fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1312fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1313fa9e4066Sahrens thename); 1314fa9e4066Sahrens else 1315fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1316fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1317fa9e4066Sahrens origname, thename); 1318fa9e4066Sahrens 1319fa9e4066Sahrens switch (errno) { 1320ea8dc4b6Seschrock case ENOTSUP: 1321ea8dc4b6Seschrock /* 1322ea8dc4b6Seschrock * Unsupported version. 1323ea8dc4b6Seschrock */ 132499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 1325ea8dc4b6Seschrock break; 1326ea8dc4b6Seschrock 1327b5989ec7Seschrock case EINVAL: 1328b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 1329b5989ec7Seschrock break; 1330b5989ec7Seschrock 1331fa9e4066Sahrens default: 133299653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 1333fa9e4066Sahrens } 1334fa9e4066Sahrens 1335fa9e4066Sahrens ret = -1; 1336fa9e4066Sahrens } else { 1337fa9e4066Sahrens zpool_handle_t *zhp; 1338ecd6cf80Smarks 1339fa9e4066Sahrens /* 1340fa9e4066Sahrens * This should never fail, but play it safe anyway. 1341fa9e4066Sahrens */ 134294de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 134394de1d4cSeschrock ret = -1; 134494de1d4cSeschrock } else if (zhp != NULL) { 1345fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 1346fa9e4066Sahrens zpool_close(zhp); 1347fa9e4066Sahrens } 1348ecd6cf80Smarks 1349fa9e4066Sahrens } 1350fa9e4066Sahrens 1351e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1352351420b3Slling nvlist_free(props); 1353351420b3Slling 1354fa9e4066Sahrens return (ret); 1355fa9e4066Sahrens } 1356fa9e4066Sahrens 1357fa9e4066Sahrens /* 1358fa9e4066Sahrens * Scrub the pool. 1359fa9e4066Sahrens */ 1360fa9e4066Sahrens int 1361fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1362fa9e4066Sahrens { 1363fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1364fa9e4066Sahrens char msg[1024]; 136599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1366fa9e4066Sahrens 1367fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1368fa9e4066Sahrens zc.zc_cookie = type; 1369fa9e4066Sahrens 1370ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1371fa9e4066Sahrens return (0); 1372fa9e4066Sahrens 1373fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 1374fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1375fa9e4066Sahrens 137699653d4eSeschrock if (errno == EBUSY) 137799653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 137899653d4eSeschrock else 137999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1380fa9e4066Sahrens } 1381fa9e4066Sahrens 1382a43d325bSek /* 1383*573ca77eSGeorge Wilson * Find a vdev that matches the search criteria specified. We use the 1384*573ca77eSGeorge Wilson * the nvpair name to determine how we should look for the device. 1385a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 1386a43d325bSek * spare; but FALSE if its an INUSE spare. 1387a43d325bSek */ 138899653d4eSeschrock static nvlist_t * 1389*573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 1390*573ca77eSGeorge Wilson boolean_t *l2cache, boolean_t *log) 1391ea8dc4b6Seschrock { 1392ea8dc4b6Seschrock uint_t c, children; 1393ea8dc4b6Seschrock nvlist_t **child; 139499653d4eSeschrock nvlist_t *ret; 1395ee0eb9f2SEric Schrock uint64_t is_log; 1396*573ca77eSGeorge Wilson char *srchkey; 1397*573ca77eSGeorge Wilson nvpair_t *pair = nvlist_next_nvpair(search, NULL); 1398*573ca77eSGeorge Wilson 1399*573ca77eSGeorge Wilson /* Nothing to look for */ 1400*573ca77eSGeorge Wilson if (search == NULL || pair == NULL) 1401*573ca77eSGeorge Wilson return (NULL); 1402ea8dc4b6Seschrock 1403*573ca77eSGeorge Wilson /* Obtain the key we will use to search */ 1404*573ca77eSGeorge Wilson srchkey = nvpair_name(pair); 1405*573ca77eSGeorge Wilson 1406*573ca77eSGeorge Wilson switch (nvpair_type(pair)) { 1407*573ca77eSGeorge Wilson case DATA_TYPE_UINT64: { 1408*573ca77eSGeorge Wilson uint64_t srchval, theguid, present; 1409*573ca77eSGeorge Wilson 1410*573ca77eSGeorge Wilson verify(nvpair_value_uint64(pair, &srchval) == 0); 1411*573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 1412*573ca77eSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1413*573ca77eSGeorge Wilson &present) == 0) { 1414*573ca77eSGeorge Wilson /* 1415*573ca77eSGeorge Wilson * If the device has never been present since 1416*573ca77eSGeorge Wilson * import, the only reliable way to match the 1417*573ca77eSGeorge Wilson * vdev is by GUID. 1418*573ca77eSGeorge Wilson */ 1419*573ca77eSGeorge Wilson verify(nvlist_lookup_uint64(nv, 1420*573ca77eSGeorge Wilson ZPOOL_CONFIG_GUID, &theguid) == 0); 1421*573ca77eSGeorge Wilson if (theguid == srchval) 1422*573ca77eSGeorge Wilson return (nv); 1423*573ca77eSGeorge Wilson } 1424*573ca77eSGeorge Wilson } 1425*573ca77eSGeorge Wilson break; 1426*573ca77eSGeorge Wilson } 1427*573ca77eSGeorge Wilson 1428*573ca77eSGeorge Wilson case DATA_TYPE_STRING: { 1429*573ca77eSGeorge Wilson char *srchval, *val; 1430*573ca77eSGeorge Wilson 1431*573ca77eSGeorge Wilson verify(nvpair_value_string(pair, &srchval) == 0); 1432*573ca77eSGeorge Wilson if (nvlist_lookup_string(nv, srchkey, &val) != 0) 1433*573ca77eSGeorge Wilson break; 1434ea8dc4b6Seschrock 1435ea8dc4b6Seschrock /* 1436*573ca77eSGeorge Wilson * Search for the requested value. We special case the search 1437*573ca77eSGeorge Wilson * for ZPOOL_CONFIG_PATH when it's a wholedisk. Otherwise, 1438*573ca77eSGeorge Wilson * all other searches are simple string compares. 1439ea8dc4b6Seschrock */ 1440*573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 1441*573ca77eSGeorge Wilson uint64_t wholedisk = 0; 1442*573ca77eSGeorge Wilson 1443*573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1444*573ca77eSGeorge Wilson &wholedisk); 1445*573ca77eSGeorge Wilson if (wholedisk) { 1446*573ca77eSGeorge Wilson /* 1447*573ca77eSGeorge Wilson * For whole disks, the internal path has 's0', 1448*573ca77eSGeorge Wilson * but the path passed in by the user doesn't. 1449*573ca77eSGeorge Wilson */ 1450*573ca77eSGeorge Wilson if (strlen(srchval) == strlen(val) - 2 && 1451*573ca77eSGeorge Wilson strncmp(srchval, val, strlen(srchval)) == 0) 1452*573ca77eSGeorge Wilson return (nv); 1453*573ca77eSGeorge Wilson break; 1454*573ca77eSGeorge Wilson } 1455ea8dc4b6Seschrock } 1456*573ca77eSGeorge Wilson 1457*573ca77eSGeorge Wilson /* 1458*573ca77eSGeorge Wilson * Common case 1459*573ca77eSGeorge Wilson */ 1460*573ca77eSGeorge Wilson if (strcmp(srchval, val) == 0) 1461*573ca77eSGeorge Wilson return (nv); 1462*573ca77eSGeorge Wilson break; 1463*573ca77eSGeorge Wilson } 1464*573ca77eSGeorge Wilson 1465*573ca77eSGeorge Wilson default: 1466*573ca77eSGeorge Wilson break; 1467ea8dc4b6Seschrock } 1468ea8dc4b6Seschrock 1469ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1470ea8dc4b6Seschrock &child, &children) != 0) 147199653d4eSeschrock return (NULL); 1472ea8dc4b6Seschrock 1473ee0eb9f2SEric Schrock for (c = 0; c < children; c++) { 1474*573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1475ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1476ee0eb9f2SEric Schrock /* 1477ee0eb9f2SEric Schrock * The 'is_log' value is only set for the toplevel 1478ee0eb9f2SEric Schrock * vdev, not the leaf vdevs. So we always lookup the 1479ee0eb9f2SEric Schrock * log device from the root of the vdev tree (where 1480ee0eb9f2SEric Schrock * 'log' is non-NULL). 1481ee0eb9f2SEric Schrock */ 1482ee0eb9f2SEric Schrock if (log != NULL && 1483ee0eb9f2SEric Schrock nvlist_lookup_uint64(child[c], 1484ee0eb9f2SEric Schrock ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 1485ee0eb9f2SEric Schrock is_log) { 1486ee0eb9f2SEric Schrock *log = B_TRUE; 1487ee0eb9f2SEric Schrock } 1488ea8dc4b6Seschrock return (ret); 1489ee0eb9f2SEric Schrock } 1490ee0eb9f2SEric Schrock } 1491ea8dc4b6Seschrock 149299653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 149399653d4eSeschrock &child, &children) == 0) { 149499653d4eSeschrock for (c = 0; c < children; c++) { 1495*573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1496ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1497a43d325bSek *avail_spare = B_TRUE; 149899653d4eSeschrock return (ret); 149999653d4eSeschrock } 150099653d4eSeschrock } 150199653d4eSeschrock } 150299653d4eSeschrock 1503fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1504fa94a07fSbrendan &child, &children) == 0) { 1505fa94a07fSbrendan for (c = 0; c < children; c++) { 1506*573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1507ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1508fa94a07fSbrendan *l2cache = B_TRUE; 1509fa94a07fSbrendan return (ret); 1510fa94a07fSbrendan } 1511fa94a07fSbrendan } 1512fa94a07fSbrendan } 1513fa94a07fSbrendan 151499653d4eSeschrock return (NULL); 1515ea8dc4b6Seschrock } 1516ea8dc4b6Seschrock 1517*573ca77eSGeorge Wilson /* 1518*573ca77eSGeorge Wilson * Given a physical path (minus the "/devices" prefix), find the 1519*573ca77eSGeorge Wilson * associated vdev. 1520*573ca77eSGeorge Wilson */ 1521*573ca77eSGeorge Wilson nvlist_t * 1522*573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 1523*573ca77eSGeorge Wilson boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 1524*573ca77eSGeorge Wilson { 1525*573ca77eSGeorge Wilson nvlist_t *search, *nvroot, *ret; 1526*573ca77eSGeorge Wilson 1527*573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1528*573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 1529*573ca77eSGeorge Wilson 1530*573ca77eSGeorge Wilson verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1531*573ca77eSGeorge Wilson &nvroot) == 0); 1532*573ca77eSGeorge Wilson 1533*573ca77eSGeorge Wilson *avail_spare = B_FALSE; 1534*573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1535*573ca77eSGeorge Wilson nvlist_free(search); 1536*573ca77eSGeorge Wilson 1537*573ca77eSGeorge Wilson return (ret); 1538*573ca77eSGeorge Wilson } 1539*573ca77eSGeorge Wilson 154099653d4eSeschrock nvlist_t * 1541fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 1542ee0eb9f2SEric Schrock boolean_t *l2cache, boolean_t *log) 1543ea8dc4b6Seschrock { 1544ea8dc4b6Seschrock char buf[MAXPATHLEN]; 1545ea8dc4b6Seschrock char *end; 1546*573ca77eSGeorge Wilson nvlist_t *nvroot, *search, *ret; 1547ea8dc4b6Seschrock uint64_t guid; 1548ea8dc4b6Seschrock 1549*573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1550*573ca77eSGeorge Wilson 15510917b783Seschrock guid = strtoull(path, &end, 10); 1552ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 1553*573ca77eSGeorge Wilson verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 1554ea8dc4b6Seschrock } else if (path[0] != '/') { 1555ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 1556*573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 1557ea8dc4b6Seschrock } else { 1558*573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 1559ea8dc4b6Seschrock } 1560ea8dc4b6Seschrock 1561ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1562ea8dc4b6Seschrock &nvroot) == 0); 1563ea8dc4b6Seschrock 1564a43d325bSek *avail_spare = B_FALSE; 1565fa94a07fSbrendan *l2cache = B_FALSE; 1566ee0eb9f2SEric Schrock if (log != NULL) 1567ee0eb9f2SEric Schrock *log = B_FALSE; 1568*573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1569*573ca77eSGeorge Wilson nvlist_free(search); 1570*573ca77eSGeorge Wilson 1571*573ca77eSGeorge Wilson return (ret); 1572a43d325bSek } 1573a43d325bSek 157419397407SSherry Moore static int 157519397407SSherry Moore vdev_online(nvlist_t *nv) 157619397407SSherry Moore { 157719397407SSherry Moore uint64_t ival; 157819397407SSherry Moore 157919397407SSherry Moore if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 158019397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 158119397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 158219397407SSherry Moore return (0); 158319397407SSherry Moore 158419397407SSherry Moore return (1); 158519397407SSherry Moore } 158619397407SSherry Moore 158719397407SSherry Moore /* 158821ecdf64SLin Ling * Helper function for zpool_get_physpaths(). 158919397407SSherry Moore */ 1590753a6d45SSherry Moore static int 159121ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 1592753a6d45SSherry Moore size_t *bytes_written) 159319397407SSherry Moore { 1594753a6d45SSherry Moore size_t bytes_left, pos, rsz; 1595753a6d45SSherry Moore char *tmppath; 1596753a6d45SSherry Moore const char *format; 1597753a6d45SSherry Moore 1598753a6d45SSherry Moore if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 1599753a6d45SSherry Moore &tmppath) != 0) 1600753a6d45SSherry Moore return (EZFS_NODEVICE); 1601753a6d45SSherry Moore 1602753a6d45SSherry Moore pos = *bytes_written; 1603753a6d45SSherry Moore bytes_left = physpath_size - pos; 1604753a6d45SSherry Moore format = (pos == 0) ? "%s" : " %s"; 1605753a6d45SSherry Moore 1606753a6d45SSherry Moore rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 1607753a6d45SSherry Moore *bytes_written += rsz; 1608753a6d45SSherry Moore 1609753a6d45SSherry Moore if (rsz >= bytes_left) { 1610753a6d45SSherry Moore /* if physpath was not copied properly, clear it */ 1611753a6d45SSherry Moore if (bytes_left != 0) { 1612753a6d45SSherry Moore physpath[pos] = 0; 1613753a6d45SSherry Moore } 1614753a6d45SSherry Moore return (EZFS_NOSPC); 1615753a6d45SSherry Moore } 1616753a6d45SSherry Moore return (0); 1617753a6d45SSherry Moore } 1618753a6d45SSherry Moore 161921ecdf64SLin Ling static int 162021ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 162121ecdf64SLin Ling size_t *rsz, boolean_t is_spare) 162221ecdf64SLin Ling { 162321ecdf64SLin Ling char *type; 162421ecdf64SLin Ling int ret; 162521ecdf64SLin Ling 162621ecdf64SLin Ling if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 162721ecdf64SLin Ling return (EZFS_INVALCONFIG); 162821ecdf64SLin Ling 162921ecdf64SLin Ling if (strcmp(type, VDEV_TYPE_DISK) == 0) { 163021ecdf64SLin Ling /* 163121ecdf64SLin Ling * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 163221ecdf64SLin Ling * For a spare vdev, we only want to boot from the active 163321ecdf64SLin Ling * spare device. 163421ecdf64SLin Ling */ 163521ecdf64SLin Ling if (is_spare) { 163621ecdf64SLin Ling uint64_t spare = 0; 163721ecdf64SLin Ling (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 163821ecdf64SLin Ling &spare); 163921ecdf64SLin Ling if (!spare) 164021ecdf64SLin Ling return (EZFS_INVALCONFIG); 164121ecdf64SLin Ling } 164221ecdf64SLin Ling 164321ecdf64SLin Ling if (vdev_online(nv)) { 164421ecdf64SLin Ling if ((ret = vdev_get_one_physpath(nv, physpath, 164521ecdf64SLin Ling phypath_size, rsz)) != 0) 164621ecdf64SLin Ling return (ret); 164721ecdf64SLin Ling } 164821ecdf64SLin Ling } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 164921ecdf64SLin Ling strcmp(type, VDEV_TYPE_REPLACING) == 0 || 165021ecdf64SLin Ling (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 165121ecdf64SLin Ling nvlist_t **child; 165221ecdf64SLin Ling uint_t count; 165321ecdf64SLin Ling int i, ret; 165421ecdf64SLin Ling 165521ecdf64SLin Ling if (nvlist_lookup_nvlist_array(nv, 165621ecdf64SLin Ling ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 165721ecdf64SLin Ling return (EZFS_INVALCONFIG); 165821ecdf64SLin Ling 165921ecdf64SLin Ling for (i = 0; i < count; i++) { 166021ecdf64SLin Ling ret = vdev_get_physpaths(child[i], physpath, 166121ecdf64SLin Ling phypath_size, rsz, is_spare); 166221ecdf64SLin Ling if (ret == EZFS_NOSPC) 166321ecdf64SLin Ling return (ret); 166421ecdf64SLin Ling } 166521ecdf64SLin Ling } 166621ecdf64SLin Ling 166721ecdf64SLin Ling return (EZFS_POOL_INVALARG); 166821ecdf64SLin Ling } 166921ecdf64SLin Ling 1670753a6d45SSherry Moore /* 1671753a6d45SSherry Moore * Get phys_path for a root pool config. 1672753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 1673753a6d45SSherry Moore */ 1674753a6d45SSherry Moore static int 1675753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 1676753a6d45SSherry Moore { 1677753a6d45SSherry Moore size_t rsz; 167819397407SSherry Moore nvlist_t *vdev_root; 167919397407SSherry Moore nvlist_t **child; 168019397407SSherry Moore uint_t count; 1681753a6d45SSherry Moore char *type; 1682753a6d45SSherry Moore 1683753a6d45SSherry Moore rsz = 0; 1684753a6d45SSherry Moore 1685753a6d45SSherry Moore if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1686753a6d45SSherry Moore &vdev_root) != 0) 1687753a6d45SSherry Moore return (EZFS_INVALCONFIG); 1688753a6d45SSherry Moore 1689753a6d45SSherry Moore if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 1690753a6d45SSherry Moore nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 1691753a6d45SSherry Moore &child, &count) != 0) 1692753a6d45SSherry Moore return (EZFS_INVALCONFIG); 169319397407SSherry Moore 169419397407SSherry Moore /* 1695753a6d45SSherry Moore * root pool can not have EFI labeled disks and can only have 1696753a6d45SSherry Moore * a single top-level vdev. 169719397407SSherry Moore */ 1698753a6d45SSherry Moore if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 1699753a6d45SSherry Moore pool_uses_efi(vdev_root)) 1700753a6d45SSherry Moore return (EZFS_POOL_INVALARG); 170119397407SSherry Moore 170221ecdf64SLin Ling (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 170321ecdf64SLin Ling B_FALSE); 170419397407SSherry Moore 1705753a6d45SSherry Moore /* No online devices */ 1706753a6d45SSherry Moore if (rsz == 0) 1707753a6d45SSherry Moore return (EZFS_NODEVICE); 1708753a6d45SSherry Moore 170919397407SSherry Moore return (0); 171019397407SSherry Moore } 171119397407SSherry Moore 1712753a6d45SSherry Moore /* 1713753a6d45SSherry Moore * Get phys_path for a root pool 1714753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 1715753a6d45SSherry Moore */ 1716753a6d45SSherry Moore int 1717753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 1718753a6d45SSherry Moore { 1719753a6d45SSherry Moore return (zpool_get_config_physpath(zhp->zpool_config, physpath, 1720753a6d45SSherry Moore phypath_size)); 1721753a6d45SSherry Moore } 1722753a6d45SSherry Moore 1723a43d325bSek /* 1724fa94a07fSbrendan * Returns TRUE if the given guid corresponds to the given type. 1725fa94a07fSbrendan * This is used to check for hot spares (INUSE or not), and level 2 cache 1726fa94a07fSbrendan * devices. 1727a43d325bSek */ 1728a43d325bSek static boolean_t 1729fa94a07fSbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type) 1730a43d325bSek { 1731fa94a07fSbrendan uint64_t target_guid; 1732a43d325bSek nvlist_t *nvroot; 1733fa94a07fSbrendan nvlist_t **list; 1734fa94a07fSbrendan uint_t count; 1735a43d325bSek int i; 1736a43d325bSek 1737a43d325bSek verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1738a43d325bSek &nvroot) == 0); 1739fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) { 1740fa94a07fSbrendan for (i = 0; i < count; i++) { 1741fa94a07fSbrendan verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID, 1742fa94a07fSbrendan &target_guid) == 0); 1743fa94a07fSbrendan if (guid == target_guid) 1744a43d325bSek return (B_TRUE); 1745a43d325bSek } 1746a43d325bSek } 1747a43d325bSek 1748a43d325bSek return (B_FALSE); 1749ea8dc4b6Seschrock } 1750ea8dc4b6Seschrock 1751*573ca77eSGeorge Wilson /* 1752*573ca77eSGeorge Wilson * If the device has being dynamically expanded then we need to relabel 1753*573ca77eSGeorge Wilson * the disk to use the new unallocated space. 1754*573ca77eSGeorge Wilson */ 1755*573ca77eSGeorge Wilson static int 1756*573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 1757*573ca77eSGeorge Wilson { 1758*573ca77eSGeorge Wilson char path[MAXPATHLEN]; 1759*573ca77eSGeorge Wilson char errbuf[1024]; 1760*573ca77eSGeorge Wilson int fd, error; 1761*573ca77eSGeorge Wilson int (*_efi_use_whole_disk)(int); 1762*573ca77eSGeorge Wilson 1763*573ca77eSGeorge Wilson if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 1764*573ca77eSGeorge Wilson "efi_use_whole_disk")) == NULL) 1765*573ca77eSGeorge Wilson return (-1); 1766*573ca77eSGeorge Wilson 1767*573ca77eSGeorge Wilson (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 1768*573ca77eSGeorge Wilson 1769*573ca77eSGeorge Wilson if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 1770*573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 1771*573ca77eSGeorge Wilson "relabel '%s': unable to open device"), name); 1772*573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 1773*573ca77eSGeorge Wilson } 1774*573ca77eSGeorge Wilson 1775*573ca77eSGeorge Wilson /* 1776*573ca77eSGeorge Wilson * It's possible that we might encounter an error if the device 1777*573ca77eSGeorge Wilson * does not have any unallocated space left. If so, we simply 1778*573ca77eSGeorge Wilson * ignore that error and continue on. 1779*573ca77eSGeorge Wilson */ 1780*573ca77eSGeorge Wilson error = _efi_use_whole_disk(fd); 1781*573ca77eSGeorge Wilson (void) close(fd); 1782*573ca77eSGeorge Wilson if (error && error != VT_ENOSPC) { 1783*573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 1784*573ca77eSGeorge Wilson "relabel '%s': unable to read disk capacity"), name); 1785*573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 1786*573ca77eSGeorge Wilson } 1787*573ca77eSGeorge Wilson return (0); 1788*573ca77eSGeorge Wilson } 1789*573ca77eSGeorge Wilson 1790fa9e4066Sahrens /* 17913d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 17923d7072f8Seschrock * ZFS_ONLINE_* flags. 1793fa9e4066Sahrens */ 1794fa9e4066Sahrens int 17953d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 17963d7072f8Seschrock vdev_state_t *newstate) 1797fa9e4066Sahrens { 1798fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1799fa9e4066Sahrens char msg[1024]; 180099653d4eSeschrock nvlist_t *tgt; 1801*573ca77eSGeorge Wilson boolean_t avail_spare, l2cache, islog; 180299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1803fa9e4066Sahrens 1804*573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND) { 1805*573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 1806*573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 1807*573ca77eSGeorge Wilson } else { 1808*573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 1809*573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot online %s"), path); 1810*573ca77eSGeorge Wilson } 1811ea8dc4b6Seschrock 1812fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1813ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1814*573ca77eSGeorge Wilson &islog)) == NULL) 181599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1816fa9e4066Sahrens 181799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1818fa9e4066Sahrens 1819fa94a07fSbrendan if (avail_spare || 1820fa94a07fSbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 1821a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1822a43d325bSek 1823*573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND || 1824*573ca77eSGeorge Wilson zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 1825*573ca77eSGeorge Wilson char *pathname = NULL; 1826*573ca77eSGeorge Wilson uint64_t wholedisk = 0; 1827*573ca77eSGeorge Wilson 1828*573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 1829*573ca77eSGeorge Wilson &wholedisk); 1830*573ca77eSGeorge Wilson verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 1831*573ca77eSGeorge Wilson &pathname) == 0); 1832*573ca77eSGeorge Wilson 1833*573ca77eSGeorge Wilson /* 1834*573ca77eSGeorge Wilson * XXX - L2ARC 1.0 devices can't support expansion. 1835*573ca77eSGeorge Wilson */ 1836*573ca77eSGeorge Wilson if (l2cache) { 1837*573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1838*573ca77eSGeorge Wilson "cannot expand cache devices")); 1839*573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 1840*573ca77eSGeorge Wilson } 1841*573ca77eSGeorge Wilson 1842*573ca77eSGeorge Wilson if (wholedisk) { 1843*573ca77eSGeorge Wilson pathname += strlen(DISK_ROOT) + 1; 1844*573ca77eSGeorge Wilson (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 1845*573ca77eSGeorge Wilson } 1846*573ca77eSGeorge Wilson } 1847*573ca77eSGeorge Wilson 18483d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 18493d7072f8Seschrock zc.zc_obj = flags; 1850fa9e4066Sahrens 1851ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 18523d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 18533d7072f8Seschrock 18543d7072f8Seschrock *newstate = zc.zc_cookie; 18553d7072f8Seschrock return (0); 1856fa9e4066Sahrens } 1857fa9e4066Sahrens 1858fa9e4066Sahrens /* 1859fa9e4066Sahrens * Take the specified vdev offline 1860fa9e4066Sahrens */ 1861fa9e4066Sahrens int 18623d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 1863fa9e4066Sahrens { 1864fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1865fa9e4066Sahrens char msg[1024]; 186699653d4eSeschrock nvlist_t *tgt; 1867fa94a07fSbrendan boolean_t avail_spare, l2cache; 186899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1869fa9e4066Sahrens 1870ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1871ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 1872ea8dc4b6Seschrock 1873fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1874ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 1875ee0eb9f2SEric Schrock NULL)) == NULL) 187699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 187799653d4eSeschrock 187899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1879fa9e4066Sahrens 1880fa94a07fSbrendan if (avail_spare || 1881fa94a07fSbrendan is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE) 1882a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1883a43d325bSek 18843d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 18853d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 18863d7072f8Seschrock 1887ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 18883d7072f8Seschrock return (0); 18893d7072f8Seschrock 18903d7072f8Seschrock switch (errno) { 18913d7072f8Seschrock case EBUSY: 18923d7072f8Seschrock 18933d7072f8Seschrock /* 18943d7072f8Seschrock * There are no other replicas of this device. 18953d7072f8Seschrock */ 18963d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 18973d7072f8Seschrock 1898e6ca193dSGeorge Wilson case EEXIST: 1899e6ca193dSGeorge Wilson /* 1900e6ca193dSGeorge Wilson * The log device has unplayed logs 1901e6ca193dSGeorge Wilson */ 1902e6ca193dSGeorge Wilson return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 1903e6ca193dSGeorge Wilson 19043d7072f8Seschrock default: 19053d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 19063d7072f8Seschrock } 19073d7072f8Seschrock } 19083d7072f8Seschrock 19093d7072f8Seschrock /* 19103d7072f8Seschrock * Mark the given vdev faulted. 19113d7072f8Seschrock */ 19123d7072f8Seschrock int 19133d7072f8Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 19143d7072f8Seschrock { 19153d7072f8Seschrock zfs_cmd_t zc = { 0 }; 19163d7072f8Seschrock char msg[1024]; 19173d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19183d7072f8Seschrock 19193d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 19203d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 1921441d80aaSlling 19223d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19233d7072f8Seschrock zc.zc_guid = guid; 19243d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 19253d7072f8Seschrock 19263d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 1927fa9e4066Sahrens return (0); 1928fa9e4066Sahrens 1929fa9e4066Sahrens switch (errno) { 193099653d4eSeschrock case EBUSY: 1931fa9e4066Sahrens 1932fa9e4066Sahrens /* 1933fa9e4066Sahrens * There are no other replicas of this device. 1934fa9e4066Sahrens */ 193599653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 1936fa9e4066Sahrens 193799653d4eSeschrock default: 193899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1939fa9e4066Sahrens } 19403d7072f8Seschrock 19413d7072f8Seschrock } 19423d7072f8Seschrock 19433d7072f8Seschrock /* 19443d7072f8Seschrock * Mark the given vdev degraded. 19453d7072f8Seschrock */ 19463d7072f8Seschrock int 19473d7072f8Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 19483d7072f8Seschrock { 19493d7072f8Seschrock zfs_cmd_t zc = { 0 }; 19503d7072f8Seschrock char msg[1024]; 19513d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 19523d7072f8Seschrock 19533d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 19543d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 19553d7072f8Seschrock 19563d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 19573d7072f8Seschrock zc.zc_guid = guid; 19583d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 19593d7072f8Seschrock 19603d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 19613d7072f8Seschrock return (0); 19623d7072f8Seschrock 19633d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 196499653d4eSeschrock } 196599653d4eSeschrock 196699653d4eSeschrock /* 196799653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 196899653d4eSeschrock * a hot spare. 196999653d4eSeschrock */ 197099653d4eSeschrock static boolean_t 197199653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 197299653d4eSeschrock { 197399653d4eSeschrock nvlist_t **child; 197499653d4eSeschrock uint_t c, children; 197599653d4eSeschrock char *type; 197699653d4eSeschrock 197799653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 197899653d4eSeschrock &children) == 0) { 197999653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 198099653d4eSeschrock &type) == 0); 198199653d4eSeschrock 198299653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 198399653d4eSeschrock children == 2 && child[which] == tgt) 198499653d4eSeschrock return (B_TRUE); 198599653d4eSeschrock 198699653d4eSeschrock for (c = 0; c < children; c++) 198799653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 198899653d4eSeschrock return (B_TRUE); 198999653d4eSeschrock } 199099653d4eSeschrock 199199653d4eSeschrock return (B_FALSE); 1992fa9e4066Sahrens } 1993fa9e4066Sahrens 1994fa9e4066Sahrens /* 1995fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 19968654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 1997fa9e4066Sahrens */ 1998fa9e4066Sahrens int 1999fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2000fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2001fa9e4066Sahrens { 2002fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2003fa9e4066Sahrens char msg[1024]; 2004fa9e4066Sahrens int ret; 200599653d4eSeschrock nvlist_t *tgt; 2006ee0eb9f2SEric Schrock boolean_t avail_spare, l2cache, islog; 2007ee0eb9f2SEric Schrock uint64_t val; 20080430f8daSeschrock char *path, *newname; 200999653d4eSeschrock nvlist_t **child; 201099653d4eSeschrock uint_t children; 201199653d4eSeschrock nvlist_t *config_root; 201299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2013b5b76fecSGeorge Wilson boolean_t rootpool = pool_is_bootable(zhp); 2014fa9e4066Sahrens 2015ea8dc4b6Seschrock if (replacing) 2016ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2017ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 2018ea8dc4b6Seschrock else 2019ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2020ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 2021ea8dc4b6Seschrock 2022b5b76fecSGeorge Wilson /* 2023b5b76fecSGeorge Wilson * If this is a root pool, make sure that we're not attaching an 2024b5b76fecSGeorge Wilson * EFI labeled device. 2025b5b76fecSGeorge Wilson */ 2026b5b76fecSGeorge Wilson if (rootpool && pool_uses_efi(nvroot)) { 2027b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2028b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root pools.")); 2029b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 2030b5b76fecSGeorge Wilson } 2031b5b76fecSGeorge Wilson 2032fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2033ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 2034ee0eb9f2SEric Schrock &islog)) == 0) 203599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 203699653d4eSeschrock 2037a43d325bSek if (avail_spare) 203899653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 203999653d4eSeschrock 2040fa94a07fSbrendan if (l2cache) 2041fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2042fa94a07fSbrendan 204399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2044fa9e4066Sahrens zc.zc_cookie = replacing; 2045fa9e4066Sahrens 204699653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 204799653d4eSeschrock &child, &children) != 0 || children != 1) { 204899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 204999653d4eSeschrock "new device must be a single disk")); 205099653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 205199653d4eSeschrock } 205299653d4eSeschrock 205399653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 205499653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 205599653d4eSeschrock 20560430f8daSeschrock if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL) 20570430f8daSeschrock return (-1); 20580430f8daSeschrock 205999653d4eSeschrock /* 206099653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 206199653d4eSeschrock * replace it with another hot spare. 206299653d4eSeschrock */ 206399653d4eSeschrock if (replacing && 206499653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 2065ee0eb9f2SEric Schrock (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 2066ee0eb9f2SEric Schrock NULL) == NULL || !avail_spare) && 2067ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 1)) { 206899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 206999653d4eSeschrock "can only be replaced by another hot spare")); 20700430f8daSeschrock free(newname); 207199653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 207299653d4eSeschrock } 207399653d4eSeschrock 207499653d4eSeschrock /* 207599653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 207699653d4eSeschrock * already spared device. 207799653d4eSeschrock */ 207899653d4eSeschrock if (replacing && 207999653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 2080ee0eb9f2SEric Schrock zpool_find_vdev(zhp, newname, &avail_spare, 2081ee0eb9f2SEric Schrock &l2cache, NULL) != NULL && avail_spare && 2082ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 0)) { 208399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 208499653d4eSeschrock "device has already been replaced with a spare")); 20850430f8daSeschrock free(newname); 208699653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 208799653d4eSeschrock } 208899653d4eSeschrock 20890430f8daSeschrock free(newname); 20900430f8daSeschrock 2091990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 209299653d4eSeschrock return (-1); 2093fa9e4066Sahrens 2094ecd6cf80Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2095fa9e4066Sahrens 2096e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2097fa9e4066Sahrens 2098b5b76fecSGeorge Wilson if (ret == 0) { 2099b5b76fecSGeorge Wilson if (rootpool) { 2100b5b76fecSGeorge Wilson /* 2101b5b76fecSGeorge Wilson * XXX - This should be removed once we can 2102b5b76fecSGeorge Wilson * automatically install the bootblocks on the 2103b5b76fecSGeorge Wilson * newly attached disk. 2104b5b76fecSGeorge Wilson */ 2105b5b76fecSGeorge Wilson (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 2106b5b76fecSGeorge Wilson "be sure to invoke %s to make '%s' bootable.\n"), 2107b5b76fecSGeorge Wilson BOOTCMD, new_disk); 210821ecdf64SLin Ling 210921ecdf64SLin Ling /* 211021ecdf64SLin Ling * XXX need a better way to prevent user from 211121ecdf64SLin Ling * booting up a half-baked vdev. 211221ecdf64SLin Ling */ 211321ecdf64SLin Ling (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 211421ecdf64SLin Ling "sure to wait until resilver is done " 211521ecdf64SLin Ling "before rebooting.\n")); 2116b5b76fecSGeorge Wilson } 2117fa9e4066Sahrens return (0); 2118b5b76fecSGeorge Wilson } 2119fa9e4066Sahrens 2120fa9e4066Sahrens switch (errno) { 2121ea8dc4b6Seschrock case ENOTSUP: 2122fa9e4066Sahrens /* 2123fa9e4066Sahrens * Can't attach to or replace this type of vdev. 2124fa9e4066Sahrens */ 21258654d025Sperrin if (replacing) { 2126ee0eb9f2SEric Schrock if (islog) 21278654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21288654d025Sperrin "cannot replace a log with a spare")); 21298654d025Sperrin else 21308654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21318654d025Sperrin "cannot replace a replacing device")); 21328654d025Sperrin } else { 213399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 213499653d4eSeschrock "can only attach to mirrors and top-level " 213599653d4eSeschrock "disks")); 21368654d025Sperrin } 213799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2138fa9e4066Sahrens break; 2139fa9e4066Sahrens 2140ea8dc4b6Seschrock case EINVAL: 2141fa9e4066Sahrens /* 2142fa9e4066Sahrens * The new device must be a single disk. 2143fa9e4066Sahrens */ 214499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 214599653d4eSeschrock "new device must be a single disk")); 214699653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2147fa9e4066Sahrens break; 2148fa9e4066Sahrens 2149ea8dc4b6Seschrock case EBUSY: 215099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 215199653d4eSeschrock new_disk); 215299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2153fa9e4066Sahrens break; 2154fa9e4066Sahrens 2155ea8dc4b6Seschrock case EOVERFLOW: 2156fa9e4066Sahrens /* 2157fa9e4066Sahrens * The new device is too small. 2158fa9e4066Sahrens */ 215999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 216099653d4eSeschrock "device is too small")); 216199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2162fa9e4066Sahrens break; 2163fa9e4066Sahrens 2164ea8dc4b6Seschrock case EDOM: 2165fa9e4066Sahrens /* 2166fa9e4066Sahrens * The new device has a different alignment requirement. 2167fa9e4066Sahrens */ 216899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 216999653d4eSeschrock "devices have different sector alignment")); 217099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2171fa9e4066Sahrens break; 2172fa9e4066Sahrens 2173ea8dc4b6Seschrock case ENAMETOOLONG: 2174fa9e4066Sahrens /* 2175fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 2176fa9e4066Sahrens */ 217799653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2178fa9e4066Sahrens break; 2179fa9e4066Sahrens 2180ea8dc4b6Seschrock default: 218199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2182fa9e4066Sahrens } 2183fa9e4066Sahrens 218499653d4eSeschrock return (-1); 2185fa9e4066Sahrens } 2186fa9e4066Sahrens 2187fa9e4066Sahrens /* 2188fa9e4066Sahrens * Detach the specified device. 2189fa9e4066Sahrens */ 2190fa9e4066Sahrens int 2191fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2192fa9e4066Sahrens { 2193fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2194fa9e4066Sahrens char msg[1024]; 219599653d4eSeschrock nvlist_t *tgt; 2196fa94a07fSbrendan boolean_t avail_spare, l2cache; 219799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2198fa9e4066Sahrens 2199ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2200ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 2201ea8dc4b6Seschrock 2202fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2203ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2204ee0eb9f2SEric Schrock NULL)) == 0) 220599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2206fa9e4066Sahrens 2207a43d325bSek if (avail_spare) 220899653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 220999653d4eSeschrock 2210fa94a07fSbrendan if (l2cache) 2211fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2212fa94a07fSbrendan 221399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 221499653d4eSeschrock 2215ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2216fa9e4066Sahrens return (0); 2217fa9e4066Sahrens 2218fa9e4066Sahrens switch (errno) { 2219fa9e4066Sahrens 2220ea8dc4b6Seschrock case ENOTSUP: 2221fa9e4066Sahrens /* 2222fa9e4066Sahrens * Can't detach from this type of vdev. 2223fa9e4066Sahrens */ 222499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 222599653d4eSeschrock "applicable to mirror and replacing vdevs")); 222699653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2227fa9e4066Sahrens break; 2228fa9e4066Sahrens 2229ea8dc4b6Seschrock case EBUSY: 2230fa9e4066Sahrens /* 2231fa9e4066Sahrens * There are no other replicas of this device. 2232fa9e4066Sahrens */ 223399653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2234fa9e4066Sahrens break; 2235fa9e4066Sahrens 2236ea8dc4b6Seschrock default: 223799653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2238ea8dc4b6Seschrock } 2239ea8dc4b6Seschrock 224099653d4eSeschrock return (-1); 224199653d4eSeschrock } 224299653d4eSeschrock 224399653d4eSeschrock /* 2244fa94a07fSbrendan * Remove the given device. Currently, this is supported only for hot spares 2245fa94a07fSbrendan * and level 2 cache devices. 224699653d4eSeschrock */ 224799653d4eSeschrock int 224899653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 224999653d4eSeschrock { 225099653d4eSeschrock zfs_cmd_t zc = { 0 }; 225199653d4eSeschrock char msg[1024]; 225299653d4eSeschrock nvlist_t *tgt; 2253fa94a07fSbrendan boolean_t avail_spare, l2cache; 225499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 225599653d4eSeschrock 225699653d4eSeschrock (void) snprintf(msg, sizeof (msg), 225799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 225899653d4eSeschrock 225999653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2260ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2261ee0eb9f2SEric Schrock NULL)) == 0) 226299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 226399653d4eSeschrock 2264fa94a07fSbrendan if (!avail_spare && !l2cache) { 226599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2266fa94a07fSbrendan "only inactive hot spares or cache devices " 2267fa94a07fSbrendan "can be removed")); 226899653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 226999653d4eSeschrock } 227099653d4eSeschrock 227199653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 227299653d4eSeschrock 2273ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 227499653d4eSeschrock return (0); 227599653d4eSeschrock 227699653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2277ea8dc4b6Seschrock } 2278ea8dc4b6Seschrock 2279ea8dc4b6Seschrock /* 2280ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 2281ea8dc4b6Seschrock */ 2282ea8dc4b6Seschrock int 2283ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 2284ea8dc4b6Seschrock { 2285ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2286ea8dc4b6Seschrock char msg[1024]; 228799653d4eSeschrock nvlist_t *tgt; 2288fa94a07fSbrendan boolean_t avail_spare, l2cache; 228999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2290ea8dc4b6Seschrock 2291ea8dc4b6Seschrock if (path) 2292ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2293ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2294e9dbad6fSeschrock path); 2295ea8dc4b6Seschrock else 2296ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2297ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2298ea8dc4b6Seschrock zhp->zpool_name); 2299ea8dc4b6Seschrock 2300ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 230199653d4eSeschrock if (path) { 2302fa94a07fSbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 2303ee0eb9f2SEric Schrock &l2cache, NULL)) == 0) 230499653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2305ea8dc4b6Seschrock 2306fa94a07fSbrendan /* 2307fa94a07fSbrendan * Don't allow error clearing for hot spares. Do allow 2308fa94a07fSbrendan * error clearing for l2cache devices. 2309fa94a07fSbrendan */ 2310a43d325bSek if (avail_spare) 231199653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2312ea8dc4b6Seschrock 231399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 231499653d4eSeschrock &zc.zc_guid) == 0); 2315fa9e4066Sahrens } 2316fa9e4066Sahrens 2317ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 231899653d4eSeschrock return (0); 231999653d4eSeschrock 232099653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2321fa9e4066Sahrens } 2322fa9e4066Sahrens 23233d7072f8Seschrock /* 23243d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 23253d7072f8Seschrock */ 23263d7072f8Seschrock int 23273d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 23283d7072f8Seschrock { 23293d7072f8Seschrock zfs_cmd_t zc = { 0 }; 23303d7072f8Seschrock char msg[1024]; 23313d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 23323d7072f8Seschrock 23333d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 23343d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 23353d7072f8Seschrock guid); 23363d7072f8Seschrock 23373d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 23383d7072f8Seschrock zc.zc_guid = guid; 23393d7072f8Seschrock 23403d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 23413d7072f8Seschrock return (0); 23423d7072f8Seschrock 23433d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 23443d7072f8Seschrock } 23453d7072f8Seschrock 2346f3861e1aSahl /* 2347f3861e1aSahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 2348f3861e1aSahl * hierarchy. 2349f3861e1aSahl */ 2350f3861e1aSahl int 2351f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 2352f3861e1aSahl void *data) 2353fa9e4066Sahrens { 2354f3861e1aSahl libzfs_handle_t *hdl = zhp->zpool_hdl; 2355f3861e1aSahl char (*paths)[MAXPATHLEN]; 2356f3861e1aSahl size_t size = 4; 2357f3861e1aSahl int curr, fd, base, ret = 0; 2358f3861e1aSahl DIR *dirp; 2359f3861e1aSahl struct dirent *dp; 2360f3861e1aSahl struct stat st; 2361f3861e1aSahl 2362f3861e1aSahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 2363f3861e1aSahl return (errno == ENOENT ? 0 : -1); 2364f3861e1aSahl 2365f3861e1aSahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 2366f3861e1aSahl int err = errno; 2367f3861e1aSahl (void) close(base); 2368f3861e1aSahl return (err == ENOENT ? 0 : -1); 2369f3861e1aSahl } 2370fa9e4066Sahrens 2371fa9e4066Sahrens /* 2372f3861e1aSahl * Oddly this wasn't a directory -- ignore that failure since we 2373f3861e1aSahl * know there are no links lower in the (non-existant) hierarchy. 2374fa9e4066Sahrens */ 2375f3861e1aSahl if (!S_ISDIR(st.st_mode)) { 2376f3861e1aSahl (void) close(base); 2377f3861e1aSahl return (0); 2378fa9e4066Sahrens } 2379fa9e4066Sahrens 2380f3861e1aSahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 2381f3861e1aSahl (void) close(base); 2382f3861e1aSahl return (-1); 2383f3861e1aSahl } 2384f3861e1aSahl 2385f3861e1aSahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 2386f3861e1aSahl curr = 0; 2387f3861e1aSahl 2388f3861e1aSahl while (curr >= 0) { 2389f3861e1aSahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 2390f3861e1aSahl goto err; 2391f3861e1aSahl 2392f3861e1aSahl if (S_ISDIR(st.st_mode)) { 2393f3861e1aSahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 2394f3861e1aSahl goto err; 2395f3861e1aSahl 2396f3861e1aSahl if ((dirp = fdopendir(fd)) == NULL) { 2397f3861e1aSahl (void) close(fd); 2398f3861e1aSahl goto err; 2399f3861e1aSahl } 2400f3861e1aSahl 2401f3861e1aSahl while ((dp = readdir(dirp)) != NULL) { 2402f3861e1aSahl if (dp->d_name[0] == '.') 2403f3861e1aSahl continue; 2404f3861e1aSahl 2405f3861e1aSahl if (curr + 1 == size) { 2406f3861e1aSahl paths = zfs_realloc(hdl, paths, 2407f3861e1aSahl size * sizeof (paths[0]), 2408f3861e1aSahl size * 2 * sizeof (paths[0])); 2409f3861e1aSahl if (paths == NULL) { 2410f3861e1aSahl (void) closedir(dirp); 2411f3861e1aSahl (void) close(fd); 2412f3861e1aSahl goto err; 2413f3861e1aSahl } 2414f3861e1aSahl 2415f3861e1aSahl size *= 2; 2416f3861e1aSahl } 2417f3861e1aSahl 2418f3861e1aSahl (void) strlcpy(paths[curr + 1], paths[curr], 2419f3861e1aSahl sizeof (paths[curr + 1])); 2420f3861e1aSahl (void) strlcat(paths[curr], "/", 2421f3861e1aSahl sizeof (paths[curr])); 2422f3861e1aSahl (void) strlcat(paths[curr], dp->d_name, 2423f3861e1aSahl sizeof (paths[curr])); 2424f3861e1aSahl curr++; 2425f3861e1aSahl } 2426f3861e1aSahl 2427f3861e1aSahl (void) closedir(dirp); 2428f3861e1aSahl 2429f3861e1aSahl } else { 2430f3861e1aSahl if ((ret = cb(paths[curr], data)) != 0) 2431f3861e1aSahl break; 2432f3861e1aSahl } 2433f3861e1aSahl 2434f3861e1aSahl curr--; 2435f3861e1aSahl } 2436f3861e1aSahl 2437f3861e1aSahl free(paths); 2438f3861e1aSahl (void) close(base); 2439f3861e1aSahl 2440f3861e1aSahl return (ret); 2441f3861e1aSahl 2442f3861e1aSahl err: 2443f3861e1aSahl free(paths); 2444f3861e1aSahl (void) close(base); 2445f3861e1aSahl return (-1); 2446f3861e1aSahl } 2447f3861e1aSahl 2448f3861e1aSahl typedef struct zvol_cb { 2449f3861e1aSahl zpool_handle_t *zcb_pool; 2450f3861e1aSahl boolean_t zcb_create; 2451f3861e1aSahl } zvol_cb_t; 2452f3861e1aSahl 2453f3861e1aSahl /*ARGSUSED*/ 2454f3861e1aSahl static int 2455f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data) 2456f3861e1aSahl { 24573aefe2c7Sahrens int ret = 0; 2458f3861e1aSahl 24593aefe2c7Sahrens if (ZFS_IS_VOLUME(zhp)) { 2460f3861e1aSahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 24613aefe2c7Sahrens ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL); 24623aefe2c7Sahrens } 2463f3861e1aSahl 24643aefe2c7Sahrens if (ret == 0) 24653aefe2c7Sahrens ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL); 2466fa9e4066Sahrens 2467fa9e4066Sahrens zfs_close(zhp); 2468f3861e1aSahl 2469fa9e4066Sahrens return (ret); 2470fa9e4066Sahrens } 2471fa9e4066Sahrens 2472fa9e4066Sahrens /* 2473fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 2474fa9e4066Sahrens */ 2475fa9e4066Sahrens int 2476fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 2477fa9e4066Sahrens { 2478fa9e4066Sahrens zfs_handle_t *zfp; 2479fa9e4066Sahrens int ret; 2480fa9e4066Sahrens 2481fa9e4066Sahrens /* 2482fa9e4066Sahrens * If the pool is unavailable, just return success. 2483fa9e4066Sahrens */ 248499653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 248599653d4eSeschrock zhp->zpool_name)) == NULL) 2486fa9e4066Sahrens return (0); 2487fa9e4066Sahrens 24883aefe2c7Sahrens ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL); 2489fa9e4066Sahrens 2490fa9e4066Sahrens zfs_close(zfp); 2491fa9e4066Sahrens return (ret); 2492fa9e4066Sahrens } 2493fa9e4066Sahrens 2494f3861e1aSahl static int 2495f3861e1aSahl do_zvol_remove(const char *dataset, void *data) 2496f3861e1aSahl { 2497f3861e1aSahl zpool_handle_t *zhp = data; 2498f3861e1aSahl 2499f3861e1aSahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 2500f3861e1aSahl } 2501f3861e1aSahl 2502fa9e4066Sahrens /* 2503f3861e1aSahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 2504f3861e1aSahl * by examining the /dev links so that a corrupted pool doesn't impede this 2505f3861e1aSahl * operation. 2506fa9e4066Sahrens */ 2507fa9e4066Sahrens int 2508fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 2509fa9e4066Sahrens { 2510f3861e1aSahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 2511fa9e4066Sahrens } 2512c67d9675Seschrock 2513c67d9675Seschrock /* 2514c67d9675Seschrock * Convert from a devid string to a path. 2515c67d9675Seschrock */ 2516c67d9675Seschrock static char * 2517c67d9675Seschrock devid_to_path(char *devid_str) 2518c67d9675Seschrock { 2519c67d9675Seschrock ddi_devid_t devid; 2520c67d9675Seschrock char *minor; 2521c67d9675Seschrock char *path; 2522c67d9675Seschrock devid_nmlist_t *list = NULL; 2523c67d9675Seschrock int ret; 2524c67d9675Seschrock 2525c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 2526c67d9675Seschrock return (NULL); 2527c67d9675Seschrock 2528c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 2529c67d9675Seschrock 2530c67d9675Seschrock devid_str_free(minor); 2531c67d9675Seschrock devid_free(devid); 2532c67d9675Seschrock 2533c67d9675Seschrock if (ret != 0) 2534c67d9675Seschrock return (NULL); 2535c67d9675Seschrock 253699653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 253799653d4eSeschrock return (NULL); 253899653d4eSeschrock 2539c67d9675Seschrock devid_free_nmlist(list); 2540c67d9675Seschrock 2541c67d9675Seschrock return (path); 2542c67d9675Seschrock } 2543c67d9675Seschrock 2544c67d9675Seschrock /* 2545c67d9675Seschrock * Convert from a path to a devid string. 2546c67d9675Seschrock */ 2547c67d9675Seschrock static char * 2548c67d9675Seschrock path_to_devid(const char *path) 2549c67d9675Seschrock { 2550c67d9675Seschrock int fd; 2551c67d9675Seschrock ddi_devid_t devid; 2552c67d9675Seschrock char *minor, *ret; 2553c67d9675Seschrock 2554c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 2555c67d9675Seschrock return (NULL); 2556c67d9675Seschrock 2557c67d9675Seschrock minor = NULL; 2558c67d9675Seschrock ret = NULL; 2559c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 2560c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 2561c67d9675Seschrock ret = devid_str_encode(devid, minor); 2562c67d9675Seschrock if (minor != NULL) 2563c67d9675Seschrock devid_str_free(minor); 2564c67d9675Seschrock devid_free(devid); 2565c67d9675Seschrock } 2566c67d9675Seschrock (void) close(fd); 2567c67d9675Seschrock 2568c67d9675Seschrock return (ret); 2569c67d9675Seschrock } 2570c67d9675Seschrock 2571c67d9675Seschrock /* 2572c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 2573c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 2574c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 2575c67d9675Seschrock */ 2576c67d9675Seschrock static void 2577c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 2578c67d9675Seschrock { 2579c67d9675Seschrock zfs_cmd_t zc = { 0 }; 2580c67d9675Seschrock 2581c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2582e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 2583c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2584ea8dc4b6Seschrock &zc.zc_guid) == 0); 2585c67d9675Seschrock 258699653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 2587c67d9675Seschrock } 2588c67d9675Seschrock 2589c67d9675Seschrock /* 2590c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 2591c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 2592c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 2593c67d9675Seschrock * trailing 's0' slice name. 2594c67d9675Seschrock * 2595c67d9675Seschrock * This routine is also responsible for identifying when disks have been 2596c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 2597c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 2598c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 2599c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 2600c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 2601c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 2602c67d9675Seschrock * of these checks. 2603c67d9675Seschrock */ 2604c67d9675Seschrock char * 260599653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 2606c67d9675Seschrock { 2607c67d9675Seschrock char *path, *devid; 2608ea8dc4b6Seschrock uint64_t value; 2609ea8dc4b6Seschrock char buf[64]; 26103d7072f8Seschrock vdev_stat_t *vs; 26113d7072f8Seschrock uint_t vsc; 2612c67d9675Seschrock 2613ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2614ea8dc4b6Seschrock &value) == 0) { 2615ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2616ea8dc4b6Seschrock &value) == 0); 26175ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 26185ad82045Snd (u_longlong_t)value); 2619ea8dc4b6Seschrock path = buf; 2620ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 2621c67d9675Seschrock 26223d7072f8Seschrock /* 26233d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 26243d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 26253d7072f8Seschrock * open a misbehaving device, which can have undesirable 26263d7072f8Seschrock * effects. 26273d7072f8Seschrock */ 26283d7072f8Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 26293d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 26303d7072f8Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 26313d7072f8Seschrock zhp != NULL && 2632c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 2633c67d9675Seschrock /* 2634c67d9675Seschrock * Determine if the current path is correct. 2635c67d9675Seschrock */ 2636c67d9675Seschrock char *newdevid = path_to_devid(path); 2637c67d9675Seschrock 2638c67d9675Seschrock if (newdevid == NULL || 2639c67d9675Seschrock strcmp(devid, newdevid) != 0) { 2640c67d9675Seschrock char *newpath; 2641c67d9675Seschrock 2642c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 2643c67d9675Seschrock /* 2644c67d9675Seschrock * Update the path appropriately. 2645c67d9675Seschrock */ 2646c67d9675Seschrock set_path(zhp, nv, newpath); 264799653d4eSeschrock if (nvlist_add_string(nv, 264899653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 264999653d4eSeschrock verify(nvlist_lookup_string(nv, 265099653d4eSeschrock ZPOOL_CONFIG_PATH, 265199653d4eSeschrock &path) == 0); 2652c67d9675Seschrock free(newpath); 2653c67d9675Seschrock } 2654c67d9675Seschrock } 2655c67d9675Seschrock 265699653d4eSeschrock if (newdevid) 265799653d4eSeschrock devid_str_free(newdevid); 2658c67d9675Seschrock } 2659c67d9675Seschrock 2660c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 2661c67d9675Seschrock path += 9; 2662c67d9675Seschrock 2663c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 2664ea8dc4b6Seschrock &value) == 0 && value) { 266599653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 266699653d4eSeschrock if (tmp == NULL) 266799653d4eSeschrock return (NULL); 2668c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 2669c67d9675Seschrock return (tmp); 2670c67d9675Seschrock } 2671c67d9675Seschrock } else { 2672c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 267399653d4eSeschrock 267499653d4eSeschrock /* 267599653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 267699653d4eSeschrock */ 267799653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 267899653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 267999653d4eSeschrock &value) == 0); 268099653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 26815ad82045Snd (u_longlong_t)value); 268299653d4eSeschrock path = buf; 268399653d4eSeschrock } 2684c67d9675Seschrock } 2685c67d9675Seschrock 268699653d4eSeschrock return (zfs_strdup(hdl, path)); 2687c67d9675Seschrock } 2688ea8dc4b6Seschrock 2689ea8dc4b6Seschrock static int 2690ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 2691ea8dc4b6Seschrock { 2692ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 2693ea8dc4b6Seschrock } 2694ea8dc4b6Seschrock 2695ea8dc4b6Seschrock /* 2696ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 2697ea8dc4b6Seschrock * caller. 2698ea8dc4b6Seschrock */ 2699ea8dc4b6Seschrock int 270055434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 2701ea8dc4b6Seschrock { 2702ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2703ea8dc4b6Seschrock uint64_t count; 2704e9dbad6fSeschrock zbookmark_t *zb = NULL; 270555434c77Sek int i; 2706ea8dc4b6Seschrock 2707ea8dc4b6Seschrock /* 2708ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 2709ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 2710ea8dc4b6Seschrock * entire list. 2711ea8dc4b6Seschrock */ 2712ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 2713ea8dc4b6Seschrock &count) == 0); 271475519f38Sek if (count == 0) 271575519f38Sek return (0); 2716e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 27175ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 271899653d4eSeschrock return (-1); 2719e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 2720ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2721ea8dc4b6Seschrock for (;;) { 272299653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 272399653d4eSeschrock &zc) != 0) { 2724e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 2725ea8dc4b6Seschrock if (errno == ENOMEM) { 2726bf561db0Svb count = zc.zc_nvlist_dst_size; 2727e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 2728bf561db0Svb zfs_alloc(zhp->zpool_hdl, count * 2729bf561db0Svb sizeof (zbookmark_t))) == (uintptr_t)NULL) 273099653d4eSeschrock return (-1); 2731ea8dc4b6Seschrock } else { 2732ea8dc4b6Seschrock return (-1); 2733ea8dc4b6Seschrock } 2734ea8dc4b6Seschrock } else { 2735ea8dc4b6Seschrock break; 2736ea8dc4b6Seschrock } 2737ea8dc4b6Seschrock } 2738ea8dc4b6Seschrock 2739ea8dc4b6Seschrock /* 2740ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 2741ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 2742e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 2743ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 2744ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 2745ea8dc4b6Seschrock */ 2746e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 2747e9dbad6fSeschrock zc.zc_nvlist_dst_size; 2748e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 2749ea8dc4b6Seschrock 2750ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 2751ea8dc4b6Seschrock 275255434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 2753ea8dc4b6Seschrock 2754ea8dc4b6Seschrock /* 275555434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 2756ea8dc4b6Seschrock */ 2757ea8dc4b6Seschrock for (i = 0; i < count; i++) { 2758ea8dc4b6Seschrock nvlist_t *nv; 2759ea8dc4b6Seschrock 2760c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 2761c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 2762c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 2763ea8dc4b6Seschrock continue; 2764ea8dc4b6Seschrock 276555434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 276655434c77Sek goto nomem; 276755434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 276855434c77Sek zb[i].zb_objset) != 0) { 276955434c77Sek nvlist_free(nv); 277099653d4eSeschrock goto nomem; 2771ea8dc4b6Seschrock } 277255434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 277355434c77Sek zb[i].zb_object) != 0) { 277455434c77Sek nvlist_free(nv); 277555434c77Sek goto nomem; 277655434c77Sek } 277755434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 277855434c77Sek nvlist_free(nv); 277955434c77Sek goto nomem; 278055434c77Sek } 278155434c77Sek nvlist_free(nv); 2782ea8dc4b6Seschrock } 2783ea8dc4b6Seschrock 27843ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 2785ea8dc4b6Seschrock return (0); 278699653d4eSeschrock 278799653d4eSeschrock nomem: 2788e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 278999653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 2790ea8dc4b6Seschrock } 2791eaca9bbdSeschrock 2792eaca9bbdSeschrock /* 2793eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 2794eaca9bbdSeschrock */ 2795eaca9bbdSeschrock int 2796990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 2797eaca9bbdSeschrock { 2798eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 279999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2800eaca9bbdSeschrock 2801eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2802990b4856Slling zc.zc_cookie = new_version; 2803990b4856Slling 2804ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 2805ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 280699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 280799653d4eSeschrock zhp->zpool_name)); 2808eaca9bbdSeschrock return (0); 2809eaca9bbdSeschrock } 281006eeb2adSek 281106eeb2adSek void 28122a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv, 28132a6b87f0Sek char *history_str) 281406eeb2adSek { 281506eeb2adSek int i; 281606eeb2adSek 28172a6b87f0Sek (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 28182a6b87f0Sek for (i = 1; i < argc; i++) { 28192a6b87f0Sek if (strlen(history_str) + 1 + strlen(argv[i]) > 28202a6b87f0Sek HIS_MAX_RECORD_LEN) 28212a6b87f0Sek break; 28222a6b87f0Sek (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 28232a6b87f0Sek (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 28242a6b87f0Sek } 28252a6b87f0Sek } 28262a6b87f0Sek 28272a6b87f0Sek /* 28282a6b87f0Sek * Stage command history for logging. 28292a6b87f0Sek */ 28302a6b87f0Sek int 28312a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 28322a6b87f0Sek { 28332a6b87f0Sek if (history_str == NULL) 28342a6b87f0Sek return (EINVAL); 28352a6b87f0Sek 28362a6b87f0Sek if (strlen(history_str) > HIS_MAX_RECORD_LEN) 28372a6b87f0Sek return (EINVAL); 28382a6b87f0Sek 2839228975ccSek if (hdl->libzfs_log_str != NULL) 2840ecd6cf80Smarks free(hdl->libzfs_log_str); 284106eeb2adSek 28422a6b87f0Sek if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 28432a6b87f0Sek return (no_memory(hdl)); 284406eeb2adSek 28452a6b87f0Sek return (0); 284606eeb2adSek } 284706eeb2adSek 284806eeb2adSek /* 284906eeb2adSek * Perform ioctl to get some command history of a pool. 285006eeb2adSek * 285106eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 285206eeb2adSek * logical offset of the history buffer to start reading from. 285306eeb2adSek * 285406eeb2adSek * Upon return, 'off' is the next logical offset to read from and 285506eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 285606eeb2adSek */ 285706eeb2adSek static int 285806eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 285906eeb2adSek { 286006eeb2adSek zfs_cmd_t zc = { 0 }; 286106eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 286206eeb2adSek 286306eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 286406eeb2adSek 286506eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 286606eeb2adSek zc.zc_history_len = *len; 286706eeb2adSek zc.zc_history_offset = *off; 286806eeb2adSek 286906eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 287006eeb2adSek switch (errno) { 287106eeb2adSek case EPERM: 2872ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 2873ece3d9b3Slling dgettext(TEXT_DOMAIN, 287406eeb2adSek "cannot show history for pool '%s'"), 287506eeb2adSek zhp->zpool_name)); 287606eeb2adSek case ENOENT: 2877ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 287806eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 287906eeb2adSek "'%s'"), zhp->zpool_name)); 2880d7306b64Sek case ENOTSUP: 2881d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 2882d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 2883d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 288406eeb2adSek default: 2885ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 288606eeb2adSek dgettext(TEXT_DOMAIN, 288706eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 288806eeb2adSek } 288906eeb2adSek } 289006eeb2adSek 289106eeb2adSek *len = zc.zc_history_len; 289206eeb2adSek *off = zc.zc_history_offset; 289306eeb2adSek 289406eeb2adSek return (0); 289506eeb2adSek } 289606eeb2adSek 289706eeb2adSek /* 289806eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 289906eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 290006eeb2adSek * processed as there wasn't a complete record. 290106eeb2adSek */ 290206eeb2adSek static int 290306eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 290406eeb2adSek nvlist_t ***records, uint_t *numrecords) 290506eeb2adSek { 290606eeb2adSek uint64_t reclen; 290706eeb2adSek nvlist_t *nv; 290806eeb2adSek int i; 290906eeb2adSek 291006eeb2adSek while (bytes_read > sizeof (reclen)) { 291106eeb2adSek 291206eeb2adSek /* get length of packed record (stored as little endian) */ 291306eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 291406eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 291506eeb2adSek 291606eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 291706eeb2adSek break; 291806eeb2adSek 291906eeb2adSek /* unpack record */ 292006eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 292106eeb2adSek return (ENOMEM); 292206eeb2adSek bytes_read -= sizeof (reclen) + reclen; 292306eeb2adSek buf += sizeof (reclen) + reclen; 292406eeb2adSek 292506eeb2adSek /* add record to nvlist array */ 292606eeb2adSek (*numrecords)++; 292706eeb2adSek if (ISP2(*numrecords + 1)) { 292806eeb2adSek *records = realloc(*records, 292906eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 293006eeb2adSek } 293106eeb2adSek (*records)[*numrecords - 1] = nv; 293206eeb2adSek } 293306eeb2adSek 293406eeb2adSek *leftover = bytes_read; 293506eeb2adSek return (0); 293606eeb2adSek } 293706eeb2adSek 293806eeb2adSek #define HIS_BUF_LEN (128*1024) 293906eeb2adSek 294006eeb2adSek /* 294106eeb2adSek * Retrieve the command history of a pool. 294206eeb2adSek */ 294306eeb2adSek int 294406eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 294506eeb2adSek { 294606eeb2adSek char buf[HIS_BUF_LEN]; 294706eeb2adSek uint64_t off = 0; 294806eeb2adSek nvlist_t **records = NULL; 294906eeb2adSek uint_t numrecords = 0; 295006eeb2adSek int err, i; 295106eeb2adSek 295206eeb2adSek do { 295306eeb2adSek uint64_t bytes_read = sizeof (buf); 295406eeb2adSek uint64_t leftover; 295506eeb2adSek 295606eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 295706eeb2adSek break; 295806eeb2adSek 295906eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 296006eeb2adSek if (!bytes_read) 296106eeb2adSek break; 296206eeb2adSek 296306eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 296406eeb2adSek &leftover, &records, &numrecords)) != 0) 296506eeb2adSek break; 296606eeb2adSek off -= leftover; 296706eeb2adSek 296806eeb2adSek /* CONSTCOND */ 296906eeb2adSek } while (1); 297006eeb2adSek 297106eeb2adSek if (!err) { 297206eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 297306eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 297406eeb2adSek records, numrecords) == 0); 297506eeb2adSek } 297606eeb2adSek for (i = 0; i < numrecords; i++) 297706eeb2adSek nvlist_free(records[i]); 297806eeb2adSek free(records); 297906eeb2adSek 298006eeb2adSek return (err); 298106eeb2adSek } 298255434c77Sek 298355434c77Sek void 298455434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 298555434c77Sek char *pathname, size_t len) 298655434c77Sek { 298755434c77Sek zfs_cmd_t zc = { 0 }; 298855434c77Sek boolean_t mounted = B_FALSE; 298955434c77Sek char *mntpnt = NULL; 299055434c77Sek char dsname[MAXNAMELEN]; 299155434c77Sek 299255434c77Sek if (dsobj == 0) { 299355434c77Sek /* special case for the MOS */ 299455434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 299555434c77Sek return; 299655434c77Sek } 299755434c77Sek 299855434c77Sek /* get the dataset's name */ 299955434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 300055434c77Sek zc.zc_obj = dsobj; 300155434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 300255434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 300355434c77Sek /* just write out a path of two object numbers */ 300455434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 300555434c77Sek dsobj, obj); 300655434c77Sek return; 300755434c77Sek } 300855434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 300955434c77Sek 301055434c77Sek /* find out if the dataset is mounted */ 301155434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 301255434c77Sek 301355434c77Sek /* get the corrupted object's path */ 301455434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 301555434c77Sek zc.zc_obj = obj; 301655434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 301755434c77Sek &zc) == 0) { 301855434c77Sek if (mounted) { 301955434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 302055434c77Sek zc.zc_value); 302155434c77Sek } else { 302255434c77Sek (void) snprintf(pathname, len, "%s:%s", 302355434c77Sek dsname, zc.zc_value); 302455434c77Sek } 302555434c77Sek } else { 302655434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 302755434c77Sek } 302855434c77Sek free(mntpnt); 302955434c77Sek } 3030b1b8ab34Slling 303115e6edf1Sgw /* 303215e6edf1Sgw * Read the EFI label from the config, if a label does not exist then 303315e6edf1Sgw * pass back the error to the caller. If the caller has passed a non-NULL 303415e6edf1Sgw * diskaddr argument then we set it to the starting address of the EFI 303515e6edf1Sgw * partition. 303615e6edf1Sgw */ 303715e6edf1Sgw static int 303815e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb) 303915e6edf1Sgw { 304015e6edf1Sgw char *path; 304115e6edf1Sgw int fd; 304215e6edf1Sgw char diskname[MAXPATHLEN]; 304315e6edf1Sgw int err = -1; 304415e6edf1Sgw 304515e6edf1Sgw if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 304615e6edf1Sgw return (err); 304715e6edf1Sgw 304815e6edf1Sgw (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 304915e6edf1Sgw strrchr(path, '/')); 305015e6edf1Sgw if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 305115e6edf1Sgw struct dk_gpt *vtoc; 305215e6edf1Sgw 305315e6edf1Sgw if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 305415e6edf1Sgw if (sb != NULL) 305515e6edf1Sgw *sb = vtoc->efi_parts[0].p_start; 305615e6edf1Sgw efi_free(vtoc); 305715e6edf1Sgw } 305815e6edf1Sgw (void) close(fd); 305915e6edf1Sgw } 306015e6edf1Sgw return (err); 306115e6edf1Sgw } 306215e6edf1Sgw 30638488aeb5Staylor /* 30648488aeb5Staylor * determine where a partition starts on a disk in the current 30658488aeb5Staylor * configuration 30668488aeb5Staylor */ 30678488aeb5Staylor static diskaddr_t 30688488aeb5Staylor find_start_block(nvlist_t *config) 30698488aeb5Staylor { 30708488aeb5Staylor nvlist_t **child; 30718488aeb5Staylor uint_t c, children; 30728488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 30738488aeb5Staylor uint64_t wholedisk; 30748488aeb5Staylor 30758488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 30768488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 30778488aeb5Staylor if (nvlist_lookup_uint64(config, 30788488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 30798488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 30808488aeb5Staylor return (MAXOFFSET_T); 30818488aeb5Staylor } 308215e6edf1Sgw if (read_efi_label(config, &sb) < 0) 308315e6edf1Sgw sb = MAXOFFSET_T; 30848488aeb5Staylor return (sb); 30858488aeb5Staylor } 30868488aeb5Staylor 30878488aeb5Staylor for (c = 0; c < children; c++) { 30888488aeb5Staylor sb = find_start_block(child[c]); 30898488aeb5Staylor if (sb != MAXOFFSET_T) { 30908488aeb5Staylor return (sb); 30918488aeb5Staylor } 30928488aeb5Staylor } 30938488aeb5Staylor return (MAXOFFSET_T); 30948488aeb5Staylor } 30958488aeb5Staylor 30968488aeb5Staylor /* 30978488aeb5Staylor * Label an individual disk. The name provided is the short name, 30988488aeb5Staylor * stripped of any leading /dev path. 30998488aeb5Staylor */ 31008488aeb5Staylor int 31018488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 31028488aeb5Staylor { 31038488aeb5Staylor char path[MAXPATHLEN]; 31048488aeb5Staylor struct dk_gpt *vtoc; 31058488aeb5Staylor int fd; 31068488aeb5Staylor size_t resv = EFI_MIN_RESV_SIZE; 31078488aeb5Staylor uint64_t slice_size; 31088488aeb5Staylor diskaddr_t start_block; 31098488aeb5Staylor char errbuf[1024]; 31108488aeb5Staylor 3111c6ef114fSmmusante /* prepare an error message just in case */ 3112c6ef114fSmmusante (void) snprintf(errbuf, sizeof (errbuf), 3113c6ef114fSmmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 3114c6ef114fSmmusante 31158488aeb5Staylor if (zhp) { 31168488aeb5Staylor nvlist_t *nvroot; 31178488aeb5Staylor 3118b5b76fecSGeorge Wilson if (pool_is_bootable(zhp)) { 3119b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3120b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root " 3121b5b76fecSGeorge Wilson "pools.")); 3122b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 3123b5b76fecSGeorge Wilson } 3124b5b76fecSGeorge Wilson 31258488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 31268488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 31278488aeb5Staylor 31288488aeb5Staylor if (zhp->zpool_start_block == 0) 31298488aeb5Staylor start_block = find_start_block(nvroot); 31308488aeb5Staylor else 31318488aeb5Staylor start_block = zhp->zpool_start_block; 31328488aeb5Staylor zhp->zpool_start_block = start_block; 31338488aeb5Staylor } else { 31348488aeb5Staylor /* new pool */ 31358488aeb5Staylor start_block = NEW_START_BLOCK; 31368488aeb5Staylor } 31378488aeb5Staylor 31388488aeb5Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 31398488aeb5Staylor BACKUP_SLICE); 31408488aeb5Staylor 31418488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 31428488aeb5Staylor /* 31438488aeb5Staylor * This shouldn't happen. We've long since verified that this 31448488aeb5Staylor * is a valid device. 31458488aeb5Staylor */ 3146c6ef114fSmmusante zfs_error_aux(hdl, 3147c6ef114fSmmusante dgettext(TEXT_DOMAIN, "unable to open device")); 31488488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 31498488aeb5Staylor } 31508488aeb5Staylor 31518488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 31528488aeb5Staylor /* 31538488aeb5Staylor * The only way this can fail is if we run out of memory, or we 31548488aeb5Staylor * were unable to read the disk's capacity 31558488aeb5Staylor */ 31568488aeb5Staylor if (errno == ENOMEM) 31578488aeb5Staylor (void) no_memory(hdl); 31588488aeb5Staylor 31598488aeb5Staylor (void) close(fd); 3160c6ef114fSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3161c6ef114fSmmusante "unable to read disk capacity"), name); 31628488aeb5Staylor 31638488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 31648488aeb5Staylor } 31658488aeb5Staylor 31668488aeb5Staylor slice_size = vtoc->efi_last_u_lba + 1; 31678488aeb5Staylor slice_size -= EFI_MIN_RESV_SIZE; 31688488aeb5Staylor if (start_block == MAXOFFSET_T) 31698488aeb5Staylor start_block = NEW_START_BLOCK; 31708488aeb5Staylor slice_size -= start_block; 31718488aeb5Staylor 31728488aeb5Staylor vtoc->efi_parts[0].p_start = start_block; 31738488aeb5Staylor vtoc->efi_parts[0].p_size = slice_size; 31748488aeb5Staylor 31758488aeb5Staylor /* 31768488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 31778488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 31788488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 31798488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 31808488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 31818488aeb5Staylor * can get, in the absence of V_OTHER. 31828488aeb5Staylor */ 31838488aeb5Staylor vtoc->efi_parts[0].p_tag = V_USR; 31848488aeb5Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 31858488aeb5Staylor 31868488aeb5Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 31878488aeb5Staylor vtoc->efi_parts[8].p_size = resv; 31888488aeb5Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 31898488aeb5Staylor 31908488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 31918488aeb5Staylor /* 31928488aeb5Staylor * Some block drivers (like pcata) may not support EFI 31938488aeb5Staylor * GPT labels. Print out a helpful error message dir- 31948488aeb5Staylor * ecting the user to manually label the disk and give 31958488aeb5Staylor * a specific slice. 31968488aeb5Staylor */ 31978488aeb5Staylor (void) close(fd); 31988488aeb5Staylor efi_free(vtoc); 31998488aeb5Staylor 32008488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3201c6ef114fSmmusante "try using fdisk(1M) and then provide a specific slice")); 32028488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 32038488aeb5Staylor } 32048488aeb5Staylor 32058488aeb5Staylor (void) close(fd); 32068488aeb5Staylor efi_free(vtoc); 32078488aeb5Staylor return (0); 32088488aeb5Staylor } 3209e7cbe64fSgw 3210e7cbe64fSgw static boolean_t 3211e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 3212e7cbe64fSgw { 3213e7cbe64fSgw char *type; 3214e7cbe64fSgw nvlist_t **child; 3215e7cbe64fSgw uint_t children, c; 3216e7cbe64fSgw 3217e7cbe64fSgw verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 3218e7cbe64fSgw if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 3219e7cbe64fSgw strcmp(type, VDEV_TYPE_FILE) == 0 || 3220e7cbe64fSgw strcmp(type, VDEV_TYPE_LOG) == 0 || 3221e7cbe64fSgw strcmp(type, VDEV_TYPE_MISSING) == 0) { 3222e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3223e7cbe64fSgw "vdev type '%s' is not supported"), type); 3224e7cbe64fSgw (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 3225e7cbe64fSgw return (B_FALSE); 3226e7cbe64fSgw } 3227e7cbe64fSgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3228e7cbe64fSgw &child, &children) == 0) { 3229e7cbe64fSgw for (c = 0; c < children; c++) { 3230e7cbe64fSgw if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 3231e7cbe64fSgw return (B_FALSE); 3232e7cbe64fSgw } 3233e7cbe64fSgw } 3234e7cbe64fSgw return (B_TRUE); 3235e7cbe64fSgw } 3236e7cbe64fSgw 3237e7cbe64fSgw /* 3238e7cbe64fSgw * check if this zvol is allowable for use as a dump device; zero if 3239e7cbe64fSgw * it is, > 0 if it isn't, < 0 if it isn't a zvol 3240e7cbe64fSgw */ 3241e7cbe64fSgw int 3242e7cbe64fSgw zvol_check_dump_config(char *arg) 3243e7cbe64fSgw { 3244e7cbe64fSgw zpool_handle_t *zhp = NULL; 3245e7cbe64fSgw nvlist_t *config, *nvroot; 3246e7cbe64fSgw char *p, *volname; 3247e7cbe64fSgw nvlist_t **top; 3248e7cbe64fSgw uint_t toplevels; 3249e7cbe64fSgw libzfs_handle_t *hdl; 3250e7cbe64fSgw char errbuf[1024]; 3251e7cbe64fSgw char poolname[ZPOOL_MAXNAMELEN]; 3252e7cbe64fSgw int pathlen = strlen(ZVOL_FULL_DEV_DIR); 3253e7cbe64fSgw int ret = 1; 3254e7cbe64fSgw 3255e7cbe64fSgw if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 3256e7cbe64fSgw return (-1); 3257e7cbe64fSgw } 3258e7cbe64fSgw 3259e7cbe64fSgw (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3260e7cbe64fSgw "dump is not supported on device '%s'"), arg); 3261e7cbe64fSgw 3262e7cbe64fSgw if ((hdl = libzfs_init()) == NULL) 3263e7cbe64fSgw return (1); 3264e7cbe64fSgw libzfs_print_on_error(hdl, B_TRUE); 3265e7cbe64fSgw 3266e7cbe64fSgw volname = arg + pathlen; 3267e7cbe64fSgw 3268e7cbe64fSgw /* check the configuration of the pool */ 3269e7cbe64fSgw if ((p = strchr(volname, '/')) == NULL) { 3270e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3271e7cbe64fSgw "malformed dataset name")); 3272e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 3273e7cbe64fSgw return (1); 3274e7cbe64fSgw } else if (p - volname >= ZFS_MAXNAMELEN) { 3275e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3276e7cbe64fSgw "dataset name is too long")); 3277e7cbe64fSgw (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 3278e7cbe64fSgw return (1); 3279e7cbe64fSgw } else { 3280e7cbe64fSgw (void) strncpy(poolname, volname, p - volname); 3281e7cbe64fSgw poolname[p - volname] = '\0'; 3282e7cbe64fSgw } 3283e7cbe64fSgw 3284e7cbe64fSgw if ((zhp = zpool_open(hdl, poolname)) == NULL) { 3285e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3286e7cbe64fSgw "could not open pool '%s'"), poolname); 3287e7cbe64fSgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 3288e7cbe64fSgw goto out; 3289e7cbe64fSgw } 3290e7cbe64fSgw config = zpool_get_config(zhp, NULL); 3291e7cbe64fSgw if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3292e7cbe64fSgw &nvroot) != 0) { 3293e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3294e7cbe64fSgw "could not obtain vdev configuration for '%s'"), poolname); 3295e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 3296e7cbe64fSgw goto out; 3297e7cbe64fSgw } 3298e7cbe64fSgw 3299e7cbe64fSgw verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 3300e7cbe64fSgw &top, &toplevels) == 0); 3301e7cbe64fSgw if (toplevels != 1) { 3302e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3303e7cbe64fSgw "'%s' has multiple top level vdevs"), poolname); 3304e7cbe64fSgw (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 3305e7cbe64fSgw goto out; 3306e7cbe64fSgw } 3307e7cbe64fSgw 3308e7cbe64fSgw if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 3309e7cbe64fSgw goto out; 3310e7cbe64fSgw } 3311e7cbe64fSgw ret = 0; 3312e7cbe64fSgw 3313e7cbe64fSgw out: 3314e7cbe64fSgw if (zhp) 3315e7cbe64fSgw zpool_close(zhp); 3316e7cbe64fSgw libzfs_fini(hdl); 3317e7cbe64fSgw return (ret); 3318e7cbe64fSgw } 3319