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 /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24e9103aaeSGarrett D'Amore * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25*7a09f97bSGeorge Wilson * Copyright (c) 2011, 2014 by Delphix. All rights reserved. 26810e43b2SBill Pijewski * Copyright (c) 2013, Joyent, Inc. All rights reserved. 27fa9e4066Sahrens */ 28fa9e4066Sahrens 29fa9e4066Sahrens #include <ctype.h> 30fa9e4066Sahrens #include <errno.h> 31fa9e4066Sahrens #include <devid.h> 32fa9e4066Sahrens #include <fcntl.h> 33fa9e4066Sahrens #include <libintl.h> 34fa9e4066Sahrens #include <stdio.h> 35fa9e4066Sahrens #include <stdlib.h> 36f3861e1aSahl #include <strings.h> 37fa9e4066Sahrens #include <unistd.h> 384445fffbSMatthew Ahrens #include <libgen.h> 398488aeb5Staylor #include <sys/efi_partition.h> 408488aeb5Staylor #include <sys/vtoc.h> 41fa9e4066Sahrens #include <sys/zfs_ioctl.h> 42573ca77eSGeorge Wilson #include <dlfcn.h> 43fa9e4066Sahrens 44fa9e4066Sahrens #include "zfs_namecheck.h" 45b1b8ab34Slling #include "zfs_prop.h" 46fa9e4066Sahrens #include "libzfs_impl.h" 47468c413aSTim Haley #include "zfs_comutil.h" 48ad135b5dSChristopher Siden #include "zfeature_common.h" 49fa9e4066Sahrens 5015e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 51990b4856Slling 52573ca77eSGeorge Wilson #define DISK_ROOT "/dev/dsk" 53573ca77eSGeorge Wilson #define RDISK_ROOT "/dev/rdsk" 54573ca77eSGeorge Wilson #define BACKUP_SLICE "s2" 55573ca77eSGeorge Wilson 56f9af39baSGeorge Wilson typedef struct prop_flags { 57f9af39baSGeorge Wilson int create:1; /* Validate property on creation */ 58f9af39baSGeorge Wilson int import:1; /* Validate property on import */ 59f9af39baSGeorge Wilson } prop_flags_t; 60f9af39baSGeorge Wilson 61990b4856Slling /* 62990b4856Slling * ==================================================================== 63990b4856Slling * zpool property functions 64990b4856Slling * ==================================================================== 65990b4856Slling */ 66990b4856Slling 67990b4856Slling static int 68990b4856Slling zpool_get_all_props(zpool_handle_t *zhp) 69990b4856Slling { 70990b4856Slling zfs_cmd_t zc = { 0 }; 71990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 72990b4856Slling 73990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 74990b4856Slling 75990b4856Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 76990b4856Slling return (-1); 77990b4856Slling 78990b4856Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 79990b4856Slling if (errno == ENOMEM) { 80990b4856Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 81990b4856Slling zcmd_free_nvlists(&zc); 82990b4856Slling return (-1); 83990b4856Slling } 84990b4856Slling } else { 85990b4856Slling zcmd_free_nvlists(&zc); 86990b4856Slling return (-1); 87990b4856Slling } 88990b4856Slling } 89990b4856Slling 90990b4856Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 91990b4856Slling zcmd_free_nvlists(&zc); 92990b4856Slling return (-1); 93990b4856Slling } 94990b4856Slling 95990b4856Slling zcmd_free_nvlists(&zc); 96990b4856Slling 97990b4856Slling return (0); 98990b4856Slling } 99990b4856Slling 100990b4856Slling static int 101990b4856Slling zpool_props_refresh(zpool_handle_t *zhp) 102990b4856Slling { 103990b4856Slling nvlist_t *old_props; 104990b4856Slling 105990b4856Slling old_props = zhp->zpool_props; 106990b4856Slling 107990b4856Slling if (zpool_get_all_props(zhp) != 0) 108990b4856Slling return (-1); 109990b4856Slling 110990b4856Slling nvlist_free(old_props); 111990b4856Slling return (0); 112990b4856Slling } 113990b4856Slling 114990b4856Slling static char * 115990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 116990b4856Slling zprop_source_t *src) 117990b4856Slling { 118990b4856Slling nvlist_t *nv, *nvl; 119990b4856Slling uint64_t ival; 120990b4856Slling char *value; 121990b4856Slling zprop_source_t source; 122990b4856Slling 123990b4856Slling nvl = zhp->zpool_props; 124990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 125990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 126990b4856Slling source = ival; 127990b4856Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 128990b4856Slling } else { 129990b4856Slling source = ZPROP_SRC_DEFAULT; 130990b4856Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 131990b4856Slling value = "-"; 132990b4856Slling } 133990b4856Slling 134990b4856Slling if (src) 135990b4856Slling *src = source; 136990b4856Slling 137990b4856Slling return (value); 138990b4856Slling } 139990b4856Slling 140990b4856Slling uint64_t 141990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 142990b4856Slling { 143990b4856Slling nvlist_t *nv, *nvl; 144990b4856Slling uint64_t value; 145990b4856Slling zprop_source_t source; 146990b4856Slling 147b87f3af3Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 148b87f3af3Sperrin /* 149b87f3af3Sperrin * zpool_get_all_props() has most likely failed because 150b87f3af3Sperrin * the pool is faulted, but if all we need is the top level 151b87f3af3Sperrin * vdev's guid then get it from the zhp config nvlist. 152b87f3af3Sperrin */ 153b87f3af3Sperrin if ((prop == ZPOOL_PROP_GUID) && 154b87f3af3Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 155b87f3af3Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 156b87f3af3Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 157b87f3af3Sperrin == 0)) { 158b87f3af3Sperrin return (value); 159b87f3af3Sperrin } 160990b4856Slling return (zpool_prop_default_numeric(prop)); 161b87f3af3Sperrin } 162990b4856Slling 163990b4856Slling nvl = zhp->zpool_props; 164990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 165990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 166990b4856Slling source = value; 167990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 168990b4856Slling } else { 169990b4856Slling source = ZPROP_SRC_DEFAULT; 170990b4856Slling value = zpool_prop_default_numeric(prop); 171990b4856Slling } 172990b4856Slling 173990b4856Slling if (src) 174990b4856Slling *src = source; 175990b4856Slling 176990b4856Slling return (value); 177990b4856Slling } 178990b4856Slling 179990b4856Slling /* 180990b4856Slling * Map VDEV STATE to printed strings. 181990b4856Slling */ 182990b4856Slling char * 183990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 184990b4856Slling { 185990b4856Slling switch (state) { 186990b4856Slling case VDEV_STATE_CLOSED: 187990b4856Slling case VDEV_STATE_OFFLINE: 188990b4856Slling return (gettext("OFFLINE")); 189990b4856Slling case VDEV_STATE_REMOVED: 190990b4856Slling return (gettext("REMOVED")); 191990b4856Slling case VDEV_STATE_CANT_OPEN: 192b87f3af3Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 193990b4856Slling return (gettext("FAULTED")); 1941195e687SMark J Musante else if (aux == VDEV_AUX_SPLIT_POOL) 1951195e687SMark J Musante return (gettext("SPLIT")); 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, 215c58b3526SAdam Stevko zprop_source_t *srctype, boolean_t literal) 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: 2418704186eSDan McDonald case ZPOOL_PROP_COMMENT: 242379c004dSEric Schrock if (zhp->zpool_props != NULL || 243379c004dSEric Schrock zpool_get_all_props(zhp) == 0) { 244379c004dSEric Schrock (void) strlcpy(buf, 245379c004dSEric Schrock zpool_get_prop_string(zhp, prop, &src), 246379c004dSEric Schrock len); 247c58b3526SAdam Stevko break; 248379c004dSEric Schrock } 249379c004dSEric Schrock /* FALLTHROUGH */ 250379c004dSEric Schrock default: 251990b4856Slling (void) strlcpy(buf, "-", len); 252379c004dSEric Schrock break; 253379c004dSEric Schrock } 254379c004dSEric Schrock 255379c004dSEric Schrock if (srctype != NULL) 256379c004dSEric Schrock *srctype = src; 257990b4856Slling return (0); 258990b4856Slling } 259990b4856Slling 260990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 261990b4856Slling prop != ZPOOL_PROP_NAME) 262990b4856Slling return (-1); 263990b4856Slling 264990b4856Slling switch (zpool_prop_get_type(prop)) { 265990b4856Slling case PROP_TYPE_STRING: 266990b4856Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 267990b4856Slling len); 268990b4856Slling break; 269990b4856Slling 270990b4856Slling case PROP_TYPE_NUMBER: 271990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 272990b4856Slling 273990b4856Slling switch (prop) { 274990b4856Slling case ZPOOL_PROP_SIZE: 275485bbbf5SGeorge Wilson case ZPOOL_PROP_ALLOCATED: 276485bbbf5SGeorge Wilson case ZPOOL_PROP_FREE: 277ad135b5dSChristopher Siden case ZPOOL_PROP_FREEING: 2787fd05ac4SMatthew Ahrens case ZPOOL_PROP_LEAKED: 279c58b3526SAdam Stevko if (literal) { 280c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu", 281c58b3526SAdam Stevko (u_longlong_t)intval); 282c58b3526SAdam Stevko } else { 283c58b3526SAdam Stevko (void) zfs_nicenum(intval, buf, len); 284c58b3526SAdam Stevko } 285990b4856Slling break; 286*7a09f97bSGeorge Wilson case ZPOOL_PROP_EXPANDSZ: 287*7a09f97bSGeorge Wilson if (intval == 0) { 288*7a09f97bSGeorge Wilson (void) strlcpy(buf, "-", len); 289*7a09f97bSGeorge Wilson } else if (literal) { 290*7a09f97bSGeorge Wilson (void) snprintf(buf, len, "%llu", 291*7a09f97bSGeorge Wilson (u_longlong_t)intval); 292*7a09f97bSGeorge Wilson } else { 293*7a09f97bSGeorge Wilson (void) zfs_nicenum(intval, buf, len); 294*7a09f97bSGeorge Wilson } 295*7a09f97bSGeorge Wilson break; 296990b4856Slling case ZPOOL_PROP_CAPACITY: 297c58b3526SAdam Stevko if (literal) { 298c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu", 299c58b3526SAdam Stevko (u_longlong_t)intval); 300c58b3526SAdam Stevko } else { 301c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu%%", 302c58b3526SAdam Stevko (u_longlong_t)intval); 303c58b3526SAdam Stevko } 304990b4856Slling break; 3052e4c9986SGeorge Wilson case ZPOOL_PROP_FRAGMENTATION: 3062e4c9986SGeorge Wilson if (intval == UINT64_MAX) { 3072e4c9986SGeorge Wilson (void) strlcpy(buf, "-", len); 3082e4c9986SGeorge Wilson } else { 3092e4c9986SGeorge Wilson (void) snprintf(buf, len, "%llu%%", 3102e4c9986SGeorge Wilson (u_longlong_t)intval); 3112e4c9986SGeorge Wilson } 3122e4c9986SGeorge Wilson break; 313b24ab676SJeff Bonwick case ZPOOL_PROP_DEDUPRATIO: 314b24ab676SJeff Bonwick (void) snprintf(buf, len, "%llu.%02llux", 315b24ab676SJeff Bonwick (u_longlong_t)(intval / 100), 316b24ab676SJeff Bonwick (u_longlong_t)(intval % 100)); 317b24ab676SJeff Bonwick break; 318990b4856Slling case ZPOOL_PROP_HEALTH: 319990b4856Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 320990b4856Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 321990b4856Slling verify(nvlist_lookup_uint64_array(nvroot, 3223f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) 3233f9d6ad7SLin Ling == 0); 324990b4856Slling 325990b4856Slling (void) strlcpy(buf, zpool_state_to_name(intval, 326990b4856Slling vs->vs_aux), len); 327990b4856Slling break; 328ad135b5dSChristopher Siden case ZPOOL_PROP_VERSION: 329ad135b5dSChristopher Siden if (intval >= SPA_VERSION_FEATURES) { 330ad135b5dSChristopher Siden (void) snprintf(buf, len, "-"); 331ad135b5dSChristopher Siden break; 332ad135b5dSChristopher Siden } 333ad135b5dSChristopher Siden /* FALLTHROUGH */ 334990b4856Slling default: 335990b4856Slling (void) snprintf(buf, len, "%llu", intval); 336990b4856Slling } 337990b4856Slling break; 338990b4856Slling 339990b4856Slling case PROP_TYPE_INDEX: 340990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 341990b4856Slling if (zpool_prop_index_to_string(prop, intval, &strval) 342990b4856Slling != 0) 343990b4856Slling return (-1); 344990b4856Slling (void) strlcpy(buf, strval, len); 345990b4856Slling break; 346990b4856Slling 347990b4856Slling default: 348990b4856Slling abort(); 349990b4856Slling } 350990b4856Slling 351990b4856Slling if (srctype) 352990b4856Slling *srctype = src; 353990b4856Slling 354990b4856Slling return (0); 355990b4856Slling } 356990b4856Slling 357990b4856Slling /* 358990b4856Slling * Check if the bootfs name has the same pool name as it is set to. 359990b4856Slling * Assuming bootfs is a valid dataset name. 360990b4856Slling */ 361990b4856Slling static boolean_t 362990b4856Slling bootfs_name_valid(const char *pool, char *bootfs) 363990b4856Slling { 364990b4856Slling int len = strlen(pool); 365990b4856Slling 366fe3e2633SEric Taylor if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 367990b4856Slling return (B_FALSE); 368990b4856Slling 369990b4856Slling if (strncmp(pool, bootfs, len) == 0 && 370990b4856Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 371990b4856Slling return (B_TRUE); 372990b4856Slling 373990b4856Slling return (B_FALSE); 374990b4856Slling } 375990b4856Slling 37615e6edf1Sgw /* 37715e6edf1Sgw * Inspect the configuration to determine if any of the devices contain 37815e6edf1Sgw * an EFI label. 37915e6edf1Sgw */ 38015e6edf1Sgw static boolean_t 38115e6edf1Sgw pool_uses_efi(nvlist_t *config) 38215e6edf1Sgw { 38315e6edf1Sgw nvlist_t **child; 38415e6edf1Sgw uint_t c, children; 38515e6edf1Sgw 38615e6edf1Sgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 38715e6edf1Sgw &child, &children) != 0) 38815e6edf1Sgw return (read_efi_label(config, NULL) >= 0); 38915e6edf1Sgw 39015e6edf1Sgw for (c = 0; c < children; c++) { 39115e6edf1Sgw if (pool_uses_efi(child[c])) 39215e6edf1Sgw return (B_TRUE); 39315e6edf1Sgw } 39415e6edf1Sgw return (B_FALSE); 39515e6edf1Sgw } 39615e6edf1Sgw 3974263d13fSGeorge Wilson boolean_t 3984263d13fSGeorge Wilson zpool_is_bootable(zpool_handle_t *zhp) 399b5b76fecSGeorge Wilson { 400b5b76fecSGeorge Wilson char bootfs[ZPOOL_MAXNAMELEN]; 401b5b76fecSGeorge Wilson 402b5b76fecSGeorge Wilson return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 403c58b3526SAdam Stevko sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-", 404b5b76fecSGeorge Wilson sizeof (bootfs)) != 0); 405b5b76fecSGeorge Wilson } 406b5b76fecSGeorge Wilson 407b5b76fecSGeorge Wilson 408990b4856Slling /* 409990b4856Slling * Given an nvlist of zpool properties to be set, validate that they are 410990b4856Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 411990b4856Slling * specified as strings. 412990b4856Slling */ 413990b4856Slling static nvlist_t * 4140a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 415f9af39baSGeorge Wilson nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf) 416990b4856Slling { 417990b4856Slling nvpair_t *elem; 418990b4856Slling nvlist_t *retprops; 419990b4856Slling zpool_prop_t prop; 420990b4856Slling char *strval; 421990b4856Slling uint64_t intval; 4228704186eSDan McDonald char *slash, *check; 4232f8aaab3Seschrock struct stat64 statbuf; 42415e6edf1Sgw zpool_handle_t *zhp; 42515e6edf1Sgw nvlist_t *nvroot; 426990b4856Slling 427990b4856Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 428990b4856Slling (void) no_memory(hdl); 429990b4856Slling return (NULL); 430990b4856Slling } 431990b4856Slling 432990b4856Slling elem = NULL; 433990b4856Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 434990b4856Slling const char *propname = nvpair_name(elem); 435990b4856Slling 436ad135b5dSChristopher Siden prop = zpool_name_to_prop(propname); 437ad135b5dSChristopher Siden if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) { 438ad135b5dSChristopher Siden int err; 439ad135b5dSChristopher Siden char *fname = strchr(propname, '@') + 1; 440ad135b5dSChristopher Siden 4412acef22dSMatthew Ahrens err = zfeature_lookup_name(fname, NULL); 442ad135b5dSChristopher Siden if (err != 0) { 443ad135b5dSChristopher Siden ASSERT3U(err, ==, ENOENT); 444ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 445ad135b5dSChristopher Siden "invalid feature '%s'"), fname); 446ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 447ad135b5dSChristopher Siden goto error; 448ad135b5dSChristopher Siden } 449ad135b5dSChristopher Siden 450ad135b5dSChristopher Siden if (nvpair_type(elem) != DATA_TYPE_STRING) { 451ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 452ad135b5dSChristopher Siden "'%s' must be a string"), propname); 453ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 454ad135b5dSChristopher Siden goto error; 455ad135b5dSChristopher Siden } 456ad135b5dSChristopher Siden 457ad135b5dSChristopher Siden (void) nvpair_value_string(elem, &strval); 458ad135b5dSChristopher Siden if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) { 459ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 460ad135b5dSChristopher Siden "property '%s' can only be set to " 461ad135b5dSChristopher Siden "'enabled'"), propname); 462ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 463ad135b5dSChristopher Siden goto error; 464ad135b5dSChristopher Siden } 465ad135b5dSChristopher Siden 466ad135b5dSChristopher Siden if (nvlist_add_uint64(retprops, propname, 0) != 0) { 467ad135b5dSChristopher Siden (void) no_memory(hdl); 468ad135b5dSChristopher Siden goto error; 469ad135b5dSChristopher Siden } 470ad135b5dSChristopher Siden continue; 471ad135b5dSChristopher Siden } 472ad135b5dSChristopher Siden 473990b4856Slling /* 474990b4856Slling * Make sure this property is valid and applies to this type. 475990b4856Slling */ 476ad135b5dSChristopher Siden if (prop == ZPROP_INVAL) { 477990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 478990b4856Slling "invalid property '%s'"), propname); 479990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 480990b4856Slling goto error; 481990b4856Slling } 482990b4856Slling 483990b4856Slling if (zpool_prop_readonly(prop)) { 484990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 485990b4856Slling "is readonly"), propname); 486990b4856Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 487990b4856Slling goto error; 488990b4856Slling } 489990b4856Slling 490990b4856Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 491990b4856Slling &strval, &intval, errbuf) != 0) 492990b4856Slling goto error; 493990b4856Slling 494990b4856Slling /* 495990b4856Slling * Perform additional checking for specific properties. 496990b4856Slling */ 497990b4856Slling switch (prop) { 498990b4856Slling case ZPOOL_PROP_VERSION: 499ad135b5dSChristopher Siden if (intval < version || 500ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(intval)) { 501990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 502990b4856Slling "property '%s' number %d is invalid."), 503990b4856Slling propname, intval); 504990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 505990b4856Slling goto error; 506990b4856Slling } 507990b4856Slling break; 508990b4856Slling 509990b4856Slling case ZPOOL_PROP_BOOTFS: 510f9af39baSGeorge Wilson if (flags.create || flags.import) { 511990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 512990b4856Slling "property '%s' cannot be set at creation " 513990b4856Slling "or import time"), propname); 514990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 515990b4856Slling goto error; 516990b4856Slling } 517990b4856Slling 518990b4856Slling if (version < SPA_VERSION_BOOTFS) { 519990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 520990b4856Slling "pool must be upgraded to support " 521990b4856Slling "'%s' property"), propname); 522990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 523990b4856Slling goto error; 524990b4856Slling } 525990b4856Slling 526990b4856Slling /* 527990b4856Slling * bootfs property value has to be a dataset name and 528990b4856Slling * the dataset has to be in the same pool as it sets to. 529990b4856Slling */ 530990b4856Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 531990b4856Slling strval)) { 532990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 533990b4856Slling "is an invalid name"), strval); 534990b4856Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 535990b4856Slling goto error; 536990b4856Slling } 53715e6edf1Sgw 53815e6edf1Sgw if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 53915e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 54015e6edf1Sgw "could not open pool '%s'"), poolname); 54115e6edf1Sgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 54215e6edf1Sgw goto error; 54315e6edf1Sgw } 54415e6edf1Sgw verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 54515e6edf1Sgw ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 54615e6edf1Sgw 54715e6edf1Sgw /* 54815e6edf1Sgw * bootfs property cannot be set on a disk which has 54915e6edf1Sgw * been EFI labeled. 55015e6edf1Sgw */ 55115e6edf1Sgw if (pool_uses_efi(nvroot)) { 55215e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 55315e6edf1Sgw "property '%s' not supported on " 55415e6edf1Sgw "EFI labeled devices"), propname); 55515e6edf1Sgw (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 55615e6edf1Sgw zpool_close(zhp); 55715e6edf1Sgw goto error; 55815e6edf1Sgw } 55915e6edf1Sgw zpool_close(zhp); 560990b4856Slling break; 561990b4856Slling 5622f8aaab3Seschrock case ZPOOL_PROP_ALTROOT: 563f9af39baSGeorge Wilson if (!flags.create && !flags.import) { 564990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 565990b4856Slling "property '%s' can only be set during pool " 566990b4856Slling "creation or import"), propname); 567990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 568990b4856Slling goto error; 569990b4856Slling } 570990b4856Slling 5712f8aaab3Seschrock if (strval[0] != '/') { 572990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5732f8aaab3Seschrock "bad alternate root '%s'"), strval); 5742f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 575990b4856Slling goto error; 576990b4856Slling } 5772f8aaab3Seschrock break; 5782f8aaab3Seschrock 5792f8aaab3Seschrock case ZPOOL_PROP_CACHEFILE: 5802f8aaab3Seschrock if (strval[0] == '\0') 5812f8aaab3Seschrock break; 5822f8aaab3Seschrock 5832f8aaab3Seschrock if (strcmp(strval, "none") == 0) 5842f8aaab3Seschrock break; 585990b4856Slling 586990b4856Slling if (strval[0] != '/') { 587990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5882f8aaab3Seschrock "property '%s' must be empty, an " 5892f8aaab3Seschrock "absolute path, or 'none'"), propname); 590990b4856Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 591990b4856Slling goto error; 592990b4856Slling } 593990b4856Slling 5942f8aaab3Seschrock slash = strrchr(strval, '/'); 595990b4856Slling 5962f8aaab3Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5972f8aaab3Seschrock strcmp(slash, "/..") == 0) { 5982f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5992f8aaab3Seschrock "'%s' is not a valid file"), strval); 6002f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 6012f8aaab3Seschrock goto error; 6022f8aaab3Seschrock } 603990b4856Slling 6042f8aaab3Seschrock *slash = '\0'; 6052f8aaab3Seschrock 6062c32020fSeschrock if (strval[0] != '\0' && 6072c32020fSeschrock (stat64(strval, &statbuf) != 0 || 6082c32020fSeschrock !S_ISDIR(statbuf.st_mode))) { 6092f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6102f8aaab3Seschrock "'%s' is not a valid directory"), 6112f8aaab3Seschrock strval); 6122f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 6132f8aaab3Seschrock goto error; 6142f8aaab3Seschrock } 6152f8aaab3Seschrock 6162f8aaab3Seschrock *slash = '/'; 6172f8aaab3Seschrock break; 618f9af39baSGeorge Wilson 6198704186eSDan McDonald case ZPOOL_PROP_COMMENT: 6208704186eSDan McDonald for (check = strval; *check != '\0'; check++) { 6218704186eSDan McDonald if (!isprint(*check)) { 6228704186eSDan McDonald zfs_error_aux(hdl, 6238704186eSDan McDonald dgettext(TEXT_DOMAIN, 6248704186eSDan McDonald "comment may only have printable " 6258704186eSDan McDonald "characters")); 6268704186eSDan McDonald (void) zfs_error(hdl, EZFS_BADPROP, 6278704186eSDan McDonald errbuf); 6288704186eSDan McDonald goto error; 6298704186eSDan McDonald } 6308704186eSDan McDonald } 6318704186eSDan McDonald if (strlen(strval) > ZPROP_MAX_COMMENT) { 6328704186eSDan McDonald zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6338704186eSDan McDonald "comment must not exceed %d characters"), 6348704186eSDan McDonald ZPROP_MAX_COMMENT); 6358704186eSDan McDonald (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 6368704186eSDan McDonald goto error; 6378704186eSDan McDonald } 6388704186eSDan McDonald break; 639f9af39baSGeorge Wilson case ZPOOL_PROP_READONLY: 640f9af39baSGeorge Wilson if (!flags.import) { 641f9af39baSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 642f9af39baSGeorge Wilson "property '%s' can only be set at " 643f9af39baSGeorge Wilson "import time"), propname); 644f9af39baSGeorge Wilson (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 645f9af39baSGeorge Wilson goto error; 646f9af39baSGeorge Wilson } 647f9af39baSGeorge Wilson break; 648990b4856Slling } 649990b4856Slling } 650990b4856Slling 651990b4856Slling return (retprops); 652990b4856Slling error: 653990b4856Slling nvlist_free(retprops); 654990b4856Slling return (NULL); 655990b4856Slling } 656990b4856Slling 657990b4856Slling /* 658990b4856Slling * Set zpool property : propname=propval. 659990b4856Slling */ 660990b4856Slling int 661990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 662990b4856Slling { 663990b4856Slling zfs_cmd_t zc = { 0 }; 664990b4856Slling int ret = -1; 665990b4856Slling char errbuf[1024]; 666990b4856Slling nvlist_t *nvl = NULL; 667990b4856Slling nvlist_t *realprops; 668990b4856Slling uint64_t version; 669f9af39baSGeorge Wilson prop_flags_t flags = { 0 }; 670990b4856Slling 671990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), 672990b4856Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 673990b4856Slling zhp->zpool_name); 674990b4856Slling 675990b4856Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 676990b4856Slling return (no_memory(zhp->zpool_hdl)); 677990b4856Slling 678990b4856Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 679990b4856Slling nvlist_free(nvl); 680990b4856Slling return (no_memory(zhp->zpool_hdl)); 681990b4856Slling } 682990b4856Slling 683990b4856Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 6840a48a24eStimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 685f9af39baSGeorge Wilson zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) { 686990b4856Slling nvlist_free(nvl); 687990b4856Slling return (-1); 688990b4856Slling } 689990b4856Slling 690990b4856Slling nvlist_free(nvl); 691990b4856Slling nvl = realprops; 692990b4856Slling 693990b4856Slling /* 694990b4856Slling * Execute the corresponding ioctl() to set this property. 695990b4856Slling */ 696990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 697990b4856Slling 698990b4856Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 699990b4856Slling nvlist_free(nvl); 700990b4856Slling return (-1); 701990b4856Slling } 702990b4856Slling 703990b4856Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 704990b4856Slling 705990b4856Slling zcmd_free_nvlists(&zc); 706990b4856Slling nvlist_free(nvl); 707990b4856Slling 708990b4856Slling if (ret) 709990b4856Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 710990b4856Slling else 711990b4856Slling (void) zpool_props_refresh(zhp); 712990b4856Slling 713990b4856Slling return (ret); 714990b4856Slling } 715990b4856Slling 716990b4856Slling int 717990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 718990b4856Slling { 719990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 720990b4856Slling zprop_list_t *entry; 721990b4856Slling char buf[ZFS_MAXPROPLEN]; 722ad135b5dSChristopher Siden nvlist_t *features = NULL; 723ad135b5dSChristopher Siden zprop_list_t **last; 724ad135b5dSChristopher Siden boolean_t firstexpand = (NULL == *plp); 725990b4856Slling 726990b4856Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 727990b4856Slling return (-1); 728990b4856Slling 729ad135b5dSChristopher Siden last = plp; 730ad135b5dSChristopher Siden while (*last != NULL) 731ad135b5dSChristopher Siden last = &(*last)->pl_next; 732ad135b5dSChristopher Siden 733ad135b5dSChristopher Siden if ((*plp)->pl_all) 734ad135b5dSChristopher Siden features = zpool_get_features(zhp); 735ad135b5dSChristopher Siden 736ad135b5dSChristopher Siden if ((*plp)->pl_all && firstexpand) { 737ad135b5dSChristopher Siden for (int i = 0; i < SPA_FEATURES; i++) { 738ad135b5dSChristopher Siden zprop_list_t *entry = zfs_alloc(hdl, 739ad135b5dSChristopher Siden sizeof (zprop_list_t)); 740ad135b5dSChristopher Siden entry->pl_prop = ZPROP_INVAL; 741ad135b5dSChristopher Siden entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s", 742ad135b5dSChristopher Siden spa_feature_table[i].fi_uname); 743ad135b5dSChristopher Siden entry->pl_width = strlen(entry->pl_user_prop); 744ad135b5dSChristopher Siden entry->pl_all = B_TRUE; 745ad135b5dSChristopher Siden 746ad135b5dSChristopher Siden *last = entry; 747ad135b5dSChristopher Siden last = &entry->pl_next; 748ad135b5dSChristopher Siden } 749ad135b5dSChristopher Siden } 750ad135b5dSChristopher Siden 751ad135b5dSChristopher Siden /* add any unsupported features */ 752ad135b5dSChristopher Siden for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL); 753ad135b5dSChristopher Siden nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) { 754ad135b5dSChristopher Siden char *propname; 755ad135b5dSChristopher Siden boolean_t found; 756ad135b5dSChristopher Siden zprop_list_t *entry; 757ad135b5dSChristopher Siden 758ad135b5dSChristopher Siden if (zfeature_is_supported(nvpair_name(nvp))) 759ad135b5dSChristopher Siden continue; 760ad135b5dSChristopher Siden 761ad135b5dSChristopher Siden propname = zfs_asprintf(hdl, "unsupported@%s", 762ad135b5dSChristopher Siden nvpair_name(nvp)); 763ad135b5dSChristopher Siden 764ad135b5dSChristopher Siden /* 765ad135b5dSChristopher Siden * Before adding the property to the list make sure that no 766ad135b5dSChristopher Siden * other pool already added the same property. 767ad135b5dSChristopher Siden */ 768ad135b5dSChristopher Siden found = B_FALSE; 769ad135b5dSChristopher Siden entry = *plp; 770ad135b5dSChristopher Siden while (entry != NULL) { 771ad135b5dSChristopher Siden if (entry->pl_user_prop != NULL && 772ad135b5dSChristopher Siden strcmp(propname, entry->pl_user_prop) == 0) { 773ad135b5dSChristopher Siden found = B_TRUE; 774ad135b5dSChristopher Siden break; 775ad135b5dSChristopher Siden } 776ad135b5dSChristopher Siden entry = entry->pl_next; 777ad135b5dSChristopher Siden } 778ad135b5dSChristopher Siden if (found) { 779ad135b5dSChristopher Siden free(propname); 780ad135b5dSChristopher Siden continue; 781ad135b5dSChristopher Siden } 782ad135b5dSChristopher Siden 783ad135b5dSChristopher Siden entry = zfs_alloc(hdl, sizeof (zprop_list_t)); 784ad135b5dSChristopher Siden entry->pl_prop = ZPROP_INVAL; 785ad135b5dSChristopher Siden entry->pl_user_prop = propname; 786ad135b5dSChristopher Siden entry->pl_width = strlen(entry->pl_user_prop); 787ad135b5dSChristopher Siden entry->pl_all = B_TRUE; 788ad135b5dSChristopher Siden 789ad135b5dSChristopher Siden *last = entry; 790ad135b5dSChristopher Siden last = &entry->pl_next; 791ad135b5dSChristopher Siden } 792ad135b5dSChristopher Siden 793990b4856Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 794990b4856Slling 795990b4856Slling if (entry->pl_fixed) 796990b4856Slling continue; 797990b4856Slling 798990b4856Slling if (entry->pl_prop != ZPROP_INVAL && 799990b4856Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 800c58b3526SAdam Stevko NULL, B_FALSE) == 0) { 801990b4856Slling if (strlen(buf) > entry->pl_width) 802990b4856Slling entry->pl_width = strlen(buf); 803990b4856Slling } 804990b4856Slling } 805990b4856Slling 806990b4856Slling return (0); 807990b4856Slling } 808990b4856Slling 809ad135b5dSChristopher Siden /* 810ad135b5dSChristopher Siden * Get the state for the given feature on the given ZFS pool. 811ad135b5dSChristopher Siden */ 812ad135b5dSChristopher Siden int 813ad135b5dSChristopher Siden zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf, 814ad135b5dSChristopher Siden size_t len) 815ad135b5dSChristopher Siden { 816ad135b5dSChristopher Siden uint64_t refcount; 817ad135b5dSChristopher Siden boolean_t found = B_FALSE; 818ad135b5dSChristopher Siden nvlist_t *features = zpool_get_features(zhp); 819ad135b5dSChristopher Siden boolean_t supported; 820ad135b5dSChristopher Siden const char *feature = strchr(propname, '@') + 1; 821ad135b5dSChristopher Siden 822ad135b5dSChristopher Siden supported = zpool_prop_feature(propname); 823ad135b5dSChristopher Siden ASSERT(supported || zfs_prop_unsupported(propname)); 824ad135b5dSChristopher Siden 825ad135b5dSChristopher Siden /* 826ad135b5dSChristopher Siden * Convert from feature name to feature guid. This conversion is 827ad135b5dSChristopher Siden * unecessary for unsupported@... properties because they already 828ad135b5dSChristopher Siden * use guids. 829ad135b5dSChristopher Siden */ 830ad135b5dSChristopher Siden if (supported) { 831ad135b5dSChristopher Siden int ret; 8322acef22dSMatthew Ahrens spa_feature_t fid; 833ad135b5dSChristopher Siden 8342acef22dSMatthew Ahrens ret = zfeature_lookup_name(feature, &fid); 835ad135b5dSChristopher Siden if (ret != 0) { 836ad135b5dSChristopher Siden (void) strlcpy(buf, "-", len); 837ad135b5dSChristopher Siden return (ENOTSUP); 838ad135b5dSChristopher Siden } 8392acef22dSMatthew Ahrens feature = spa_feature_table[fid].fi_guid; 840ad135b5dSChristopher Siden } 841ad135b5dSChristopher Siden 842ad135b5dSChristopher Siden if (nvlist_lookup_uint64(features, feature, &refcount) == 0) 843ad135b5dSChristopher Siden found = B_TRUE; 844ad135b5dSChristopher Siden 845ad135b5dSChristopher Siden if (supported) { 846ad135b5dSChristopher Siden if (!found) { 847ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len); 848ad135b5dSChristopher Siden } else { 849ad135b5dSChristopher Siden if (refcount == 0) 850ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len); 851ad135b5dSChristopher Siden else 852ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len); 853ad135b5dSChristopher Siden } 854ad135b5dSChristopher Siden } else { 855ad135b5dSChristopher Siden if (found) { 856ad135b5dSChristopher Siden if (refcount == 0) { 857ad135b5dSChristopher Siden (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE); 858ad135b5dSChristopher Siden } else { 859ad135b5dSChristopher Siden (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY); 860ad135b5dSChristopher Siden } 861ad135b5dSChristopher Siden } else { 862ad135b5dSChristopher Siden (void) strlcpy(buf, "-", len); 863ad135b5dSChristopher Siden return (ENOTSUP); 864ad135b5dSChristopher Siden } 865ad135b5dSChristopher Siden } 866ad135b5dSChristopher Siden 867ad135b5dSChristopher Siden return (0); 868ad135b5dSChristopher Siden } 869990b4856Slling 870573ca77eSGeorge Wilson /* 871573ca77eSGeorge Wilson * Don't start the slice at the default block of 34; many storage 872573ca77eSGeorge Wilson * devices will use a stripe width of 128k, so start there instead. 873573ca77eSGeorge Wilson */ 874573ca77eSGeorge Wilson #define NEW_START_BLOCK 256 875573ca77eSGeorge Wilson 876fa9e4066Sahrens /* 877fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 878fa9e4066Sahrens * 'buf'. 879fa9e4066Sahrens */ 880e7cbe64fSgw boolean_t 88199653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 882fa9e4066Sahrens { 883fa9e4066Sahrens namecheck_err_t why; 884fa9e4066Sahrens char what; 885b468a217Seschrock int ret; 886b468a217Seschrock 887b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 888b468a217Seschrock 889b468a217Seschrock /* 890b468a217Seschrock * The rules for reserved pool names were extended at a later point. 891b468a217Seschrock * But we need to support users with existing pools that may now be 892b468a217Seschrock * invalid. So we only check for this expanded set of names during a 893b468a217Seschrock * create (or import), and only in userland. 894b468a217Seschrock */ 895b468a217Seschrock if (ret == 0 && !isopen && 896b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 897b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 8988654d025Sperrin strncmp(pool, "spare", 5) == 0 || 8998654d025Sperrin strcmp(pool, "log") == 0)) { 900e7cbe64fSgw if (hdl != NULL) 901e7cbe64fSgw zfs_error_aux(hdl, 902e7cbe64fSgw dgettext(TEXT_DOMAIN, "name is reserved")); 90399653d4eSeschrock return (B_FALSE); 904b468a217Seschrock } 905b468a217Seschrock 906fa9e4066Sahrens 907b468a217Seschrock if (ret != 0) { 90899653d4eSeschrock if (hdl != NULL) { 909fa9e4066Sahrens switch (why) { 910b81d61a6Slling case NAME_ERR_TOOLONG: 91199653d4eSeschrock zfs_error_aux(hdl, 912b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 913b81d61a6Slling break; 914b81d61a6Slling 915fa9e4066Sahrens case NAME_ERR_INVALCHAR: 91699653d4eSeschrock zfs_error_aux(hdl, 917fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 918fa9e4066Sahrens "'%c' in pool name"), what); 919fa9e4066Sahrens break; 920fa9e4066Sahrens 921fa9e4066Sahrens case NAME_ERR_NOLETTER: 92299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 92399653d4eSeschrock "name must begin with a letter")); 924fa9e4066Sahrens break; 925fa9e4066Sahrens 926fa9e4066Sahrens case NAME_ERR_RESERVED: 92799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 92899653d4eSeschrock "name is reserved")); 929fa9e4066Sahrens break; 930fa9e4066Sahrens 931fa9e4066Sahrens case NAME_ERR_DISKLIKE: 93299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 93399653d4eSeschrock "pool name is reserved")); 934fa9e4066Sahrens break; 9355ad82045Snd 9365ad82045Snd case NAME_ERR_LEADING_SLASH: 9375ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9385ad82045Snd "leading slash in name")); 9395ad82045Snd break; 9405ad82045Snd 9415ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 9425ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9435ad82045Snd "empty component in name")); 9445ad82045Snd break; 9455ad82045Snd 9465ad82045Snd case NAME_ERR_TRAILING_SLASH: 9475ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9485ad82045Snd "trailing slash in name")); 9495ad82045Snd break; 9505ad82045Snd 9515ad82045Snd case NAME_ERR_MULTIPLE_AT: 9525ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9535ad82045Snd "multiple '@' delimiters in name")); 9545ad82045Snd break; 9555ad82045Snd 956fa9e4066Sahrens } 957fa9e4066Sahrens } 95899653d4eSeschrock return (B_FALSE); 959fa9e4066Sahrens } 960fa9e4066Sahrens 96199653d4eSeschrock return (B_TRUE); 962fa9e4066Sahrens } 963fa9e4066Sahrens 964fa9e4066Sahrens /* 965fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 966fa9e4066Sahrens * state. 967fa9e4066Sahrens */ 968fa9e4066Sahrens zpool_handle_t * 96999653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 970fa9e4066Sahrens { 971fa9e4066Sahrens zpool_handle_t *zhp; 97294de1d4cSeschrock boolean_t missing; 973fa9e4066Sahrens 974fa9e4066Sahrens /* 975fa9e4066Sahrens * Make sure the pool name is valid. 976fa9e4066Sahrens */ 97799653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 978ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 97999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 98099653d4eSeschrock pool); 981fa9e4066Sahrens return (NULL); 982fa9e4066Sahrens } 983fa9e4066Sahrens 98499653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 98599653d4eSeschrock return (NULL); 986fa9e4066Sahrens 98799653d4eSeschrock zhp->zpool_hdl = hdl; 988fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 989fa9e4066Sahrens 99094de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 99194de1d4cSeschrock zpool_close(zhp); 99294de1d4cSeschrock return (NULL); 99394de1d4cSeschrock } 99494de1d4cSeschrock 99594de1d4cSeschrock if (missing) { 996990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 997ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 998990b4856Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 99994de1d4cSeschrock zpool_close(zhp); 100094de1d4cSeschrock return (NULL); 1001fa9e4066Sahrens } 1002fa9e4066Sahrens 1003fa9e4066Sahrens return (zhp); 1004fa9e4066Sahrens } 1005fa9e4066Sahrens 1006fa9e4066Sahrens /* 1007fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 1008fa9e4066Sahrens * the configuration cache may be out of date). 1009fa9e4066Sahrens */ 101094de1d4cSeschrock int 101194de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 1012fa9e4066Sahrens { 1013fa9e4066Sahrens zpool_handle_t *zhp; 101494de1d4cSeschrock boolean_t missing; 1015fa9e4066Sahrens 101694de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 101794de1d4cSeschrock return (-1); 1018fa9e4066Sahrens 101999653d4eSeschrock zhp->zpool_hdl = hdl; 1020fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 1021fa9e4066Sahrens 102294de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 102394de1d4cSeschrock zpool_close(zhp); 102494de1d4cSeschrock return (-1); 1025fa9e4066Sahrens } 1026fa9e4066Sahrens 102794de1d4cSeschrock if (missing) { 102894de1d4cSeschrock zpool_close(zhp); 102994de1d4cSeschrock *ret = NULL; 103094de1d4cSeschrock return (0); 103194de1d4cSeschrock } 103294de1d4cSeschrock 103394de1d4cSeschrock *ret = zhp; 103494de1d4cSeschrock return (0); 1035fa9e4066Sahrens } 1036fa9e4066Sahrens 1037fa9e4066Sahrens /* 1038fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 1039fa9e4066Sahrens * state. 1040fa9e4066Sahrens */ 1041fa9e4066Sahrens zpool_handle_t * 104299653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 1043fa9e4066Sahrens { 1044fa9e4066Sahrens zpool_handle_t *zhp; 1045fa9e4066Sahrens 104699653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 1047fa9e4066Sahrens return (NULL); 1048fa9e4066Sahrens 1049fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 1050ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 105199653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 1052fa9e4066Sahrens zpool_close(zhp); 1053fa9e4066Sahrens return (NULL); 1054fa9e4066Sahrens } 1055fa9e4066Sahrens 1056fa9e4066Sahrens return (zhp); 1057fa9e4066Sahrens } 1058fa9e4066Sahrens 1059fa9e4066Sahrens /* 1060fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 1061fa9e4066Sahrens */ 1062fa9e4066Sahrens void 1063fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 1064fa9e4066Sahrens { 1065fa9e4066Sahrens if (zhp->zpool_config) 1066fa9e4066Sahrens nvlist_free(zhp->zpool_config); 1067088e9d47Seschrock if (zhp->zpool_old_config) 1068088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 1069b1b8ab34Slling if (zhp->zpool_props) 1070b1b8ab34Slling nvlist_free(zhp->zpool_props); 1071fa9e4066Sahrens free(zhp); 1072fa9e4066Sahrens } 1073fa9e4066Sahrens 1074fa9e4066Sahrens /* 1075fa9e4066Sahrens * Return the name of the pool. 1076fa9e4066Sahrens */ 1077fa9e4066Sahrens const char * 1078fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 1079fa9e4066Sahrens { 1080fa9e4066Sahrens return (zhp->zpool_name); 1081fa9e4066Sahrens } 1082fa9e4066Sahrens 1083fa9e4066Sahrens 1084fa9e4066Sahrens /* 1085fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 1086fa9e4066Sahrens */ 1087fa9e4066Sahrens int 1088fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 1089fa9e4066Sahrens { 1090fa9e4066Sahrens return (zhp->zpool_state); 1091fa9e4066Sahrens } 1092fa9e4066Sahrens 1093fa9e4066Sahrens /* 1094fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 1095fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 1096fa9e4066Sahrens * don't have to worry about error semantics. 1097fa9e4066Sahrens */ 1098fa9e4066Sahrens int 109999653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 11000a48a24eStimh nvlist_t *props, nvlist_t *fsprops) 1101fa9e4066Sahrens { 1102fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 11030a48a24eStimh nvlist_t *zc_fsprops = NULL; 11040a48a24eStimh nvlist_t *zc_props = NULL; 110599653d4eSeschrock char msg[1024]; 11060a48a24eStimh int ret = -1; 1107fa9e4066Sahrens 110899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 110999653d4eSeschrock "cannot create '%s'"), pool); 1110fa9e4066Sahrens 111199653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 111299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 1113fa9e4066Sahrens 1114351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 1115990b4856Slling return (-1); 1116fa9e4066Sahrens 11170a48a24eStimh if (props) { 1118f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE }; 1119f9af39baSGeorge Wilson 11200a48a24eStimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 1121f9af39baSGeorge Wilson SPA_VERSION_1, flags, msg)) == NULL) { 11220a48a24eStimh goto create_failed; 11230a48a24eStimh } 11240a48a24eStimh } 112599653d4eSeschrock 11260a48a24eStimh if (fsprops) { 11270a48a24eStimh uint64_t zoned; 11280a48a24eStimh char *zonestr; 11290a48a24eStimh 11300a48a24eStimh zoned = ((nvlist_lookup_string(fsprops, 11310a48a24eStimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 11320a48a24eStimh strcmp(zonestr, "on") == 0); 11330a48a24eStimh 11340a48a24eStimh if ((zc_fsprops = zfs_valid_proplist(hdl, 11350a48a24eStimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 11360a48a24eStimh goto create_failed; 11370a48a24eStimh } 11380a48a24eStimh if (!zc_props && 11390a48a24eStimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 11400a48a24eStimh goto create_failed; 11410a48a24eStimh } 11420a48a24eStimh if (nvlist_add_nvlist(zc_props, 11430a48a24eStimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 11440a48a24eStimh goto create_failed; 11450a48a24eStimh } 1146351420b3Slling } 1147fa9e4066Sahrens 11480a48a24eStimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 11490a48a24eStimh goto create_failed; 11500a48a24eStimh 1151990b4856Slling (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 1152fa9e4066Sahrens 11530a48a24eStimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 1154351420b3Slling 1155e9dbad6fSeschrock zcmd_free_nvlists(&zc); 11560a48a24eStimh nvlist_free(zc_props); 11570a48a24eStimh nvlist_free(zc_fsprops); 1158fa9e4066Sahrens 115999653d4eSeschrock switch (errno) { 1160fa9e4066Sahrens case EBUSY: 1161fa9e4066Sahrens /* 1162fa9e4066Sahrens * This can happen if the user has specified the same 1163fa9e4066Sahrens * device multiple times. We can't reliably detect this 1164fa9e4066Sahrens * until we try to add it and see we already have a 1165fa9e4066Sahrens * label. 1166fa9e4066Sahrens */ 116799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116899653d4eSeschrock "one or more vdevs refer to the same device")); 116999653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1170fa9e4066Sahrens 1171fa9e4066Sahrens case EOVERFLOW: 1172fa9e4066Sahrens /* 117399653d4eSeschrock * This occurs when one of the devices is below 1174fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1175fa9e4066Sahrens * device was the problem device since there's no 1176fa9e4066Sahrens * reliable way to determine device size from userland. 1177fa9e4066Sahrens */ 1178fa9e4066Sahrens { 1179fa9e4066Sahrens char buf[64]; 1180fa9e4066Sahrens 1181fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1182fa9e4066Sahrens 118399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 118499653d4eSeschrock "one or more devices is less than the " 118599653d4eSeschrock "minimum size (%s)"), buf); 1186fa9e4066Sahrens } 118799653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1188fa9e4066Sahrens 1189fa9e4066Sahrens case ENOSPC: 119099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 119199653d4eSeschrock "one or more devices is out of space")); 119299653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1193fa9e4066Sahrens 1194fa94a07fSbrendan case ENOTBLK: 1195fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1196fa94a07fSbrendan "cache device must be a disk or disk slice")); 1197fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 1198fa94a07fSbrendan 1199fa9e4066Sahrens default: 120099653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1201fa9e4066Sahrens } 1202fa9e4066Sahrens } 1203fa9e4066Sahrens 12040a48a24eStimh create_failed: 1205351420b3Slling zcmd_free_nvlists(&zc); 12060a48a24eStimh nvlist_free(zc_props); 12070a48a24eStimh nvlist_free(zc_fsprops); 12080a48a24eStimh return (ret); 1209fa9e4066Sahrens } 1210fa9e4066Sahrens 1211fa9e4066Sahrens /* 1212fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1213fa9e4066Sahrens * datasets left in the pool. 1214fa9e4066Sahrens */ 1215fa9e4066Sahrens int 12164445fffbSMatthew Ahrens zpool_destroy(zpool_handle_t *zhp, const char *log_str) 1217fa9e4066Sahrens { 1218fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1219fa9e4066Sahrens zfs_handle_t *zfp = NULL; 122099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 122199653d4eSeschrock char msg[1024]; 1222fa9e4066Sahrens 1223fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 1224cb04b873SMark J Musante (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL) 1225fa9e4066Sahrens return (-1); 1226fa9e4066Sahrens 1227fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 12284445fffbSMatthew Ahrens zc.zc_history = (uint64_t)(uintptr_t)log_str; 1229fa9e4066Sahrens 1230cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 123199653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 123299653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 1233fa9e4066Sahrens 123499653d4eSeschrock if (errno == EROFS) { 123599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 123699653d4eSeschrock "one or more devices is read only")); 123799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 123899653d4eSeschrock } else { 123999653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1240fa9e4066Sahrens } 1241fa9e4066Sahrens 1242fa9e4066Sahrens if (zfp) 1243fa9e4066Sahrens zfs_close(zfp); 1244fa9e4066Sahrens return (-1); 1245fa9e4066Sahrens } 1246fa9e4066Sahrens 1247fa9e4066Sahrens if (zfp) { 1248fa9e4066Sahrens remove_mountpoint(zfp); 1249fa9e4066Sahrens zfs_close(zfp); 1250fa9e4066Sahrens } 1251fa9e4066Sahrens 1252fa9e4066Sahrens return (0); 1253fa9e4066Sahrens } 1254fa9e4066Sahrens 1255fa9e4066Sahrens /* 1256fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1257fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1258fa9e4066Sahrens */ 1259fa9e4066Sahrens int 1260fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1261fa9e4066Sahrens { 1262e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 126399653d4eSeschrock int ret; 126499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 126599653d4eSeschrock char msg[1024]; 1266fa94a07fSbrendan nvlist_t **spares, **l2cache; 1267fa94a07fSbrendan uint_t nspares, nl2cache; 126899653d4eSeschrock 126999653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 127099653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 127199653d4eSeschrock 1272fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1273fa94a07fSbrendan SPA_VERSION_SPARES && 127499653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 127599653d4eSeschrock &spares, &nspares) == 0) { 127699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 127799653d4eSeschrock "upgraded to add hot spares")); 127899653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 127999653d4eSeschrock } 1280fa9e4066Sahrens 12814263d13fSGeorge Wilson if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 1282b5b76fecSGeorge Wilson ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 1283b5b76fecSGeorge Wilson uint64_t s; 1284b5b76fecSGeorge Wilson 1285b5b76fecSGeorge Wilson for (s = 0; s < nspares; s++) { 1286b5b76fecSGeorge Wilson char *path; 1287b5b76fecSGeorge Wilson 1288b5b76fecSGeorge Wilson if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 1289b5b76fecSGeorge Wilson &path) == 0 && pool_uses_efi(spares[s])) { 1290b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1291b5b76fecSGeorge Wilson "device '%s' contains an EFI label and " 1292b5b76fecSGeorge Wilson "cannot be used on root pools."), 129388ecc943SGeorge Wilson zpool_vdev_name(hdl, NULL, spares[s], 129488ecc943SGeorge Wilson B_FALSE)); 1295b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 1296b5b76fecSGeorge Wilson } 1297b5b76fecSGeorge Wilson } 1298b5b76fecSGeorge Wilson } 1299b5b76fecSGeorge Wilson 1300fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1301fa94a07fSbrendan SPA_VERSION_L2CACHE && 1302fa94a07fSbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1303fa94a07fSbrendan &l2cache, &nl2cache) == 0) { 1304fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 1305fa94a07fSbrendan "upgraded to add cache devices")); 1306fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 1307fa94a07fSbrendan } 1308fa94a07fSbrendan 1309990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 131099653d4eSeschrock return (-1); 1311fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1312fa9e4066Sahrens 1313cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1314fa9e4066Sahrens switch (errno) { 1315fa9e4066Sahrens case EBUSY: 1316fa9e4066Sahrens /* 1317fa9e4066Sahrens * This can happen if the user has specified the same 1318fa9e4066Sahrens * device multiple times. We can't reliably detect this 1319fa9e4066Sahrens * until we try to add it and see we already have a 1320fa9e4066Sahrens * label. 1321fa9e4066Sahrens */ 132299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 132399653d4eSeschrock "one or more vdevs refer to the same device")); 132499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1325fa9e4066Sahrens break; 1326fa9e4066Sahrens 1327fa9e4066Sahrens case EOVERFLOW: 1328fa9e4066Sahrens /* 1329fa9e4066Sahrens * This occurrs when one of the devices is below 1330fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1331fa9e4066Sahrens * device was the problem device since there's no 1332fa9e4066Sahrens * reliable way to determine device size from userland. 1333fa9e4066Sahrens */ 1334fa9e4066Sahrens { 1335fa9e4066Sahrens char buf[64]; 1336fa9e4066Sahrens 1337fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1338fa9e4066Sahrens 133999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 134099653d4eSeschrock "device is less than the minimum " 134199653d4eSeschrock "size (%s)"), buf); 1342fa9e4066Sahrens } 134399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 134499653d4eSeschrock break; 134599653d4eSeschrock 134699653d4eSeschrock case ENOTSUP: 134799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13488654d025Sperrin "pool must be upgraded to add these vdevs")); 134999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1350fa9e4066Sahrens break; 1351fa9e4066Sahrens 1352b1b8ab34Slling case EDOM: 1353b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 13548654d025Sperrin "root pool can not have multiple vdevs" 13558654d025Sperrin " or separate logs")); 1356b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 1357b1b8ab34Slling break; 1358b1b8ab34Slling 1359fa94a07fSbrendan case ENOTBLK: 1360fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1361fa94a07fSbrendan "cache device must be a disk or disk slice")); 1362fa94a07fSbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 1363fa94a07fSbrendan break; 1364fa94a07fSbrendan 1365fa9e4066Sahrens default: 136699653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1367fa9e4066Sahrens } 1368fa9e4066Sahrens 136999653d4eSeschrock ret = -1; 137099653d4eSeschrock } else { 137199653d4eSeschrock ret = 0; 1372fa9e4066Sahrens } 1373fa9e4066Sahrens 1374e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1375fa9e4066Sahrens 137699653d4eSeschrock return (ret); 1377fa9e4066Sahrens } 1378fa9e4066Sahrens 1379fa9e4066Sahrens /* 1380fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 1381fa9e4066Sahrens * mounted datasets in the pool. 1382fa9e4066Sahrens */ 13834445fffbSMatthew Ahrens static int 13844445fffbSMatthew Ahrens zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce, 13854445fffbSMatthew Ahrens const char *log_str) 1386fa9e4066Sahrens { 1387fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 138889a89ebfSlling char msg[1024]; 1389fa9e4066Sahrens 139089a89ebfSlling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 139189a89ebfSlling "cannot export '%s'"), zhp->zpool_name); 139289a89ebfSlling 1393fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 139489a89ebfSlling zc.zc_cookie = force; 1395394ab0cbSGeorge Wilson zc.zc_guid = hardforce; 13964445fffbSMatthew Ahrens zc.zc_history = (uint64_t)(uintptr_t)log_str; 139789a89ebfSlling 139889a89ebfSlling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 139989a89ebfSlling switch (errno) { 140089a89ebfSlling case EXDEV: 140189a89ebfSlling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 140289a89ebfSlling "use '-f' to override the following errors:\n" 140389a89ebfSlling "'%s' has an active shared spare which could be" 140489a89ebfSlling " used by other pools once '%s' is exported."), 140589a89ebfSlling zhp->zpool_name, zhp->zpool_name); 140689a89ebfSlling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 140789a89ebfSlling msg)); 140889a89ebfSlling default: 140989a89ebfSlling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 141089a89ebfSlling msg)); 141189a89ebfSlling } 141289a89ebfSlling } 1413fa9e4066Sahrens 1414fa9e4066Sahrens return (0); 1415fa9e4066Sahrens } 1416fa9e4066Sahrens 1417394ab0cbSGeorge Wilson int 14184445fffbSMatthew Ahrens zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str) 1419394ab0cbSGeorge Wilson { 14204445fffbSMatthew Ahrens return (zpool_export_common(zhp, force, B_FALSE, log_str)); 1421394ab0cbSGeorge Wilson } 1422394ab0cbSGeorge Wilson 1423394ab0cbSGeorge Wilson int 14244445fffbSMatthew Ahrens zpool_export_force(zpool_handle_t *zhp, const char *log_str) 1425394ab0cbSGeorge Wilson { 14264445fffbSMatthew Ahrens return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str)); 1427394ab0cbSGeorge Wilson } 1428394ab0cbSGeorge Wilson 1429468c413aSTim Haley static void 1430468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 14314b964adaSGeorge Wilson nvlist_t *config) 1432468c413aSTim Haley { 14334b964adaSGeorge Wilson nvlist_t *nv = NULL; 1434468c413aSTim Haley uint64_t rewindto; 1435468c413aSTim Haley int64_t loss = -1; 1436468c413aSTim Haley struct tm t; 1437468c413aSTim Haley char timestr[128]; 1438468c413aSTim Haley 14394b964adaSGeorge Wilson if (!hdl->libzfs_printerr || config == NULL) 14404b964adaSGeorge Wilson return; 14414b964adaSGeorge Wilson 1442ad135b5dSChristopher Siden if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || 1443ad135b5dSChristopher Siden nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) { 1444468c413aSTim Haley return; 1445ad135b5dSChristopher Siden } 1446468c413aSTim Haley 14474b964adaSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1448468c413aSTim Haley return; 14494b964adaSGeorge Wilson (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 1450468c413aSTim Haley 1451468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1452468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1453468c413aSTim Haley if (dryrun) { 1454468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1455468c413aSTim Haley "Would be able to return %s " 1456468c413aSTim Haley "to its state as of %s.\n"), 1457468c413aSTim Haley name, timestr); 1458468c413aSTim Haley } else { 1459468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1460468c413aSTim Haley "Pool %s returned to its state as of %s.\n"), 1461468c413aSTim Haley name, timestr); 1462468c413aSTim Haley } 1463468c413aSTim Haley if (loss > 120) { 1464468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1465468c413aSTim Haley "%s approximately %lld "), 1466468c413aSTim Haley dryrun ? "Would discard" : "Discarded", 1467468c413aSTim Haley (loss + 30) / 60); 1468468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1469468c413aSTim Haley "minutes of transactions.\n")); 1470468c413aSTim Haley } else if (loss > 0) { 1471468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1472468c413aSTim Haley "%s approximately %lld "), 1473468c413aSTim Haley dryrun ? "Would discard" : "Discarded", loss); 1474468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1475468c413aSTim Haley "seconds of transactions.\n")); 1476468c413aSTim Haley } 1477468c413aSTim Haley } 1478468c413aSTim Haley } 1479468c413aSTim Haley 1480468c413aSTim Haley void 1481468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 1482468c413aSTim Haley nvlist_t *config) 1483468c413aSTim Haley { 14844b964adaSGeorge Wilson nvlist_t *nv = NULL; 1485468c413aSTim Haley int64_t loss = -1; 1486468c413aSTim Haley uint64_t edata = UINT64_MAX; 1487468c413aSTim Haley uint64_t rewindto; 1488468c413aSTim Haley struct tm t; 1489468c413aSTim Haley char timestr[128]; 1490468c413aSTim Haley 1491468c413aSTim Haley if (!hdl->libzfs_printerr) 1492468c413aSTim Haley return; 1493468c413aSTim Haley 1494468c413aSTim Haley if (reason >= 0) 1495468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 1496468c413aSTim Haley else 1497468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "\t")); 1498468c413aSTim Haley 1499468c413aSTim Haley /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 15004b964adaSGeorge Wilson if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || 1501ad135b5dSChristopher Siden nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 || 15024b964adaSGeorge Wilson nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1503468c413aSTim Haley goto no_info; 1504468c413aSTim Haley 15054b964adaSGeorge Wilson (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 15064b964adaSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 1507468c413aSTim Haley &edata); 1508468c413aSTim Haley 1509468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1510468c413aSTim Haley "Recovery is possible, but will result in some data loss.\n")); 1511468c413aSTim Haley 1512468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1513468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1514468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1515468c413aSTim Haley "\tReturning the pool to its state as of %s\n" 1516468c413aSTim Haley "\tshould correct the problem. "), 1517468c413aSTim Haley timestr); 1518468c413aSTim Haley } else { 1519468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1520468c413aSTim Haley "\tReverting the pool to an earlier state " 1521468c413aSTim Haley "should correct the problem.\n\t")); 1522468c413aSTim Haley } 1523468c413aSTim Haley 1524468c413aSTim Haley if (loss > 120) { 1525468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1526468c413aSTim Haley "Approximately %lld minutes of data\n" 1527468c413aSTim Haley "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 1528468c413aSTim Haley } else if (loss > 0) { 1529468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1530468c413aSTim Haley "Approximately %lld seconds of data\n" 1531468c413aSTim Haley "\tmust be discarded, irreversibly. "), loss); 1532468c413aSTim Haley } 1533468c413aSTim Haley if (edata != 0 && edata != UINT64_MAX) { 1534468c413aSTim Haley if (edata == 1) { 1535468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1536468c413aSTim Haley "After rewind, at least\n" 1537468c413aSTim Haley "\tone persistent user-data error will remain. ")); 1538468c413aSTim Haley } else { 1539468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1540468c413aSTim Haley "After rewind, several\n" 1541468c413aSTim Haley "\tpersistent user-data errors will remain. ")); 1542468c413aSTim Haley } 1543468c413aSTim Haley } 1544468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1545a33cae98STim Haley "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "), 1546a33cae98STim Haley reason >= 0 ? "clear" : "import", name); 1547468c413aSTim Haley 1548468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1549468c413aSTim Haley "A scrub of the pool\n" 1550468c413aSTim Haley "\tis strongly recommended after recovery.\n")); 1551468c413aSTim Haley return; 1552468c413aSTim Haley 1553468c413aSTim Haley no_info: 1554468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1555468c413aSTim Haley "Destroy and re-create the pool from\n\ta backup source.\n")); 1556468c413aSTim Haley } 1557468c413aSTim Haley 1558fa9e4066Sahrens /* 1559990b4856Slling * zpool_import() is a contracted interface. Should be kept the same 1560990b4856Slling * if possible. 1561990b4856Slling * 1562990b4856Slling * Applications should use zpool_import_props() to import a pool with 1563990b4856Slling * new properties value to be set. 1564fa9e4066Sahrens */ 1565fa9e4066Sahrens int 156699653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1567990b4856Slling char *altroot) 1568990b4856Slling { 1569990b4856Slling nvlist_t *props = NULL; 1570990b4856Slling int ret; 1571990b4856Slling 1572990b4856Slling if (altroot != NULL) { 1573990b4856Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1574990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1575990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1576990b4856Slling newname)); 1577990b4856Slling } 1578990b4856Slling 1579990b4856Slling if (nvlist_add_string(props, 1580352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 1581352d8027SGeorge Wilson nvlist_add_string(props, 1582352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 1583990b4856Slling nvlist_free(props); 1584990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1585990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1586990b4856Slling newname)); 1587990b4856Slling } 1588990b4856Slling } 1589990b4856Slling 15904b964adaSGeorge Wilson ret = zpool_import_props(hdl, config, newname, props, 15914b964adaSGeorge Wilson ZFS_IMPORT_NORMAL); 1592990b4856Slling if (props) 1593990b4856Slling nvlist_free(props); 1594990b4856Slling return (ret); 1595990b4856Slling } 1596990b4856Slling 15974b964adaSGeorge Wilson static void 15984b964adaSGeorge Wilson print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv, 15994b964adaSGeorge Wilson int indent) 16004b964adaSGeorge Wilson { 16014b964adaSGeorge Wilson nvlist_t **child; 16024b964adaSGeorge Wilson uint_t c, children; 16034b964adaSGeorge Wilson char *vname; 16044b964adaSGeorge Wilson uint64_t is_log = 0; 16054b964adaSGeorge Wilson 16064b964adaSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, 16074b964adaSGeorge Wilson &is_log); 16084b964adaSGeorge Wilson 16094b964adaSGeorge Wilson if (name != NULL) 16104b964adaSGeorge Wilson (void) printf("\t%*s%s%s\n", indent, "", name, 16114b964adaSGeorge Wilson is_log ? " [log]" : ""); 16124b964adaSGeorge Wilson 16134b964adaSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 16144b964adaSGeorge Wilson &child, &children) != 0) 16154b964adaSGeorge Wilson return; 16164b964adaSGeorge Wilson 16174b964adaSGeorge Wilson for (c = 0; c < children; c++) { 16184b964adaSGeorge Wilson vname = zpool_vdev_name(hdl, NULL, child[c], B_TRUE); 16194b964adaSGeorge Wilson print_vdev_tree(hdl, vname, child[c], indent + 2); 16204b964adaSGeorge Wilson free(vname); 16214b964adaSGeorge Wilson } 16224b964adaSGeorge Wilson } 16234b964adaSGeorge Wilson 1624ad135b5dSChristopher Siden void 1625ad135b5dSChristopher Siden zpool_print_unsup_feat(nvlist_t *config) 1626ad135b5dSChristopher Siden { 1627ad135b5dSChristopher Siden nvlist_t *nvinfo, *unsup_feat; 1628ad135b5dSChristopher Siden 1629ad135b5dSChristopher Siden verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 1630ad135b5dSChristopher Siden 0); 1631ad135b5dSChristopher Siden verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT, 1632ad135b5dSChristopher Siden &unsup_feat) == 0); 1633ad135b5dSChristopher Siden 1634ad135b5dSChristopher Siden for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL; 1635ad135b5dSChristopher Siden nvp = nvlist_next_nvpair(unsup_feat, nvp)) { 1636ad135b5dSChristopher Siden char *desc; 1637ad135b5dSChristopher Siden 1638ad135b5dSChristopher Siden verify(nvpair_type(nvp) == DATA_TYPE_STRING); 1639ad135b5dSChristopher Siden verify(nvpair_value_string(nvp, &desc) == 0); 1640ad135b5dSChristopher Siden 1641ad135b5dSChristopher Siden if (strlen(desc) > 0) 1642ad135b5dSChristopher Siden (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc); 1643ad135b5dSChristopher Siden else 1644ad135b5dSChristopher Siden (void) printf("\t%s\n", nvpair_name(nvp)); 1645ad135b5dSChristopher Siden } 1646ad135b5dSChristopher Siden } 1647ad135b5dSChristopher Siden 1648990b4856Slling /* 1649990b4856Slling * Import the given pool using the known configuration and a list of 1650990b4856Slling * properties to be set. The configuration should have come from 1651990b4856Slling * zpool_find_import(). The 'newname' parameters control whether the pool 1652990b4856Slling * is imported with a different name. 1653990b4856Slling */ 1654990b4856Slling int 1655990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 16564b964adaSGeorge Wilson nvlist_t *props, int flags) 1657fa9e4066Sahrens { 1658e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 1659468c413aSTim Haley zpool_rewind_policy_t policy; 16604b964adaSGeorge Wilson nvlist_t *nv = NULL; 16614b964adaSGeorge Wilson nvlist_t *nvinfo = NULL; 16624b964adaSGeorge Wilson nvlist_t *missing = NULL; 1663fa9e4066Sahrens char *thename; 1664fa9e4066Sahrens char *origname; 1665fa9e4066Sahrens int ret; 16664b964adaSGeorge Wilson int error = 0; 1667990b4856Slling char errbuf[1024]; 1668fa9e4066Sahrens 1669fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1670fa9e4066Sahrens &origname) == 0); 1671fa9e4066Sahrens 1672990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1673990b4856Slling "cannot import pool '%s'"), origname); 1674990b4856Slling 1675fa9e4066Sahrens if (newname != NULL) { 167699653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 1677ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 167899653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 167999653d4eSeschrock newname)); 1680fa9e4066Sahrens thename = (char *)newname; 1681fa9e4066Sahrens } else { 1682fa9e4066Sahrens thename = origname; 1683fa9e4066Sahrens } 1684fa9e4066Sahrens 1685990b4856Slling if (props) { 1686990b4856Slling uint64_t version; 1687f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 1688fa9e4066Sahrens 1689990b4856Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 1690990b4856Slling &version) == 0); 1691fa9e4066Sahrens 16920a48a24eStimh if ((props = zpool_valid_proplist(hdl, origname, 1693f9af39baSGeorge Wilson props, version, flags, errbuf)) == NULL) { 1694990b4856Slling return (-1); 1695351420b3Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 1696351420b3Slling nvlist_free(props); 1697990b4856Slling return (-1); 1698351420b3Slling } 1699990b4856Slling } 1700990b4856Slling 1701990b4856Slling (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1702fa9e4066Sahrens 1703fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1704ea8dc4b6Seschrock &zc.zc_guid) == 0); 1705fa9e4066Sahrens 1706351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 1707351420b3Slling nvlist_free(props); 170899653d4eSeschrock return (-1); 1709351420b3Slling } 171057f304caSGeorge Wilson if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) { 1711468c413aSTim Haley nvlist_free(props); 1712468c413aSTim Haley return (-1); 1713468c413aSTim Haley } 1714fa9e4066Sahrens 17154b964adaSGeorge Wilson zc.zc_cookie = flags; 17164b964adaSGeorge Wilson while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 && 17174b964adaSGeorge Wilson errno == ENOMEM) { 17184b964adaSGeorge Wilson if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 17194b964adaSGeorge Wilson zcmd_free_nvlists(&zc); 17204b964adaSGeorge Wilson return (-1); 17214b964adaSGeorge Wilson } 17224b964adaSGeorge Wilson } 17234b964adaSGeorge Wilson if (ret != 0) 17244b964adaSGeorge Wilson error = errno; 17254b964adaSGeorge Wilson 17264b964adaSGeorge Wilson (void) zcmd_read_dst_nvlist(hdl, &zc, &nv); 17274b964adaSGeorge Wilson zpool_get_rewind_policy(config, &policy); 17284b964adaSGeorge Wilson 17294b964adaSGeorge Wilson if (error) { 1730fa9e4066Sahrens char desc[1024]; 1731468c413aSTim Haley 1732468c413aSTim Haley /* 1733468c413aSTim Haley * Dry-run failed, but we print out what success 1734468c413aSTim Haley * looks like if we found a best txg 1735468c413aSTim Haley */ 17364b964adaSGeorge Wilson if (policy.zrp_request & ZPOOL_TRY_REWIND) { 1737468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 17384b964adaSGeorge Wilson B_TRUE, nv); 17394b964adaSGeorge Wilson nvlist_free(nv); 1740468c413aSTim Haley return (-1); 1741468c413aSTim Haley } 1742468c413aSTim Haley 1743fa9e4066Sahrens if (newname == NULL) 1744fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1745fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1746fa9e4066Sahrens thename); 1747fa9e4066Sahrens else 1748fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1749fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1750fa9e4066Sahrens origname, thename); 1751fa9e4066Sahrens 17524b964adaSGeorge Wilson switch (error) { 1753ea8dc4b6Seschrock case ENOTSUP: 1754ad135b5dSChristopher Siden if (nv != NULL && nvlist_lookup_nvlist(nv, 1755ad135b5dSChristopher Siden ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && 1756ad135b5dSChristopher Siden nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) { 1757ad135b5dSChristopher Siden (void) printf(dgettext(TEXT_DOMAIN, "This " 1758ad135b5dSChristopher Siden "pool uses the following feature(s) not " 1759ad135b5dSChristopher Siden "supported by this system:\n")); 1760ad135b5dSChristopher Siden zpool_print_unsup_feat(nv); 1761ad135b5dSChristopher Siden if (nvlist_exists(nvinfo, 1762ad135b5dSChristopher Siden ZPOOL_CONFIG_CAN_RDONLY)) { 1763ad135b5dSChristopher Siden (void) printf(dgettext(TEXT_DOMAIN, 1764ad135b5dSChristopher Siden "All unsupported features are only " 1765ad135b5dSChristopher Siden "required for writing to the pool." 1766ad135b5dSChristopher Siden "\nThe pool can be imported using " 1767ad135b5dSChristopher Siden "'-o readonly=on'.\n")); 1768ad135b5dSChristopher Siden } 1769ad135b5dSChristopher Siden } 1770ea8dc4b6Seschrock /* 1771ea8dc4b6Seschrock * Unsupported version. 1772ea8dc4b6Seschrock */ 177399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 1774ea8dc4b6Seschrock break; 1775ea8dc4b6Seschrock 1776b5989ec7Seschrock case EINVAL: 1777b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 1778b5989ec7Seschrock break; 1779b5989ec7Seschrock 178054a91118SChris Kirby case EROFS: 178154a91118SChris Kirby zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 178254a91118SChris Kirby "one or more devices is read only")); 178354a91118SChris Kirby (void) zfs_error(hdl, EZFS_BADDEV, desc); 178454a91118SChris Kirby break; 178554a91118SChris Kirby 17864b964adaSGeorge Wilson case ENXIO: 17874b964adaSGeorge Wilson if (nv && nvlist_lookup_nvlist(nv, 17884b964adaSGeorge Wilson ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && 17894b964adaSGeorge Wilson nvlist_lookup_nvlist(nvinfo, 17904b964adaSGeorge Wilson ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) { 17914b964adaSGeorge Wilson (void) printf(dgettext(TEXT_DOMAIN, 17924b964adaSGeorge Wilson "The devices below are missing, use " 17934b964adaSGeorge Wilson "'-m' to import the pool anyway:\n")); 17944b964adaSGeorge Wilson print_vdev_tree(hdl, NULL, missing, 2); 17954b964adaSGeorge Wilson (void) printf("\n"); 17964b964adaSGeorge Wilson } 17974b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 17984b964adaSGeorge Wilson break; 17994b964adaSGeorge Wilson 18004b964adaSGeorge Wilson case EEXIST: 18014b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 18024b964adaSGeorge Wilson break; 18034b964adaSGeorge Wilson 1804fa9e4066Sahrens default: 18054b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 1806468c413aSTim Haley zpool_explain_recover(hdl, 18074b964adaSGeorge Wilson newname ? origname : thename, -error, nv); 1808468c413aSTim Haley break; 1809fa9e4066Sahrens } 1810fa9e4066Sahrens 18114b964adaSGeorge Wilson nvlist_free(nv); 1812fa9e4066Sahrens ret = -1; 1813fa9e4066Sahrens } else { 1814fa9e4066Sahrens zpool_handle_t *zhp; 1815ecd6cf80Smarks 1816fa9e4066Sahrens /* 1817fa9e4066Sahrens * This should never fail, but play it safe anyway. 1818fa9e4066Sahrens */ 1819681d9761SEric Taylor if (zpool_open_silent(hdl, thename, &zhp) != 0) 182094de1d4cSeschrock ret = -1; 1821681d9761SEric Taylor else if (zhp != NULL) 1822fa9e4066Sahrens zpool_close(zhp); 1823468c413aSTim Haley if (policy.zrp_request & 1824468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 1825468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 18264b964adaSGeorge Wilson ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), nv); 1827468c413aSTim Haley } 18284b964adaSGeorge Wilson nvlist_free(nv); 1829468c413aSTim Haley return (0); 1830fa9e4066Sahrens } 1831fa9e4066Sahrens 1832e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1833351420b3Slling nvlist_free(props); 1834351420b3Slling 1835fa9e4066Sahrens return (ret); 1836fa9e4066Sahrens } 1837fa9e4066Sahrens 1838fa9e4066Sahrens /* 18393f9d6ad7SLin Ling * Scan the pool. 1840fa9e4066Sahrens */ 1841fa9e4066Sahrens int 18423f9d6ad7SLin Ling zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func) 1843fa9e4066Sahrens { 1844fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1845fa9e4066Sahrens char msg[1024]; 184699653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1847fa9e4066Sahrens 1848fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 18493f9d6ad7SLin Ling zc.zc_cookie = func; 1850fa9e4066Sahrens 1851cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0 || 18523f9d6ad7SLin Ling (errno == ENOENT && func != POOL_SCAN_NONE)) 1853fa9e4066Sahrens return (0); 1854fa9e4066Sahrens 18553f9d6ad7SLin Ling if (func == POOL_SCAN_SCRUB) { 18563f9d6ad7SLin Ling (void) snprintf(msg, sizeof (msg), 18573f9d6ad7SLin Ling dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 18583f9d6ad7SLin Ling } else if (func == POOL_SCAN_NONE) { 18593f9d6ad7SLin Ling (void) snprintf(msg, sizeof (msg), 18603f9d6ad7SLin Ling dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"), 18613f9d6ad7SLin Ling zc.zc_name); 18623f9d6ad7SLin Ling } else { 18633f9d6ad7SLin Ling assert(!"unexpected result"); 18643f9d6ad7SLin Ling } 1865fa9e4066Sahrens 18663f9d6ad7SLin Ling if (errno == EBUSY) { 18673f9d6ad7SLin Ling nvlist_t *nvroot; 18683f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 18693f9d6ad7SLin Ling uint_t psc; 18703f9d6ad7SLin Ling 18713f9d6ad7SLin Ling verify(nvlist_lookup_nvlist(zhp->zpool_config, 18723f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 18733f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nvroot, 18743f9d6ad7SLin Ling ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc); 18753f9d6ad7SLin Ling if (ps && ps->pss_func == POOL_SCAN_SCRUB) 18763f9d6ad7SLin Ling return (zfs_error(hdl, EZFS_SCRUBBING, msg)); 18773f9d6ad7SLin Ling else 18783f9d6ad7SLin Ling return (zfs_error(hdl, EZFS_RESILVERING, msg)); 18793f9d6ad7SLin Ling } else if (errno == ENOENT) { 18803f9d6ad7SLin Ling return (zfs_error(hdl, EZFS_NO_SCRUB, msg)); 18813f9d6ad7SLin Ling } else { 188299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 18833f9d6ad7SLin Ling } 1884fa9e4066Sahrens } 1885fa9e4066Sahrens 18863fdda499SJohn Harres /* 18873fdda499SJohn Harres * This provides a very minimal check whether a given string is likely a 18883fdda499SJohn Harres * c#t#d# style string. Users of this are expected to do their own 18893fdda499SJohn Harres * verification of the s# part. 18903fdda499SJohn Harres */ 18913fdda499SJohn Harres #define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1])) 18923fdda499SJohn Harres 18933fdda499SJohn Harres /* 18943fdda499SJohn Harres * More elaborate version for ones which may start with "/dev/dsk/" 18953fdda499SJohn Harres * and the like. 18963fdda499SJohn Harres */ 18973fdda499SJohn Harres static int 18983fdda499SJohn Harres ctd_check_path(char *str) { 18993fdda499SJohn Harres /* 19003fdda499SJohn Harres * If it starts with a slash, check the last component. 19013fdda499SJohn Harres */ 19023fdda499SJohn Harres if (str && str[0] == '/') { 19033fdda499SJohn Harres char *tmp = strrchr(str, '/'); 19043fdda499SJohn Harres 19053fdda499SJohn Harres /* 19063fdda499SJohn Harres * If it ends in "/old", check the second-to-last 19073fdda499SJohn Harres * component of the string instead. 19083fdda499SJohn Harres */ 19093fdda499SJohn Harres if (tmp != str && strcmp(tmp, "/old") == 0) { 19103fdda499SJohn Harres for (tmp--; *tmp != '/'; tmp--) 19113fdda499SJohn Harres ; 19123fdda499SJohn Harres } 19133fdda499SJohn Harres str = tmp + 1; 19143fdda499SJohn Harres } 19153fdda499SJohn Harres return (CTD_CHECK(str)); 19163fdda499SJohn Harres } 19173fdda499SJohn Harres 1918a43d325bSek /* 1919573ca77eSGeorge Wilson * Find a vdev that matches the search criteria specified. We use the 1920573ca77eSGeorge Wilson * the nvpair name to determine how we should look for the device. 1921a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 1922a43d325bSek * spare; but FALSE if its an INUSE spare. 1923a43d325bSek */ 192499653d4eSeschrock static nvlist_t * 1925573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 1926573ca77eSGeorge Wilson boolean_t *l2cache, boolean_t *log) 1927ea8dc4b6Seschrock { 1928ea8dc4b6Seschrock uint_t c, children; 1929ea8dc4b6Seschrock nvlist_t **child; 193099653d4eSeschrock nvlist_t *ret; 1931ee0eb9f2SEric Schrock uint64_t is_log; 1932573ca77eSGeorge Wilson char *srchkey; 1933573ca77eSGeorge Wilson nvpair_t *pair = nvlist_next_nvpair(search, NULL); 1934573ca77eSGeorge Wilson 1935573ca77eSGeorge Wilson /* Nothing to look for */ 1936573ca77eSGeorge Wilson if (search == NULL || pair == NULL) 1937573ca77eSGeorge Wilson return (NULL); 1938ea8dc4b6Seschrock 1939573ca77eSGeorge Wilson /* Obtain the key we will use to search */ 1940573ca77eSGeorge Wilson srchkey = nvpair_name(pair); 1941573ca77eSGeorge Wilson 1942573ca77eSGeorge Wilson switch (nvpair_type(pair)) { 1943cb04b873SMark J Musante case DATA_TYPE_UINT64: 1944573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 1945cb04b873SMark J Musante uint64_t srchval, theguid; 1946cb04b873SMark J Musante 1947cb04b873SMark J Musante verify(nvpair_value_uint64(pair, &srchval) == 0); 1948cb04b873SMark J Musante verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1949cb04b873SMark J Musante &theguid) == 0); 1950cb04b873SMark J Musante if (theguid == srchval) 1951cb04b873SMark J Musante return (nv); 1952573ca77eSGeorge Wilson } 1953573ca77eSGeorge Wilson break; 1954573ca77eSGeorge Wilson 1955573ca77eSGeorge Wilson case DATA_TYPE_STRING: { 1956573ca77eSGeorge Wilson char *srchval, *val; 1957573ca77eSGeorge Wilson 1958573ca77eSGeorge Wilson verify(nvpair_value_string(pair, &srchval) == 0); 1959573ca77eSGeorge Wilson if (nvlist_lookup_string(nv, srchkey, &val) != 0) 1960573ca77eSGeorge Wilson break; 1961ea8dc4b6Seschrock 1962ea8dc4b6Seschrock /* 19633fdda499SJohn Harres * Search for the requested value. Special cases: 19643fdda499SJohn Harres * 19653fdda499SJohn Harres * - ZPOOL_CONFIG_PATH for whole disk entries. These end in 19663fdda499SJohn Harres * "s0" or "s0/old". The "s0" part is hidden from the user, 19673fdda499SJohn Harres * but included in the string, so this matches around it. 19683fdda499SJohn Harres * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 19693fdda499SJohn Harres * 197088ecc943SGeorge Wilson * Otherwise, all other searches are simple string compares. 1971ea8dc4b6Seschrock */ 19723fdda499SJohn Harres if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && 19733fdda499SJohn Harres ctd_check_path(val)) { 1974573ca77eSGeorge Wilson uint64_t wholedisk = 0; 1975573ca77eSGeorge Wilson 1976573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1977573ca77eSGeorge Wilson &wholedisk); 1978573ca77eSGeorge Wilson if (wholedisk) { 19793fdda499SJohn Harres int slen = strlen(srchval); 19803fdda499SJohn Harres int vlen = strlen(val); 19813fdda499SJohn Harres 19823fdda499SJohn Harres if (slen != vlen - 2) 19833fdda499SJohn Harres break; 19843fdda499SJohn Harres 19853fdda499SJohn Harres /* 19863fdda499SJohn Harres * make_leaf_vdev() should only set 19873fdda499SJohn Harres * wholedisk for ZPOOL_CONFIG_PATHs which 19883fdda499SJohn Harres * will include "/dev/dsk/", giving plenty of 19893fdda499SJohn Harres * room for the indices used next. 19903fdda499SJohn Harres */ 19913fdda499SJohn Harres ASSERT(vlen >= 6); 19923fdda499SJohn Harres 19933fdda499SJohn Harres /* 19943fdda499SJohn Harres * strings identical except trailing "s0" 19953fdda499SJohn Harres */ 19963fdda499SJohn Harres if (strcmp(&val[vlen - 2], "s0") == 0 && 19973fdda499SJohn Harres strncmp(srchval, val, slen) == 0) 19983fdda499SJohn Harres return (nv); 19993fdda499SJohn Harres 2000573ca77eSGeorge Wilson /* 20013fdda499SJohn Harres * strings identical except trailing "s0/old" 2002573ca77eSGeorge Wilson */ 20033fdda499SJohn Harres if (strcmp(&val[vlen - 6], "s0/old") == 0 && 20043fdda499SJohn Harres strcmp(&srchval[slen - 4], "/old") == 0 && 20053fdda499SJohn Harres strncmp(srchval, val, slen - 4) == 0) 2006573ca77eSGeorge Wilson return (nv); 20073fdda499SJohn Harres 2008573ca77eSGeorge Wilson break; 2009573ca77eSGeorge Wilson } 201088ecc943SGeorge Wilson } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 201188ecc943SGeorge Wilson char *type, *idx, *end, *p; 201288ecc943SGeorge Wilson uint64_t id, vdev_id; 201388ecc943SGeorge Wilson 201488ecc943SGeorge Wilson /* 201588ecc943SGeorge Wilson * Determine our vdev type, keeping in mind 201688ecc943SGeorge Wilson * that the srchval is composed of a type and 201788ecc943SGeorge Wilson * vdev id pair (i.e. mirror-4). 201888ecc943SGeorge Wilson */ 201988ecc943SGeorge Wilson if ((type = strdup(srchval)) == NULL) 202088ecc943SGeorge Wilson return (NULL); 202188ecc943SGeorge Wilson 202288ecc943SGeorge Wilson if ((p = strrchr(type, '-')) == NULL) { 202388ecc943SGeorge Wilson free(type); 202488ecc943SGeorge Wilson break; 202588ecc943SGeorge Wilson } 202688ecc943SGeorge Wilson idx = p + 1; 202788ecc943SGeorge Wilson *p = '\0'; 202888ecc943SGeorge Wilson 202988ecc943SGeorge Wilson /* 203088ecc943SGeorge Wilson * If the types don't match then keep looking. 203188ecc943SGeorge Wilson */ 203288ecc943SGeorge Wilson if (strncmp(val, type, strlen(val)) != 0) { 203388ecc943SGeorge Wilson free(type); 203488ecc943SGeorge Wilson break; 203588ecc943SGeorge Wilson } 203688ecc943SGeorge Wilson 203788ecc943SGeorge Wilson verify(strncmp(type, VDEV_TYPE_RAIDZ, 203888ecc943SGeorge Wilson strlen(VDEV_TYPE_RAIDZ)) == 0 || 203988ecc943SGeorge Wilson strncmp(type, VDEV_TYPE_MIRROR, 204088ecc943SGeorge Wilson strlen(VDEV_TYPE_MIRROR)) == 0); 204188ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 204288ecc943SGeorge Wilson &id) == 0); 204388ecc943SGeorge Wilson 204488ecc943SGeorge Wilson errno = 0; 204588ecc943SGeorge Wilson vdev_id = strtoull(idx, &end, 10); 204688ecc943SGeorge Wilson 204788ecc943SGeorge Wilson free(type); 204888ecc943SGeorge Wilson if (errno != 0) 204988ecc943SGeorge Wilson return (NULL); 205088ecc943SGeorge Wilson 205188ecc943SGeorge Wilson /* 205288ecc943SGeorge Wilson * Now verify that we have the correct vdev id. 205388ecc943SGeorge Wilson */ 205488ecc943SGeorge Wilson if (vdev_id == id) 205588ecc943SGeorge Wilson return (nv); 2056ea8dc4b6Seschrock } 2057573ca77eSGeorge Wilson 2058573ca77eSGeorge Wilson /* 2059573ca77eSGeorge Wilson * Common case 2060573ca77eSGeorge Wilson */ 2061573ca77eSGeorge Wilson if (strcmp(srchval, val) == 0) 2062573ca77eSGeorge Wilson return (nv); 2063573ca77eSGeorge Wilson break; 2064573ca77eSGeorge Wilson } 2065573ca77eSGeorge Wilson 2066573ca77eSGeorge Wilson default: 2067573ca77eSGeorge Wilson break; 2068ea8dc4b6Seschrock } 2069ea8dc4b6Seschrock 2070ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2071ea8dc4b6Seschrock &child, &children) != 0) 207299653d4eSeschrock return (NULL); 2073ea8dc4b6Seschrock 2074ee0eb9f2SEric Schrock for (c = 0; c < children; c++) { 2075573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2076ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2077ee0eb9f2SEric Schrock /* 2078ee0eb9f2SEric Schrock * The 'is_log' value is only set for the toplevel 2079ee0eb9f2SEric Schrock * vdev, not the leaf vdevs. So we always lookup the 2080ee0eb9f2SEric Schrock * log device from the root of the vdev tree (where 2081ee0eb9f2SEric Schrock * 'log' is non-NULL). 2082ee0eb9f2SEric Schrock */ 2083ee0eb9f2SEric Schrock if (log != NULL && 2084ee0eb9f2SEric Schrock nvlist_lookup_uint64(child[c], 2085ee0eb9f2SEric Schrock ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 2086ee0eb9f2SEric Schrock is_log) { 2087ee0eb9f2SEric Schrock *log = B_TRUE; 2088ee0eb9f2SEric Schrock } 2089ea8dc4b6Seschrock return (ret); 2090ee0eb9f2SEric Schrock } 2091ee0eb9f2SEric Schrock } 2092ea8dc4b6Seschrock 209399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 209499653d4eSeschrock &child, &children) == 0) { 209599653d4eSeschrock for (c = 0; c < children; c++) { 2096573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2097ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2098a43d325bSek *avail_spare = B_TRUE; 209999653d4eSeschrock return (ret); 210099653d4eSeschrock } 210199653d4eSeschrock } 210299653d4eSeschrock } 210399653d4eSeschrock 2104fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2105fa94a07fSbrendan &child, &children) == 0) { 2106fa94a07fSbrendan for (c = 0; c < children; c++) { 2107573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2108ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2109fa94a07fSbrendan *l2cache = B_TRUE; 2110fa94a07fSbrendan return (ret); 2111fa94a07fSbrendan } 2112fa94a07fSbrendan } 2113fa94a07fSbrendan } 2114fa94a07fSbrendan 211599653d4eSeschrock return (NULL); 2116ea8dc4b6Seschrock } 2117ea8dc4b6Seschrock 2118573ca77eSGeorge Wilson /* 2119573ca77eSGeorge Wilson * Given a physical path (minus the "/devices" prefix), find the 2120573ca77eSGeorge Wilson * associated vdev. 2121573ca77eSGeorge Wilson */ 2122573ca77eSGeorge Wilson nvlist_t * 2123573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 2124573ca77eSGeorge Wilson boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 2125573ca77eSGeorge Wilson { 2126573ca77eSGeorge Wilson nvlist_t *search, *nvroot, *ret; 2127573ca77eSGeorge Wilson 2128573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2129573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 2130573ca77eSGeorge Wilson 2131573ca77eSGeorge Wilson verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 2132573ca77eSGeorge Wilson &nvroot) == 0); 2133573ca77eSGeorge Wilson 2134573ca77eSGeorge Wilson *avail_spare = B_FALSE; 2135cb04b873SMark J Musante *l2cache = B_FALSE; 2136daeb70e5SMark J Musante if (log != NULL) 2137daeb70e5SMark J Musante *log = B_FALSE; 2138573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 2139573ca77eSGeorge Wilson nvlist_free(search); 2140573ca77eSGeorge Wilson 2141573ca77eSGeorge Wilson return (ret); 2142573ca77eSGeorge Wilson } 2143573ca77eSGeorge Wilson 214488ecc943SGeorge Wilson /* 214588ecc943SGeorge Wilson * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 214688ecc943SGeorge Wilson */ 214788ecc943SGeorge Wilson boolean_t 214888ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name) 214988ecc943SGeorge Wilson { 215088ecc943SGeorge Wilson if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 215188ecc943SGeorge Wilson strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 215288ecc943SGeorge Wilson return (B_TRUE); 215388ecc943SGeorge Wilson return (B_FALSE); 215488ecc943SGeorge Wilson } 215588ecc943SGeorge Wilson 215699653d4eSeschrock nvlist_t * 2157fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 2158ee0eb9f2SEric Schrock boolean_t *l2cache, boolean_t *log) 2159ea8dc4b6Seschrock { 2160ea8dc4b6Seschrock char buf[MAXPATHLEN]; 2161ea8dc4b6Seschrock char *end; 2162573ca77eSGeorge Wilson nvlist_t *nvroot, *search, *ret; 2163ea8dc4b6Seschrock uint64_t guid; 2164ea8dc4b6Seschrock 2165573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2166573ca77eSGeorge Wilson 21670917b783Seschrock guid = strtoull(path, &end, 10); 2168ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 2169573ca77eSGeorge Wilson verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 217088ecc943SGeorge Wilson } else if (zpool_vdev_is_interior(path)) { 217188ecc943SGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 2172ea8dc4b6Seschrock } else if (path[0] != '/') { 2173ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 2174573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 2175ea8dc4b6Seschrock } else { 2176573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 2177ea8dc4b6Seschrock } 2178ea8dc4b6Seschrock 2179ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 2180ea8dc4b6Seschrock &nvroot) == 0); 2181ea8dc4b6Seschrock 2182a43d325bSek *avail_spare = B_FALSE; 2183fa94a07fSbrendan *l2cache = B_FALSE; 2184ee0eb9f2SEric Schrock if (log != NULL) 2185ee0eb9f2SEric Schrock *log = B_FALSE; 2186573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 2187573ca77eSGeorge Wilson nvlist_free(search); 2188573ca77eSGeorge Wilson 2189573ca77eSGeorge Wilson return (ret); 2190a43d325bSek } 2191a43d325bSek 219219397407SSherry Moore static int 219319397407SSherry Moore vdev_online(nvlist_t *nv) 219419397407SSherry Moore { 219519397407SSherry Moore uint64_t ival; 219619397407SSherry Moore 219719397407SSherry Moore if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 219819397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 219919397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 220019397407SSherry Moore return (0); 220119397407SSherry Moore 220219397407SSherry Moore return (1); 220319397407SSherry Moore } 220419397407SSherry Moore 220519397407SSherry Moore /* 220621ecdf64SLin Ling * Helper function for zpool_get_physpaths(). 220719397407SSherry Moore */ 2208753a6d45SSherry Moore static int 220921ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 2210753a6d45SSherry Moore size_t *bytes_written) 221119397407SSherry Moore { 2212753a6d45SSherry Moore size_t bytes_left, pos, rsz; 2213753a6d45SSherry Moore char *tmppath; 2214753a6d45SSherry Moore const char *format; 2215753a6d45SSherry Moore 2216753a6d45SSherry Moore if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 2217753a6d45SSherry Moore &tmppath) != 0) 2218753a6d45SSherry Moore return (EZFS_NODEVICE); 2219753a6d45SSherry Moore 2220753a6d45SSherry Moore pos = *bytes_written; 2221753a6d45SSherry Moore bytes_left = physpath_size - pos; 2222753a6d45SSherry Moore format = (pos == 0) ? "%s" : " %s"; 2223753a6d45SSherry Moore 2224753a6d45SSherry Moore rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 2225753a6d45SSherry Moore *bytes_written += rsz; 2226753a6d45SSherry Moore 2227753a6d45SSherry Moore if (rsz >= bytes_left) { 2228753a6d45SSherry Moore /* if physpath was not copied properly, clear it */ 2229753a6d45SSherry Moore if (bytes_left != 0) { 2230753a6d45SSherry Moore physpath[pos] = 0; 2231753a6d45SSherry Moore } 2232753a6d45SSherry Moore return (EZFS_NOSPC); 2233753a6d45SSherry Moore } 2234753a6d45SSherry Moore return (0); 2235753a6d45SSherry Moore } 2236753a6d45SSherry Moore 223721ecdf64SLin Ling static int 223821ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 223921ecdf64SLin Ling size_t *rsz, boolean_t is_spare) 224021ecdf64SLin Ling { 224121ecdf64SLin Ling char *type; 224221ecdf64SLin Ling int ret; 224321ecdf64SLin Ling 224421ecdf64SLin Ling if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 224521ecdf64SLin Ling return (EZFS_INVALCONFIG); 224621ecdf64SLin Ling 224721ecdf64SLin Ling if (strcmp(type, VDEV_TYPE_DISK) == 0) { 224821ecdf64SLin Ling /* 224921ecdf64SLin Ling * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 225021ecdf64SLin Ling * For a spare vdev, we only want to boot from the active 225121ecdf64SLin Ling * spare device. 225221ecdf64SLin Ling */ 225321ecdf64SLin Ling if (is_spare) { 225421ecdf64SLin Ling uint64_t spare = 0; 225521ecdf64SLin Ling (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 225621ecdf64SLin Ling &spare); 225721ecdf64SLin Ling if (!spare) 225821ecdf64SLin Ling return (EZFS_INVALCONFIG); 225921ecdf64SLin Ling } 226021ecdf64SLin Ling 226121ecdf64SLin Ling if (vdev_online(nv)) { 226221ecdf64SLin Ling if ((ret = vdev_get_one_physpath(nv, physpath, 226321ecdf64SLin Ling phypath_size, rsz)) != 0) 226421ecdf64SLin Ling return (ret); 226521ecdf64SLin Ling } 226621ecdf64SLin Ling } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 226721ecdf64SLin Ling strcmp(type, VDEV_TYPE_REPLACING) == 0 || 226821ecdf64SLin Ling (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 226921ecdf64SLin Ling nvlist_t **child; 227021ecdf64SLin Ling uint_t count; 227121ecdf64SLin Ling int i, ret; 227221ecdf64SLin Ling 227321ecdf64SLin Ling if (nvlist_lookup_nvlist_array(nv, 227421ecdf64SLin Ling ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 227521ecdf64SLin Ling return (EZFS_INVALCONFIG); 227621ecdf64SLin Ling 227721ecdf64SLin Ling for (i = 0; i < count; i++) { 227821ecdf64SLin Ling ret = vdev_get_physpaths(child[i], physpath, 227921ecdf64SLin Ling phypath_size, rsz, is_spare); 228021ecdf64SLin Ling if (ret == EZFS_NOSPC) 228121ecdf64SLin Ling return (ret); 228221ecdf64SLin Ling } 228321ecdf64SLin Ling } 228421ecdf64SLin Ling 228521ecdf64SLin Ling return (EZFS_POOL_INVALARG); 228621ecdf64SLin Ling } 228721ecdf64SLin Ling 2288753a6d45SSherry Moore /* 2289753a6d45SSherry Moore * Get phys_path for a root pool config. 2290753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 2291753a6d45SSherry Moore */ 2292753a6d45SSherry Moore static int 2293753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 2294753a6d45SSherry Moore { 2295753a6d45SSherry Moore size_t rsz; 229619397407SSherry Moore nvlist_t *vdev_root; 229719397407SSherry Moore nvlist_t **child; 229819397407SSherry Moore uint_t count; 2299753a6d45SSherry Moore char *type; 2300753a6d45SSherry Moore 2301753a6d45SSherry Moore rsz = 0; 2302753a6d45SSherry Moore 2303753a6d45SSherry Moore if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2304753a6d45SSherry Moore &vdev_root) != 0) 2305753a6d45SSherry Moore return (EZFS_INVALCONFIG); 2306753a6d45SSherry Moore 2307753a6d45SSherry Moore if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 2308753a6d45SSherry Moore nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 2309753a6d45SSherry Moore &child, &count) != 0) 2310753a6d45SSherry Moore return (EZFS_INVALCONFIG); 231119397407SSherry Moore 231219397407SSherry Moore /* 2313753a6d45SSherry Moore * root pool can not have EFI labeled disks and can only have 2314753a6d45SSherry Moore * a single top-level vdev. 231519397407SSherry Moore */ 2316753a6d45SSherry Moore if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 2317753a6d45SSherry Moore pool_uses_efi(vdev_root)) 2318753a6d45SSherry Moore return (EZFS_POOL_INVALARG); 231919397407SSherry Moore 232021ecdf64SLin Ling (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 232121ecdf64SLin Ling B_FALSE); 232219397407SSherry Moore 2323753a6d45SSherry Moore /* No online devices */ 2324753a6d45SSherry Moore if (rsz == 0) 2325753a6d45SSherry Moore return (EZFS_NODEVICE); 2326753a6d45SSherry Moore 232719397407SSherry Moore return (0); 232819397407SSherry Moore } 232919397407SSherry Moore 2330753a6d45SSherry Moore /* 2331753a6d45SSherry Moore * Get phys_path for a root pool 2332753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 2333753a6d45SSherry Moore */ 2334753a6d45SSherry Moore int 2335753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 2336753a6d45SSherry Moore { 2337753a6d45SSherry Moore return (zpool_get_config_physpath(zhp->zpool_config, physpath, 2338753a6d45SSherry Moore phypath_size)); 2339753a6d45SSherry Moore } 2340753a6d45SSherry Moore 2341573ca77eSGeorge Wilson /* 2342573ca77eSGeorge Wilson * If the device has being dynamically expanded then we need to relabel 2343573ca77eSGeorge Wilson * the disk to use the new unallocated space. 2344573ca77eSGeorge Wilson */ 2345573ca77eSGeorge Wilson static int 2346573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 2347573ca77eSGeorge Wilson { 2348573ca77eSGeorge Wilson char path[MAXPATHLEN]; 2349573ca77eSGeorge Wilson char errbuf[1024]; 2350573ca77eSGeorge Wilson int fd, error; 2351573ca77eSGeorge Wilson int (*_efi_use_whole_disk)(int); 2352573ca77eSGeorge Wilson 2353573ca77eSGeorge Wilson if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 2354573ca77eSGeorge Wilson "efi_use_whole_disk")) == NULL) 2355573ca77eSGeorge Wilson return (-1); 2356573ca77eSGeorge Wilson 2357573ca77eSGeorge Wilson (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 2358573ca77eSGeorge Wilson 2359573ca77eSGeorge Wilson if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 2360573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 2361573ca77eSGeorge Wilson "relabel '%s': unable to open device"), name); 2362573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 2363573ca77eSGeorge Wilson } 2364573ca77eSGeorge Wilson 2365573ca77eSGeorge Wilson /* 2366573ca77eSGeorge Wilson * It's possible that we might encounter an error if the device 2367573ca77eSGeorge Wilson * does not have any unallocated space left. If so, we simply 2368573ca77eSGeorge Wilson * ignore that error and continue on. 2369573ca77eSGeorge Wilson */ 2370573ca77eSGeorge Wilson error = _efi_use_whole_disk(fd); 2371573ca77eSGeorge Wilson (void) close(fd); 2372573ca77eSGeorge Wilson if (error && error != VT_ENOSPC) { 2373573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 2374573ca77eSGeorge Wilson "relabel '%s': unable to read disk capacity"), name); 2375573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 2376573ca77eSGeorge Wilson } 2377573ca77eSGeorge Wilson return (0); 2378573ca77eSGeorge Wilson } 2379573ca77eSGeorge Wilson 2380fa9e4066Sahrens /* 23813d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 23823d7072f8Seschrock * ZFS_ONLINE_* flags. 2383fa9e4066Sahrens */ 2384fa9e4066Sahrens int 23853d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 23863d7072f8Seschrock vdev_state_t *newstate) 2387fa9e4066Sahrens { 2388fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2389fa9e4066Sahrens char msg[1024]; 239099653d4eSeschrock nvlist_t *tgt; 2391573ca77eSGeorge Wilson boolean_t avail_spare, l2cache, islog; 239299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2393fa9e4066Sahrens 2394573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND) { 2395573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2396573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 2397573ca77eSGeorge Wilson } else { 2398573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2399573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot online %s"), path); 2400573ca77eSGeorge Wilson } 2401ea8dc4b6Seschrock 2402fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2403ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2404573ca77eSGeorge Wilson &islog)) == NULL) 240599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2406fa9e4066Sahrens 240799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2408fa9e4066Sahrens 2409069f55e2SEric Schrock if (avail_spare) 2410a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2411a43d325bSek 2412573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND || 2413573ca77eSGeorge Wilson zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 2414573ca77eSGeorge Wilson char *pathname = NULL; 2415573ca77eSGeorge Wilson uint64_t wholedisk = 0; 2416573ca77eSGeorge Wilson 2417573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 2418573ca77eSGeorge Wilson &wholedisk); 2419573ca77eSGeorge Wilson verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 2420573ca77eSGeorge Wilson &pathname) == 0); 2421573ca77eSGeorge Wilson 2422573ca77eSGeorge Wilson /* 2423573ca77eSGeorge Wilson * XXX - L2ARC 1.0 devices can't support expansion. 2424573ca77eSGeorge Wilson */ 2425573ca77eSGeorge Wilson if (l2cache) { 2426573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2427573ca77eSGeorge Wilson "cannot expand cache devices")); 2428573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 2429573ca77eSGeorge Wilson } 2430573ca77eSGeorge Wilson 2431573ca77eSGeorge Wilson if (wholedisk) { 2432573ca77eSGeorge Wilson pathname += strlen(DISK_ROOT) + 1; 2433cb04b873SMark J Musante (void) zpool_relabel_disk(hdl, pathname); 2434573ca77eSGeorge Wilson } 2435573ca77eSGeorge Wilson } 2436573ca77eSGeorge Wilson 24373d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 24383d7072f8Seschrock zc.zc_obj = flags; 2439fa9e4066Sahrens 2440cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) { 24411195e687SMark J Musante if (errno == EINVAL) { 24421195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split " 24431195e687SMark J Musante "from this pool into a new one. Use '%s' " 24441195e687SMark J Musante "instead"), "zpool detach"); 24451195e687SMark J Musante return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg)); 24461195e687SMark J Musante } 24473d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 24481195e687SMark J Musante } 24493d7072f8Seschrock 24503d7072f8Seschrock *newstate = zc.zc_cookie; 24513d7072f8Seschrock return (0); 2452fa9e4066Sahrens } 2453fa9e4066Sahrens 2454fa9e4066Sahrens /* 2455fa9e4066Sahrens * Take the specified vdev offline 2456fa9e4066Sahrens */ 2457fa9e4066Sahrens int 24583d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2459fa9e4066Sahrens { 2460fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2461fa9e4066Sahrens char msg[1024]; 246299653d4eSeschrock nvlist_t *tgt; 2463fa94a07fSbrendan boolean_t avail_spare, l2cache; 246499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2465fa9e4066Sahrens 2466ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2467ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 2468ea8dc4b6Seschrock 2469fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2470ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2471ee0eb9f2SEric Schrock NULL)) == NULL) 247299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 247399653d4eSeschrock 247499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2475fa9e4066Sahrens 2476069f55e2SEric Schrock if (avail_spare) 2477a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2478a43d325bSek 24793d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 24803d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 24813d7072f8Seschrock 2482cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 24833d7072f8Seschrock return (0); 24843d7072f8Seschrock 24853d7072f8Seschrock switch (errno) { 24863d7072f8Seschrock case EBUSY: 24873d7072f8Seschrock 24883d7072f8Seschrock /* 24893d7072f8Seschrock * There are no other replicas of this device. 24903d7072f8Seschrock */ 24913d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 24923d7072f8Seschrock 2493e6ca193dSGeorge Wilson case EEXIST: 2494e6ca193dSGeorge Wilson /* 2495e6ca193dSGeorge Wilson * The log device has unplayed logs 2496e6ca193dSGeorge Wilson */ 2497e6ca193dSGeorge Wilson return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 2498e6ca193dSGeorge Wilson 24993d7072f8Seschrock default: 25003d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 25013d7072f8Seschrock } 25023d7072f8Seschrock } 25033d7072f8Seschrock 25043d7072f8Seschrock /* 25053d7072f8Seschrock * Mark the given vdev faulted. 25063d7072f8Seschrock */ 25073d7072f8Seschrock int 2508069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 25093d7072f8Seschrock { 25103d7072f8Seschrock zfs_cmd_t zc = { 0 }; 25113d7072f8Seschrock char msg[1024]; 25123d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 25133d7072f8Seschrock 25143d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 25153d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 2516441d80aaSlling 25173d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25183d7072f8Seschrock zc.zc_guid = guid; 25193d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 2520069f55e2SEric Schrock zc.zc_obj = aux; 25213d7072f8Seschrock 2522cb04b873SMark J Musante if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2523fa9e4066Sahrens return (0); 2524fa9e4066Sahrens 2525fa9e4066Sahrens switch (errno) { 252699653d4eSeschrock case EBUSY: 2527fa9e4066Sahrens 2528fa9e4066Sahrens /* 2529fa9e4066Sahrens * There are no other replicas of this device. 2530fa9e4066Sahrens */ 253199653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 2532fa9e4066Sahrens 253399653d4eSeschrock default: 253499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2535fa9e4066Sahrens } 25363d7072f8Seschrock 25373d7072f8Seschrock } 25383d7072f8Seschrock 25393d7072f8Seschrock /* 25403d7072f8Seschrock * Mark the given vdev degraded. 25413d7072f8Seschrock */ 25423d7072f8Seschrock int 2543069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 25443d7072f8Seschrock { 25453d7072f8Seschrock zfs_cmd_t zc = { 0 }; 25463d7072f8Seschrock char msg[1024]; 25473d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 25483d7072f8Seschrock 25493d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 25503d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 25513d7072f8Seschrock 25523d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25533d7072f8Seschrock zc.zc_guid = guid; 25543d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 2555069f55e2SEric Schrock zc.zc_obj = aux; 25563d7072f8Seschrock 2557cb04b873SMark J Musante if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 25583d7072f8Seschrock return (0); 25593d7072f8Seschrock 25603d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 256199653d4eSeschrock } 256299653d4eSeschrock 256399653d4eSeschrock /* 256499653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 256599653d4eSeschrock * a hot spare. 256699653d4eSeschrock */ 256799653d4eSeschrock static boolean_t 256899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 256999653d4eSeschrock { 257099653d4eSeschrock nvlist_t **child; 257199653d4eSeschrock uint_t c, children; 257299653d4eSeschrock char *type; 257399653d4eSeschrock 257499653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 257599653d4eSeschrock &children) == 0) { 257699653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 257799653d4eSeschrock &type) == 0); 257899653d4eSeschrock 257999653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 258099653d4eSeschrock children == 2 && child[which] == tgt) 258199653d4eSeschrock return (B_TRUE); 258299653d4eSeschrock 258399653d4eSeschrock for (c = 0; c < children; c++) 258499653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 258599653d4eSeschrock return (B_TRUE); 258699653d4eSeschrock } 258799653d4eSeschrock 258899653d4eSeschrock return (B_FALSE); 2589fa9e4066Sahrens } 2590fa9e4066Sahrens 2591fa9e4066Sahrens /* 2592fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 25938654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2594fa9e4066Sahrens */ 2595fa9e4066Sahrens int 2596fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2597fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2598fa9e4066Sahrens { 2599fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2600fa9e4066Sahrens char msg[1024]; 2601fa9e4066Sahrens int ret; 260299653d4eSeschrock nvlist_t *tgt; 2603ee0eb9f2SEric Schrock boolean_t avail_spare, l2cache, islog; 2604ee0eb9f2SEric Schrock uint64_t val; 2605cb04b873SMark J Musante char *newname; 260699653d4eSeschrock nvlist_t **child; 260799653d4eSeschrock uint_t children; 260899653d4eSeschrock nvlist_t *config_root; 260999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 26104263d13fSGeorge Wilson boolean_t rootpool = zpool_is_bootable(zhp); 2611fa9e4066Sahrens 2612ea8dc4b6Seschrock if (replacing) 2613ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2614ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 2615ea8dc4b6Seschrock else 2616ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2617ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 2618ea8dc4b6Seschrock 2619b5b76fecSGeorge Wilson /* 2620b5b76fecSGeorge Wilson * If this is a root pool, make sure that we're not attaching an 2621b5b76fecSGeorge Wilson * EFI labeled device. 2622b5b76fecSGeorge Wilson */ 2623b5b76fecSGeorge Wilson if (rootpool && pool_uses_efi(nvroot)) { 2624b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2625b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root pools.")); 2626b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 2627b5b76fecSGeorge Wilson } 2628b5b76fecSGeorge Wilson 2629fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2630ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 2631ee0eb9f2SEric Schrock &islog)) == 0) 263299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 263399653d4eSeschrock 2634a43d325bSek if (avail_spare) 263599653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 263699653d4eSeschrock 2637fa94a07fSbrendan if (l2cache) 2638fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2639fa94a07fSbrendan 264099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2641fa9e4066Sahrens zc.zc_cookie = replacing; 2642fa9e4066Sahrens 264399653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 264499653d4eSeschrock &child, &children) != 0 || children != 1) { 264599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 264699653d4eSeschrock "new device must be a single disk")); 264799653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 264899653d4eSeschrock } 264999653d4eSeschrock 265099653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 265199653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 265299653d4eSeschrock 265388ecc943SGeorge Wilson if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 26540430f8daSeschrock return (-1); 26550430f8daSeschrock 265699653d4eSeschrock /* 265799653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 265899653d4eSeschrock * replace it with another hot spare. 265999653d4eSeschrock */ 266099653d4eSeschrock if (replacing && 266199653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 2662ee0eb9f2SEric Schrock (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 2663ee0eb9f2SEric Schrock NULL) == NULL || !avail_spare) && 2664ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 1)) { 266599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 266699653d4eSeschrock "can only be replaced by another hot spare")); 26670430f8daSeschrock free(newname); 266899653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 266999653d4eSeschrock } 267099653d4eSeschrock 26710430f8daSeschrock free(newname); 26720430f8daSeschrock 2673990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 267499653d4eSeschrock return (-1); 2675fa9e4066Sahrens 2676cb04b873SMark J Musante ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2677fa9e4066Sahrens 2678e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2679fa9e4066Sahrens 2680b5b76fecSGeorge Wilson if (ret == 0) { 2681b5b76fecSGeorge Wilson if (rootpool) { 268221ecdf64SLin Ling /* 268321ecdf64SLin Ling * XXX need a better way to prevent user from 268421ecdf64SLin Ling * booting up a half-baked vdev. 268521ecdf64SLin Ling */ 268621ecdf64SLin Ling (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 268721ecdf64SLin Ling "sure to wait until resilver is done " 268821ecdf64SLin Ling "before rebooting.\n")); 2689b5b76fecSGeorge Wilson } 2690fa9e4066Sahrens return (0); 2691b5b76fecSGeorge Wilson } 2692fa9e4066Sahrens 2693fa9e4066Sahrens switch (errno) { 2694ea8dc4b6Seschrock case ENOTSUP: 2695fa9e4066Sahrens /* 2696fa9e4066Sahrens * Can't attach to or replace this type of vdev. 2697fa9e4066Sahrens */ 26988654d025Sperrin if (replacing) { 2699cb04b873SMark J Musante uint64_t version = zpool_get_prop_int(zhp, 2700cb04b873SMark J Musante ZPOOL_PROP_VERSION, NULL); 2701cb04b873SMark J Musante 2702ee0eb9f2SEric Schrock if (islog) 27038654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27048654d025Sperrin "cannot replace a log with a spare")); 2705cb04b873SMark J Musante else if (version >= SPA_VERSION_MULTI_REPLACE) 2706cb04b873SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2707cb04b873SMark J Musante "already in replacing/spare config; wait " 2708cb04b873SMark J Musante "for completion or use 'zpool detach'")); 27098654d025Sperrin else 27108654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 27118654d025Sperrin "cannot replace a replacing device")); 27128654d025Sperrin } else { 271399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 271499653d4eSeschrock "can only attach to mirrors and top-level " 271599653d4eSeschrock "disks")); 27168654d025Sperrin } 271799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2718fa9e4066Sahrens break; 2719fa9e4066Sahrens 2720ea8dc4b6Seschrock case EINVAL: 2721fa9e4066Sahrens /* 2722fa9e4066Sahrens * The new device must be a single disk. 2723fa9e4066Sahrens */ 272499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 272599653d4eSeschrock "new device must be a single disk")); 272699653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2727fa9e4066Sahrens break; 2728fa9e4066Sahrens 2729ea8dc4b6Seschrock case EBUSY: 273099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 273199653d4eSeschrock new_disk); 273299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2733fa9e4066Sahrens break; 2734fa9e4066Sahrens 2735ea8dc4b6Seschrock case EOVERFLOW: 2736fa9e4066Sahrens /* 2737fa9e4066Sahrens * The new device is too small. 2738fa9e4066Sahrens */ 273999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 274099653d4eSeschrock "device is too small")); 274199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2742fa9e4066Sahrens break; 2743fa9e4066Sahrens 2744ea8dc4b6Seschrock case EDOM: 2745fa9e4066Sahrens /* 2746fa9e4066Sahrens * The new device has a different alignment requirement. 2747fa9e4066Sahrens */ 274899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 274999653d4eSeschrock "devices have different sector alignment")); 275099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2751fa9e4066Sahrens break; 2752fa9e4066Sahrens 2753ea8dc4b6Seschrock case ENAMETOOLONG: 2754fa9e4066Sahrens /* 2755fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 2756fa9e4066Sahrens */ 275799653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2758fa9e4066Sahrens break; 2759fa9e4066Sahrens 2760ea8dc4b6Seschrock default: 276199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2762fa9e4066Sahrens } 2763fa9e4066Sahrens 276499653d4eSeschrock return (-1); 2765fa9e4066Sahrens } 2766fa9e4066Sahrens 2767fa9e4066Sahrens /* 2768fa9e4066Sahrens * Detach the specified device. 2769fa9e4066Sahrens */ 2770fa9e4066Sahrens int 2771fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2772fa9e4066Sahrens { 2773fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2774fa9e4066Sahrens char msg[1024]; 277599653d4eSeschrock nvlist_t *tgt; 2776fa94a07fSbrendan boolean_t avail_spare, l2cache; 277799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2778fa9e4066Sahrens 2779ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2780ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 2781ea8dc4b6Seschrock 2782fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2783ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2784ee0eb9f2SEric Schrock NULL)) == 0) 278599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2786fa9e4066Sahrens 2787a43d325bSek if (avail_spare) 278899653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 278999653d4eSeschrock 2790fa94a07fSbrendan if (l2cache) 2791fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2792fa94a07fSbrendan 279399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 279499653d4eSeschrock 2795ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2796fa9e4066Sahrens return (0); 2797fa9e4066Sahrens 2798fa9e4066Sahrens switch (errno) { 2799fa9e4066Sahrens 2800ea8dc4b6Seschrock case ENOTSUP: 2801fa9e4066Sahrens /* 2802fa9e4066Sahrens * Can't detach from this type of vdev. 2803fa9e4066Sahrens */ 280499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 280599653d4eSeschrock "applicable to mirror and replacing vdevs")); 2806cb04b873SMark J Musante (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2807fa9e4066Sahrens break; 2808fa9e4066Sahrens 2809ea8dc4b6Seschrock case EBUSY: 2810fa9e4066Sahrens /* 2811fa9e4066Sahrens * There are no other replicas of this device. 2812fa9e4066Sahrens */ 281399653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2814fa9e4066Sahrens break; 2815fa9e4066Sahrens 2816ea8dc4b6Seschrock default: 281799653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2818ea8dc4b6Seschrock } 2819ea8dc4b6Seschrock 282099653d4eSeschrock return (-1); 282199653d4eSeschrock } 282299653d4eSeschrock 28231195e687SMark J Musante /* 28241195e687SMark J Musante * Find a mirror vdev in the source nvlist. 28251195e687SMark J Musante * 28261195e687SMark J Musante * The mchild array contains a list of disks in one of the top-level mirrors 28271195e687SMark J Musante * of the source pool. The schild array contains a list of disks that the 28281195e687SMark J Musante * user specified on the command line. We loop over the mchild array to 28291195e687SMark J Musante * see if any entry in the schild array matches. 28301195e687SMark J Musante * 28311195e687SMark J Musante * If a disk in the mchild array is found in the schild array, we return 28321195e687SMark J Musante * the index of that entry. Otherwise we return -1. 28331195e687SMark J Musante */ 28341195e687SMark J Musante static int 28351195e687SMark J Musante find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren, 28361195e687SMark J Musante nvlist_t **schild, uint_t schildren) 28371195e687SMark J Musante { 28381195e687SMark J Musante uint_t mc; 28391195e687SMark J Musante 28401195e687SMark J Musante for (mc = 0; mc < mchildren; mc++) { 28411195e687SMark J Musante uint_t sc; 28421195e687SMark J Musante char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp, 28431195e687SMark J Musante mchild[mc], B_FALSE); 28441195e687SMark J Musante 28451195e687SMark J Musante for (sc = 0; sc < schildren; sc++) { 28461195e687SMark J Musante char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp, 28471195e687SMark J Musante schild[sc], B_FALSE); 28481195e687SMark J Musante boolean_t result = (strcmp(mpath, spath) == 0); 28491195e687SMark J Musante 28501195e687SMark J Musante free(spath); 28511195e687SMark J Musante if (result) { 28521195e687SMark J Musante free(mpath); 28531195e687SMark J Musante return (mc); 28541195e687SMark J Musante } 28551195e687SMark J Musante } 28561195e687SMark J Musante 28571195e687SMark J Musante free(mpath); 28581195e687SMark J Musante } 28591195e687SMark J Musante 28601195e687SMark J Musante return (-1); 28611195e687SMark J Musante } 28621195e687SMark J Musante 28631195e687SMark J Musante /* 28641195e687SMark J Musante * Split a mirror pool. If newroot points to null, then a new nvlist 28651195e687SMark J Musante * is generated and it is the responsibility of the caller to free it. 28661195e687SMark J Musante */ 28671195e687SMark J Musante int 28681195e687SMark J Musante zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot, 28691195e687SMark J Musante nvlist_t *props, splitflags_t flags) 28701195e687SMark J Musante { 28711195e687SMark J Musante zfs_cmd_t zc = { 0 }; 28721195e687SMark J Musante char msg[1024]; 28731195e687SMark J Musante nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL; 28741195e687SMark J Musante nvlist_t **varray = NULL, *zc_props = NULL; 28751195e687SMark J Musante uint_t c, children, newchildren, lastlog = 0, vcount, found = 0; 28761195e687SMark J Musante libzfs_handle_t *hdl = zhp->zpool_hdl; 28771195e687SMark J Musante uint64_t vers; 28781195e687SMark J Musante boolean_t freelist = B_FALSE, memory_err = B_TRUE; 28791195e687SMark J Musante int retval = 0; 28801195e687SMark J Musante 28811195e687SMark J Musante (void) snprintf(msg, sizeof (msg), 28821195e687SMark J Musante dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name); 28831195e687SMark J Musante 28841195e687SMark J Musante if (!zpool_name_valid(hdl, B_FALSE, newname)) 28851195e687SMark J Musante return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 28861195e687SMark J Musante 28871195e687SMark J Musante if ((config = zpool_get_config(zhp, NULL)) == NULL) { 28881195e687SMark J Musante (void) fprintf(stderr, gettext("Internal error: unable to " 28891195e687SMark J Musante "retrieve pool configuration\n")); 28901195e687SMark J Musante return (-1); 28911195e687SMark J Musante } 28921195e687SMark J Musante 28931195e687SMark J Musante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) 28941195e687SMark J Musante == 0); 28951195e687SMark J Musante verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0); 28961195e687SMark J Musante 28971195e687SMark J Musante if (props) { 2898f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 28991195e687SMark J Musante if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name, 2900f9af39baSGeorge Wilson props, vers, flags, msg)) == NULL) 29011195e687SMark J Musante return (-1); 29021195e687SMark J Musante } 29031195e687SMark J Musante 29041195e687SMark J Musante if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, 29051195e687SMark J Musante &children) != 0) { 29061195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29071195e687SMark J Musante "Source pool is missing vdev tree")); 29081195e687SMark J Musante if (zc_props) 29091195e687SMark J Musante nvlist_free(zc_props); 29101195e687SMark J Musante return (-1); 29111195e687SMark J Musante } 29121195e687SMark J Musante 29131195e687SMark J Musante varray = zfs_alloc(hdl, children * sizeof (nvlist_t *)); 29141195e687SMark J Musante vcount = 0; 29151195e687SMark J Musante 29161195e687SMark J Musante if (*newroot == NULL || 29171195e687SMark J Musante nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, 29181195e687SMark J Musante &newchild, &newchildren) != 0) 29191195e687SMark J Musante newchildren = 0; 29201195e687SMark J Musante 29211195e687SMark J Musante for (c = 0; c < children; c++) { 29221195e687SMark J Musante uint64_t is_log = B_FALSE, is_hole = B_FALSE; 29231195e687SMark J Musante char *type; 29241195e687SMark J Musante nvlist_t **mchild, *vdev; 29251195e687SMark J Musante uint_t mchildren; 29261195e687SMark J Musante int entry; 29271195e687SMark J Musante 29281195e687SMark J Musante /* 29291195e687SMark J Musante * Unlike cache & spares, slogs are stored in the 29301195e687SMark J Musante * ZPOOL_CONFIG_CHILDREN array. We filter them out here. 29311195e687SMark J Musante */ 29321195e687SMark J Musante (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 29331195e687SMark J Musante &is_log); 29341195e687SMark J Musante (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 29351195e687SMark J Musante &is_hole); 29361195e687SMark J Musante if (is_log || is_hole) { 29371195e687SMark J Musante /* 29381195e687SMark J Musante * Create a hole vdev and put it in the config. 29391195e687SMark J Musante */ 29401195e687SMark J Musante if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0) 29411195e687SMark J Musante goto out; 29421195e687SMark J Musante if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, 29431195e687SMark J Musante VDEV_TYPE_HOLE) != 0) 29441195e687SMark J Musante goto out; 29451195e687SMark J Musante if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE, 29461195e687SMark J Musante 1) != 0) 29471195e687SMark J Musante goto out; 29481195e687SMark J Musante if (lastlog == 0) 29491195e687SMark J Musante lastlog = vcount; 29501195e687SMark J Musante varray[vcount++] = vdev; 29511195e687SMark J Musante continue; 29521195e687SMark J Musante } 29531195e687SMark J Musante lastlog = 0; 29541195e687SMark J Musante verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type) 29551195e687SMark J Musante == 0); 29561195e687SMark J Musante if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 29571195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 29581195e687SMark J Musante "Source pool must be composed only of mirrors\n")); 29591195e687SMark J Musante retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 29601195e687SMark J Musante goto out; 29611195e687SMark J Musante } 29621195e687SMark J Musante 29631195e687SMark J Musante verify(nvlist_lookup_nvlist_array(child[c], 29641195e687SMark J Musante ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0); 29651195e687SMark J Musante 29661195e687SMark J Musante /* find or add an entry for this top-level vdev */ 29671195e687SMark J Musante if (newchildren > 0 && 29681195e687SMark J Musante (entry = find_vdev_entry(zhp, mchild, mchildren, 29691195e687SMark J Musante newchild, newchildren)) >= 0) { 29701195e687SMark J Musante /* We found a disk that the user specified. */ 29711195e687SMark J Musante vdev = mchild[entry]; 29721195e687SMark J Musante ++found; 29731195e687SMark J Musante } else { 29741195e687SMark J Musante /* User didn't specify a disk for this vdev. */ 29751195e687SMark J Musante vdev = mchild[mchildren - 1]; 29761195e687SMark J Musante } 29771195e687SMark J Musante 29781195e687SMark J Musante if (nvlist_dup(vdev, &varray[vcount++], 0) != 0) 29791195e687SMark J Musante goto out; 29801195e687SMark J Musante } 29811195e687SMark J Musante 29821195e687SMark J Musante /* did we find every disk the user specified? */ 29831195e687SMark J Musante if (found != newchildren) { 29841195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must " 29851195e687SMark J Musante "include at most one disk from each mirror")); 29861195e687SMark J Musante retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 29871195e687SMark J Musante goto out; 29881195e687SMark J Musante } 29891195e687SMark J Musante 29901195e687SMark J Musante /* Prepare the nvlist for populating. */ 29911195e687SMark J Musante if (*newroot == NULL) { 29921195e687SMark J Musante if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0) 29931195e687SMark J Musante goto out; 29941195e687SMark J Musante freelist = B_TRUE; 29951195e687SMark J Musante if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE, 29961195e687SMark J Musante VDEV_TYPE_ROOT) != 0) 29971195e687SMark J Musante goto out; 29981195e687SMark J Musante } else { 29991195e687SMark J Musante verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0); 30001195e687SMark J Musante } 30011195e687SMark J Musante 30021195e687SMark J Musante /* Add all the children we found */ 30031195e687SMark J Musante if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray, 30041195e687SMark J Musante lastlog == 0 ? vcount : lastlog) != 0) 30051195e687SMark J Musante goto out; 30061195e687SMark J Musante 30071195e687SMark J Musante /* 30081195e687SMark J Musante * If we're just doing a dry run, exit now with success. 30091195e687SMark J Musante */ 30101195e687SMark J Musante if (flags.dryrun) { 30111195e687SMark J Musante memory_err = B_FALSE; 30121195e687SMark J Musante freelist = B_FALSE; 30131195e687SMark J Musante goto out; 30141195e687SMark J Musante } 30151195e687SMark J Musante 30161195e687SMark J Musante /* now build up the config list & call the ioctl */ 30171195e687SMark J Musante if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0) 30181195e687SMark J Musante goto out; 30191195e687SMark J Musante 30201195e687SMark J Musante if (nvlist_add_nvlist(newconfig, 30211195e687SMark J Musante ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 || 30221195e687SMark J Musante nvlist_add_string(newconfig, 30231195e687SMark J Musante ZPOOL_CONFIG_POOL_NAME, newname) != 0 || 30241195e687SMark J Musante nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0) 30251195e687SMark J Musante goto out; 30261195e687SMark J Musante 30271195e687SMark J Musante /* 30281195e687SMark J Musante * The new pool is automatically part of the namespace unless we 30291195e687SMark J Musante * explicitly export it. 30301195e687SMark J Musante */ 30311195e687SMark J Musante if (!flags.import) 30321195e687SMark J Musante zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT; 30331195e687SMark J Musante (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 30341195e687SMark J Musante (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string)); 30351195e687SMark J Musante if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0) 30361195e687SMark J Musante goto out; 30371195e687SMark J Musante if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 30381195e687SMark J Musante goto out; 30391195e687SMark J Musante 30401195e687SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) { 30411195e687SMark J Musante retval = zpool_standard_error(hdl, errno, msg); 30421195e687SMark J Musante goto out; 30431195e687SMark J Musante } 30441195e687SMark J Musante 30451195e687SMark J Musante freelist = B_FALSE; 30461195e687SMark J Musante memory_err = B_FALSE; 30471195e687SMark J Musante 30481195e687SMark J Musante out: 30491195e687SMark J Musante if (varray != NULL) { 30501195e687SMark J Musante int v; 30511195e687SMark J Musante 30521195e687SMark J Musante for (v = 0; v < vcount; v++) 30531195e687SMark J Musante nvlist_free(varray[v]); 30541195e687SMark J Musante free(varray); 30551195e687SMark J Musante } 30561195e687SMark J Musante zcmd_free_nvlists(&zc); 30571195e687SMark J Musante if (zc_props) 30581195e687SMark J Musante nvlist_free(zc_props); 30591195e687SMark J Musante if (newconfig) 30601195e687SMark J Musante nvlist_free(newconfig); 30611195e687SMark J Musante if (freelist) { 30621195e687SMark J Musante nvlist_free(*newroot); 30631195e687SMark J Musante *newroot = NULL; 30641195e687SMark J Musante } 30651195e687SMark J Musante 30661195e687SMark J Musante if (retval != 0) 30671195e687SMark J Musante return (retval); 30681195e687SMark J Musante 30691195e687SMark J Musante if (memory_err) 30701195e687SMark J Musante return (no_memory(hdl)); 30711195e687SMark J Musante 30721195e687SMark J Musante return (0); 30731195e687SMark J Musante } 30741195e687SMark J Musante 307599653d4eSeschrock /* 3076fa94a07fSbrendan * Remove the given device. Currently, this is supported only for hot spares 3077fa94a07fSbrendan * and level 2 cache devices. 307899653d4eSeschrock */ 307999653d4eSeschrock int 308099653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 308199653d4eSeschrock { 308299653d4eSeschrock zfs_cmd_t zc = { 0 }; 308399653d4eSeschrock char msg[1024]; 308499653d4eSeschrock nvlist_t *tgt; 308588ecc943SGeorge Wilson boolean_t avail_spare, l2cache, islog; 308699653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 308788ecc943SGeorge Wilson uint64_t version; 308899653d4eSeschrock 308999653d4eSeschrock (void) snprintf(msg, sizeof (msg), 309099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 309199653d4eSeschrock 309299653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3093ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 309488ecc943SGeorge Wilson &islog)) == 0) 309599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 309688ecc943SGeorge Wilson /* 309788ecc943SGeorge Wilson * XXX - this should just go away. 309888ecc943SGeorge Wilson */ 309988ecc943SGeorge Wilson if (!avail_spare && !l2cache && !islog) { 310099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 310188ecc943SGeorge Wilson "only inactive hot spares, cache, top-level, " 310288ecc943SGeorge Wilson "or log devices can be removed")); 310399653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 310499653d4eSeschrock } 310599653d4eSeschrock 310688ecc943SGeorge Wilson version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 310788ecc943SGeorge Wilson if (islog && version < SPA_VERSION_HOLES) { 310888ecc943SGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 310988ecc943SGeorge Wilson "pool must be upgrade to support log removal")); 311088ecc943SGeorge Wilson return (zfs_error(hdl, EZFS_BADVERSION, msg)); 311188ecc943SGeorge Wilson } 311288ecc943SGeorge Wilson 311399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 311499653d4eSeschrock 3115ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 311699653d4eSeschrock return (0); 311799653d4eSeschrock 311899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 3119ea8dc4b6Seschrock } 3120ea8dc4b6Seschrock 3121ea8dc4b6Seschrock /* 3122ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 3123ea8dc4b6Seschrock */ 3124ea8dc4b6Seschrock int 3125468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 3126ea8dc4b6Seschrock { 3127ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 3128ea8dc4b6Seschrock char msg[1024]; 312999653d4eSeschrock nvlist_t *tgt; 3130468c413aSTim Haley zpool_rewind_policy_t policy; 3131fa94a07fSbrendan boolean_t avail_spare, l2cache; 313299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 3133468c413aSTim Haley nvlist_t *nvi = NULL; 31344b964adaSGeorge Wilson int error; 3135ea8dc4b6Seschrock 3136ea8dc4b6Seschrock if (path) 3137ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 3138ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 3139e9dbad6fSeschrock path); 3140ea8dc4b6Seschrock else 3141ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 3142ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 3143ea8dc4b6Seschrock zhp->zpool_name); 3144ea8dc4b6Seschrock 3145ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 314699653d4eSeschrock if (path) { 3147fa94a07fSbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 3148ee0eb9f2SEric Schrock &l2cache, NULL)) == 0) 314999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 3150ea8dc4b6Seschrock 3151fa94a07fSbrendan /* 3152fa94a07fSbrendan * Don't allow error clearing for hot spares. Do allow 3153fa94a07fSbrendan * error clearing for l2cache devices. 3154fa94a07fSbrendan */ 3155a43d325bSek if (avail_spare) 315699653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 3157ea8dc4b6Seschrock 315899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 315999653d4eSeschrock &zc.zc_guid) == 0); 3160fa9e4066Sahrens } 3161fa9e4066Sahrens 3162468c413aSTim Haley zpool_get_rewind_policy(rewindnvl, &policy); 3163468c413aSTim Haley zc.zc_cookie = policy.zrp_request; 3164468c413aSTim Haley 316557f304caSGeorge Wilson if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0) 3166468c413aSTim Haley return (-1); 3167468c413aSTim Haley 3168cb04b873SMark J Musante if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0) 3169468c413aSTim Haley return (-1); 3170468c413aSTim Haley 31714b964adaSGeorge Wilson while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 && 31724b964adaSGeorge Wilson errno == ENOMEM) { 31734b964adaSGeorge Wilson if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 31744b964adaSGeorge Wilson zcmd_free_nvlists(&zc); 31754b964adaSGeorge Wilson return (-1); 31764b964adaSGeorge Wilson } 31774b964adaSGeorge Wilson } 31784b964adaSGeorge Wilson 31794b964adaSGeorge Wilson if (!error || ((policy.zrp_request & ZPOOL_TRY_REWIND) && 3180468c413aSTim Haley errno != EPERM && errno != EACCES)) { 3181468c413aSTim Haley if (policy.zrp_request & 3182468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 3183468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 3184468c413aSTim Haley zpool_rewind_exclaim(hdl, zc.zc_name, 3185468c413aSTim Haley ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 3186468c413aSTim Haley nvi); 3187468c413aSTim Haley nvlist_free(nvi); 3188468c413aSTim Haley } 3189468c413aSTim Haley zcmd_free_nvlists(&zc); 319099653d4eSeschrock return (0); 3191468c413aSTim Haley } 319299653d4eSeschrock 3193468c413aSTim Haley zcmd_free_nvlists(&zc); 319499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 3195fa9e4066Sahrens } 3196fa9e4066Sahrens 31973d7072f8Seschrock /* 31983d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 31993d7072f8Seschrock */ 32003d7072f8Seschrock int 32013d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 32023d7072f8Seschrock { 32033d7072f8Seschrock zfs_cmd_t zc = { 0 }; 32043d7072f8Seschrock char msg[1024]; 32053d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 32063d7072f8Seschrock 32073d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 32083d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 32093d7072f8Seschrock guid); 32103d7072f8Seschrock 32113d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 32123d7072f8Seschrock zc.zc_guid = guid; 321314f8ce41SVictor Latushkin zc.zc_cookie = ZPOOL_NO_REWIND; 32143d7072f8Seschrock 32153d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 32163d7072f8Seschrock return (0); 32173d7072f8Seschrock 32183d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 32193d7072f8Seschrock } 32203d7072f8Seschrock 3221e9103aaeSGarrett D'Amore /* 3222e9103aaeSGarrett D'Amore * Change the GUID for a pool. 3223e9103aaeSGarrett D'Amore */ 3224e9103aaeSGarrett D'Amore int 3225e9103aaeSGarrett D'Amore zpool_reguid(zpool_handle_t *zhp) 3226e9103aaeSGarrett D'Amore { 3227e9103aaeSGarrett D'Amore char msg[1024]; 3228e9103aaeSGarrett D'Amore libzfs_handle_t *hdl = zhp->zpool_hdl; 3229e9103aaeSGarrett D'Amore zfs_cmd_t zc = { 0 }; 3230e9103aaeSGarrett D'Amore 3231e9103aaeSGarrett D'Amore (void) snprintf(msg, sizeof (msg), 3232e9103aaeSGarrett D'Amore dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name); 3233e9103aaeSGarrett D'Amore 3234e9103aaeSGarrett D'Amore (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3235e9103aaeSGarrett D'Amore if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0) 3236e9103aaeSGarrett D'Amore return (0); 3237e9103aaeSGarrett D'Amore 3238e9103aaeSGarrett D'Amore return (zpool_standard_error(hdl, errno, msg)); 3239e9103aaeSGarrett D'Amore } 3240e9103aaeSGarrett D'Amore 32414263d13fSGeorge Wilson /* 32424263d13fSGeorge Wilson * Reopen the pool. 32434263d13fSGeorge Wilson */ 32444263d13fSGeorge Wilson int 32454263d13fSGeorge Wilson zpool_reopen(zpool_handle_t *zhp) 32464263d13fSGeorge Wilson { 32474263d13fSGeorge Wilson zfs_cmd_t zc = { 0 }; 32484263d13fSGeorge Wilson char msg[1024]; 32494263d13fSGeorge Wilson libzfs_handle_t *hdl = zhp->zpool_hdl; 32504263d13fSGeorge Wilson 32514263d13fSGeorge Wilson (void) snprintf(msg, sizeof (msg), 32524263d13fSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), 32534263d13fSGeorge Wilson zhp->zpool_name); 32544263d13fSGeorge Wilson 32554263d13fSGeorge Wilson (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 32564263d13fSGeorge Wilson if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0) 32574263d13fSGeorge Wilson return (0); 32584263d13fSGeorge Wilson return (zpool_standard_error(hdl, errno, msg)); 32594263d13fSGeorge Wilson } 32604263d13fSGeorge Wilson 3261c67d9675Seschrock /* 3262c67d9675Seschrock * Convert from a devid string to a path. 3263c67d9675Seschrock */ 3264c67d9675Seschrock static char * 3265c67d9675Seschrock devid_to_path(char *devid_str) 3266c67d9675Seschrock { 3267c67d9675Seschrock ddi_devid_t devid; 3268c67d9675Seschrock char *minor; 3269c67d9675Seschrock char *path; 3270c67d9675Seschrock devid_nmlist_t *list = NULL; 3271c67d9675Seschrock int ret; 3272c67d9675Seschrock 3273c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 3274c67d9675Seschrock return (NULL); 3275c67d9675Seschrock 3276c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 3277c67d9675Seschrock 3278c67d9675Seschrock devid_str_free(minor); 3279c67d9675Seschrock devid_free(devid); 3280c67d9675Seschrock 3281c67d9675Seschrock if (ret != 0) 3282c67d9675Seschrock return (NULL); 3283c67d9675Seschrock 328499653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 328599653d4eSeschrock return (NULL); 328699653d4eSeschrock 3287c67d9675Seschrock devid_free_nmlist(list); 3288c67d9675Seschrock 3289c67d9675Seschrock return (path); 3290c67d9675Seschrock } 3291c67d9675Seschrock 3292c67d9675Seschrock /* 3293c67d9675Seschrock * Convert from a path to a devid string. 3294c67d9675Seschrock */ 3295c67d9675Seschrock static char * 3296c67d9675Seschrock path_to_devid(const char *path) 3297c67d9675Seschrock { 3298c67d9675Seschrock int fd; 3299c67d9675Seschrock ddi_devid_t devid; 3300c67d9675Seschrock char *minor, *ret; 3301c67d9675Seschrock 3302c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 3303c67d9675Seschrock return (NULL); 3304c67d9675Seschrock 3305c67d9675Seschrock minor = NULL; 3306c67d9675Seschrock ret = NULL; 3307c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 3308c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 3309c67d9675Seschrock ret = devid_str_encode(devid, minor); 3310c67d9675Seschrock if (minor != NULL) 3311c67d9675Seschrock devid_str_free(minor); 3312c67d9675Seschrock devid_free(devid); 3313c67d9675Seschrock } 3314c67d9675Seschrock (void) close(fd); 3315c67d9675Seschrock 3316c67d9675Seschrock return (ret); 3317c67d9675Seschrock } 3318c67d9675Seschrock 3319c67d9675Seschrock /* 3320c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 3321c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 3322c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 3323c67d9675Seschrock */ 3324c67d9675Seschrock static void 3325c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 3326c67d9675Seschrock { 3327c67d9675Seschrock zfs_cmd_t zc = { 0 }; 3328c67d9675Seschrock 3329c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3330e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 3331c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 3332ea8dc4b6Seschrock &zc.zc_guid) == 0); 3333c67d9675Seschrock 333499653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 3335c67d9675Seschrock } 3336c67d9675Seschrock 3337c67d9675Seschrock /* 3338c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 3339c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 3340c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 3341c67d9675Seschrock * trailing 's0' slice name. 3342c67d9675Seschrock * 3343c67d9675Seschrock * This routine is also responsible for identifying when disks have been 3344c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 3345c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 3346c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 3347c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 3348c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 3349c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 3350c67d9675Seschrock * of these checks. 3351c67d9675Seschrock */ 3352c67d9675Seschrock char * 335388ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 335488ecc943SGeorge Wilson boolean_t verbose) 3355c67d9675Seschrock { 3356c67d9675Seschrock char *path, *devid; 3357ea8dc4b6Seschrock uint64_t value; 3358ea8dc4b6Seschrock char buf[64]; 33593d7072f8Seschrock vdev_stat_t *vs; 33603d7072f8Seschrock uint_t vsc; 3361c67d9675Seschrock 3362ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 3363ea8dc4b6Seschrock &value) == 0) { 3364ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 3365ea8dc4b6Seschrock &value) == 0); 33665ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 33675ad82045Snd (u_longlong_t)value); 3368ea8dc4b6Seschrock path = buf; 3369ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 3370c67d9675Seschrock 33713d7072f8Seschrock /* 33723d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 33733d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 33743d7072f8Seschrock * open a misbehaving device, which can have undesirable 33753d7072f8Seschrock * effects. 33763d7072f8Seschrock */ 33773f9d6ad7SLin Ling if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 33783d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 33793d7072f8Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 33803d7072f8Seschrock zhp != NULL && 3381c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 3382c67d9675Seschrock /* 3383c67d9675Seschrock * Determine if the current path is correct. 3384c67d9675Seschrock */ 3385c67d9675Seschrock char *newdevid = path_to_devid(path); 3386c67d9675Seschrock 3387c67d9675Seschrock if (newdevid == NULL || 3388c67d9675Seschrock strcmp(devid, newdevid) != 0) { 3389c67d9675Seschrock char *newpath; 3390c67d9675Seschrock 3391c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 3392c67d9675Seschrock /* 3393c67d9675Seschrock * Update the path appropriately. 3394c67d9675Seschrock */ 3395c67d9675Seschrock set_path(zhp, nv, newpath); 339699653d4eSeschrock if (nvlist_add_string(nv, 339799653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 339899653d4eSeschrock verify(nvlist_lookup_string(nv, 339999653d4eSeschrock ZPOOL_CONFIG_PATH, 340099653d4eSeschrock &path) == 0); 3401c67d9675Seschrock free(newpath); 3402c67d9675Seschrock } 3403c67d9675Seschrock } 3404c67d9675Seschrock 340599653d4eSeschrock if (newdevid) 340699653d4eSeschrock devid_str_free(newdevid); 3407c67d9675Seschrock } 3408c67d9675Seschrock 3409c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 3410c67d9675Seschrock path += 9; 3411c67d9675Seschrock 3412c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 3413ea8dc4b6Seschrock &value) == 0 && value) { 34143fdda499SJohn Harres int pathlen = strlen(path); 341599653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 34163fdda499SJohn Harres 34173fdda499SJohn Harres /* 34183fdda499SJohn Harres * If it starts with c#, and ends with "s0", chop 34193fdda499SJohn Harres * the "s0" off, or if it ends with "s0/old", remove 34203fdda499SJohn Harres * the "s0" from the middle. 34213fdda499SJohn Harres */ 34223fdda499SJohn Harres if (CTD_CHECK(tmp)) { 34233fdda499SJohn Harres if (strcmp(&tmp[pathlen - 2], "s0") == 0) { 34243fdda499SJohn Harres tmp[pathlen - 2] = '\0'; 34253fdda499SJohn Harres } else if (pathlen > 6 && 34263fdda499SJohn Harres strcmp(&tmp[pathlen - 6], "s0/old") == 0) { 34273fdda499SJohn Harres (void) strcpy(&tmp[pathlen - 6], 34283fdda499SJohn Harres "/old"); 34293fdda499SJohn Harres } 34303fdda499SJohn Harres } 3431c67d9675Seschrock return (tmp); 3432c67d9675Seschrock } 3433c67d9675Seschrock } else { 3434c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 343599653d4eSeschrock 343699653d4eSeschrock /* 343799653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 343899653d4eSeschrock */ 343999653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 344099653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 344199653d4eSeschrock &value) == 0); 344299653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 34435ad82045Snd (u_longlong_t)value); 344499653d4eSeschrock path = buf; 344599653d4eSeschrock } 344688ecc943SGeorge Wilson 344788ecc943SGeorge Wilson /* 344888ecc943SGeorge Wilson * We identify each top-level vdev by using a <type-id> 344988ecc943SGeorge Wilson * naming convention. 345088ecc943SGeorge Wilson */ 345188ecc943SGeorge Wilson if (verbose) { 345288ecc943SGeorge Wilson uint64_t id; 345388ecc943SGeorge Wilson 345488ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 345588ecc943SGeorge Wilson &id) == 0); 345688ecc943SGeorge Wilson (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 345788ecc943SGeorge Wilson (u_longlong_t)id); 345888ecc943SGeorge Wilson path = buf; 345988ecc943SGeorge Wilson } 3460c67d9675Seschrock } 3461c67d9675Seschrock 346299653d4eSeschrock return (zfs_strdup(hdl, path)); 3463c67d9675Seschrock } 3464ea8dc4b6Seschrock 3465ea8dc4b6Seschrock static int 3466ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 3467ea8dc4b6Seschrock { 34687802d7bfSMatthew Ahrens return (memcmp(a, b, sizeof (zbookmark_phys_t))); 3469ea8dc4b6Seschrock } 3470ea8dc4b6Seschrock 3471ea8dc4b6Seschrock /* 3472ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 3473ea8dc4b6Seschrock * caller. 3474ea8dc4b6Seschrock */ 3475ea8dc4b6Seschrock int 347655434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 3477ea8dc4b6Seschrock { 3478ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 3479ea8dc4b6Seschrock uint64_t count; 34807802d7bfSMatthew Ahrens zbookmark_phys_t *zb = NULL; 348155434c77Sek int i; 3482ea8dc4b6Seschrock 3483ea8dc4b6Seschrock /* 3484ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 3485ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 3486ea8dc4b6Seschrock * entire list. 3487ea8dc4b6Seschrock */ 3488ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 3489ea8dc4b6Seschrock &count) == 0); 349075519f38Sek if (count == 0) 349175519f38Sek return (0); 3492e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 34937802d7bfSMatthew Ahrens count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL) 349499653d4eSeschrock return (-1); 3495e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 3496ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 3497ea8dc4b6Seschrock for (;;) { 349899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 349999653d4eSeschrock &zc) != 0) { 3500e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 3501ea8dc4b6Seschrock if (errno == ENOMEM) { 35027802d7bfSMatthew Ahrens void *dst; 35037802d7bfSMatthew Ahrens 3504bf561db0Svb count = zc.zc_nvlist_dst_size; 35057802d7bfSMatthew Ahrens dst = zfs_alloc(zhp->zpool_hdl, count * 35067802d7bfSMatthew Ahrens sizeof (zbookmark_phys_t)); 35077802d7bfSMatthew Ahrens if (dst == NULL) 350899653d4eSeschrock return (-1); 35097802d7bfSMatthew Ahrens zc.zc_nvlist_dst = (uintptr_t)dst; 3510ea8dc4b6Seschrock } else { 3511ea8dc4b6Seschrock return (-1); 3512ea8dc4b6Seschrock } 3513ea8dc4b6Seschrock } else { 3514ea8dc4b6Seschrock break; 3515ea8dc4b6Seschrock } 3516ea8dc4b6Seschrock } 3517ea8dc4b6Seschrock 3518ea8dc4b6Seschrock /* 3519ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 3520ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 3521e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 3522ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 3523ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 3524ea8dc4b6Seschrock */ 35257802d7bfSMatthew Ahrens zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) + 3526e9dbad6fSeschrock zc.zc_nvlist_dst_size; 3527e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 3528ea8dc4b6Seschrock 35297802d7bfSMatthew Ahrens qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_compare); 3530ea8dc4b6Seschrock 353155434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 3532ea8dc4b6Seschrock 3533ea8dc4b6Seschrock /* 353455434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 3535ea8dc4b6Seschrock */ 3536ea8dc4b6Seschrock for (i = 0; i < count; i++) { 3537ea8dc4b6Seschrock nvlist_t *nv; 3538ea8dc4b6Seschrock 3539c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 3540c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 3541c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 3542ea8dc4b6Seschrock continue; 3543ea8dc4b6Seschrock 354455434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 354555434c77Sek goto nomem; 354655434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 354755434c77Sek zb[i].zb_objset) != 0) { 354855434c77Sek nvlist_free(nv); 354999653d4eSeschrock goto nomem; 3550ea8dc4b6Seschrock } 355155434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 355255434c77Sek zb[i].zb_object) != 0) { 355355434c77Sek nvlist_free(nv); 355455434c77Sek goto nomem; 355555434c77Sek } 355655434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 355755434c77Sek nvlist_free(nv); 355855434c77Sek goto nomem; 355955434c77Sek } 356055434c77Sek nvlist_free(nv); 3561ea8dc4b6Seschrock } 3562ea8dc4b6Seschrock 35633ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 3564ea8dc4b6Seschrock return (0); 356599653d4eSeschrock 356699653d4eSeschrock nomem: 3567e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 356899653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 3569ea8dc4b6Seschrock } 3570eaca9bbdSeschrock 3571eaca9bbdSeschrock /* 3572eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 3573eaca9bbdSeschrock */ 3574eaca9bbdSeschrock int 3575990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 3576eaca9bbdSeschrock { 3577eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 357899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 3579eaca9bbdSeschrock 3580eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 3581990b4856Slling zc.zc_cookie = new_version; 3582990b4856Slling 3583ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 3584ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 358599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 358699653d4eSeschrock zhp->zpool_name)); 3587eaca9bbdSeschrock return (0); 3588eaca9bbdSeschrock } 358906eeb2adSek 359006eeb2adSek void 35914445fffbSMatthew Ahrens zfs_save_arguments(int argc, char **argv, char *string, int len) 359206eeb2adSek { 35934445fffbSMatthew Ahrens (void) strlcpy(string, basename(argv[0]), len); 35944445fffbSMatthew Ahrens for (int i = 1; i < argc; i++) { 35954445fffbSMatthew Ahrens (void) strlcat(string, " ", len); 35964445fffbSMatthew Ahrens (void) strlcat(string, argv[i], len); 35972a6b87f0Sek } 35982a6b87f0Sek } 35992a6b87f0Sek 36002a6b87f0Sek int 36014445fffbSMatthew Ahrens zpool_log_history(libzfs_handle_t *hdl, const char *message) 36022a6b87f0Sek { 36034445fffbSMatthew Ahrens zfs_cmd_t zc = { 0 }; 36044445fffbSMatthew Ahrens nvlist_t *args; 36054445fffbSMatthew Ahrens int err; 36064445fffbSMatthew Ahrens 36074445fffbSMatthew Ahrens args = fnvlist_alloc(); 36084445fffbSMatthew Ahrens fnvlist_add_string(args, "message", message); 36094445fffbSMatthew Ahrens err = zcmd_write_src_nvlist(hdl, &zc, args); 36104445fffbSMatthew Ahrens if (err == 0) 36114445fffbSMatthew Ahrens err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc); 36124445fffbSMatthew Ahrens nvlist_free(args); 36134445fffbSMatthew Ahrens zcmd_free_nvlists(&zc); 36144445fffbSMatthew Ahrens return (err); 361506eeb2adSek } 361606eeb2adSek 361706eeb2adSek /* 361806eeb2adSek * Perform ioctl to get some command history of a pool. 361906eeb2adSek * 362006eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 362106eeb2adSek * logical offset of the history buffer to start reading from. 362206eeb2adSek * 362306eeb2adSek * Upon return, 'off' is the next logical offset to read from and 362406eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 362506eeb2adSek */ 362606eeb2adSek static int 362706eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 362806eeb2adSek { 362906eeb2adSek zfs_cmd_t zc = { 0 }; 363006eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 363106eeb2adSek 363206eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 363306eeb2adSek 363406eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 363506eeb2adSek zc.zc_history_len = *len; 363606eeb2adSek zc.zc_history_offset = *off; 363706eeb2adSek 363806eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 363906eeb2adSek switch (errno) { 364006eeb2adSek case EPERM: 3641ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 3642ece3d9b3Slling dgettext(TEXT_DOMAIN, 364306eeb2adSek "cannot show history for pool '%s'"), 364406eeb2adSek zhp->zpool_name)); 364506eeb2adSek case ENOENT: 3646ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 364706eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 364806eeb2adSek "'%s'"), zhp->zpool_name)); 3649d7306b64Sek case ENOTSUP: 3650d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 3651d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 3652d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 365306eeb2adSek default: 3654ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 365506eeb2adSek dgettext(TEXT_DOMAIN, 365606eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 365706eeb2adSek } 365806eeb2adSek } 365906eeb2adSek 366006eeb2adSek *len = zc.zc_history_len; 366106eeb2adSek *off = zc.zc_history_offset; 366206eeb2adSek 366306eeb2adSek return (0); 366406eeb2adSek } 366506eeb2adSek 366606eeb2adSek /* 366706eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 366806eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 366906eeb2adSek * processed as there wasn't a complete record. 367006eeb2adSek */ 36718f18d1faSGeorge Wilson int 367206eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 367306eeb2adSek nvlist_t ***records, uint_t *numrecords) 367406eeb2adSek { 367506eeb2adSek uint64_t reclen; 367606eeb2adSek nvlist_t *nv; 367706eeb2adSek int i; 367806eeb2adSek 367906eeb2adSek while (bytes_read > sizeof (reclen)) { 368006eeb2adSek 368106eeb2adSek /* get length of packed record (stored as little endian) */ 368206eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 368306eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 368406eeb2adSek 368506eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 368606eeb2adSek break; 368706eeb2adSek 368806eeb2adSek /* unpack record */ 368906eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 369006eeb2adSek return (ENOMEM); 369106eeb2adSek bytes_read -= sizeof (reclen) + reclen; 369206eeb2adSek buf += sizeof (reclen) + reclen; 369306eeb2adSek 369406eeb2adSek /* add record to nvlist array */ 369506eeb2adSek (*numrecords)++; 369606eeb2adSek if (ISP2(*numrecords + 1)) { 369706eeb2adSek *records = realloc(*records, 369806eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 369906eeb2adSek } 370006eeb2adSek (*records)[*numrecords - 1] = nv; 370106eeb2adSek } 370206eeb2adSek 370306eeb2adSek *leftover = bytes_read; 370406eeb2adSek return (0); 370506eeb2adSek } 370606eeb2adSek 370706eeb2adSek /* 370806eeb2adSek * Retrieve the command history of a pool. 370906eeb2adSek */ 371006eeb2adSek int 371106eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 371206eeb2adSek { 37133339867aSMatthew Ahrens char *buf; 37143339867aSMatthew Ahrens int buflen = 128 * 1024; 371506eeb2adSek uint64_t off = 0; 371606eeb2adSek nvlist_t **records = NULL; 371706eeb2adSek uint_t numrecords = 0; 371806eeb2adSek int err, i; 371906eeb2adSek 37203339867aSMatthew Ahrens buf = malloc(buflen); 37213339867aSMatthew Ahrens if (buf == NULL) 37223339867aSMatthew Ahrens return (ENOMEM); 372306eeb2adSek do { 37243339867aSMatthew Ahrens uint64_t bytes_read = buflen; 372506eeb2adSek uint64_t leftover; 372606eeb2adSek 372706eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 372806eeb2adSek break; 372906eeb2adSek 373006eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 373106eeb2adSek if (!bytes_read) 373206eeb2adSek break; 373306eeb2adSek 373406eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 373506eeb2adSek &leftover, &records, &numrecords)) != 0) 373606eeb2adSek break; 373706eeb2adSek off -= leftover; 37383339867aSMatthew Ahrens if (leftover == bytes_read) { 37393339867aSMatthew Ahrens /* 37403339867aSMatthew Ahrens * no progress made, because buffer is not big enough 37413339867aSMatthew Ahrens * to hold this record; resize and retry. 37423339867aSMatthew Ahrens */ 37433339867aSMatthew Ahrens buflen *= 2; 37443339867aSMatthew Ahrens free(buf); 37453339867aSMatthew Ahrens buf = malloc(buflen); 37463339867aSMatthew Ahrens if (buf == NULL) 37473339867aSMatthew Ahrens return (ENOMEM); 37483339867aSMatthew Ahrens } 374906eeb2adSek 375006eeb2adSek /* CONSTCOND */ 375106eeb2adSek } while (1); 375206eeb2adSek 37533339867aSMatthew Ahrens free(buf); 37543339867aSMatthew Ahrens 375506eeb2adSek if (!err) { 375606eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 375706eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 375806eeb2adSek records, numrecords) == 0); 375906eeb2adSek } 376006eeb2adSek for (i = 0; i < numrecords; i++) 376106eeb2adSek nvlist_free(records[i]); 376206eeb2adSek free(records); 376306eeb2adSek 376406eeb2adSek return (err); 376506eeb2adSek } 376655434c77Sek 376755434c77Sek void 376855434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 376955434c77Sek char *pathname, size_t len) 377055434c77Sek { 377155434c77Sek zfs_cmd_t zc = { 0 }; 377255434c77Sek boolean_t mounted = B_FALSE; 377355434c77Sek char *mntpnt = NULL; 377455434c77Sek char dsname[MAXNAMELEN]; 377555434c77Sek 377655434c77Sek if (dsobj == 0) { 377755434c77Sek /* special case for the MOS */ 377855434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 377955434c77Sek return; 378055434c77Sek } 378155434c77Sek 378255434c77Sek /* get the dataset's name */ 378355434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 378455434c77Sek zc.zc_obj = dsobj; 378555434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 378655434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 378755434c77Sek /* just write out a path of two object numbers */ 378855434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 378955434c77Sek dsobj, obj); 379055434c77Sek return; 379155434c77Sek } 379255434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 379355434c77Sek 379455434c77Sek /* find out if the dataset is mounted */ 379555434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 379655434c77Sek 379755434c77Sek /* get the corrupted object's path */ 379855434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 379955434c77Sek zc.zc_obj = obj; 380055434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 380155434c77Sek &zc) == 0) { 380255434c77Sek if (mounted) { 380355434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 380455434c77Sek zc.zc_value); 380555434c77Sek } else { 380655434c77Sek (void) snprintf(pathname, len, "%s:%s", 380755434c77Sek dsname, zc.zc_value); 380855434c77Sek } 380955434c77Sek } else { 381055434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 381155434c77Sek } 381255434c77Sek free(mntpnt); 381355434c77Sek } 3814b1b8ab34Slling 381515e6edf1Sgw /* 381615e6edf1Sgw * Read the EFI label from the config, if a label does not exist then 381715e6edf1Sgw * pass back the error to the caller. If the caller has passed a non-NULL 381815e6edf1Sgw * diskaddr argument then we set it to the starting address of the EFI 381915e6edf1Sgw * partition. 382015e6edf1Sgw */ 382115e6edf1Sgw static int 382215e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb) 382315e6edf1Sgw { 382415e6edf1Sgw char *path; 382515e6edf1Sgw int fd; 382615e6edf1Sgw char diskname[MAXPATHLEN]; 382715e6edf1Sgw int err = -1; 382815e6edf1Sgw 382915e6edf1Sgw if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 383015e6edf1Sgw return (err); 383115e6edf1Sgw 383215e6edf1Sgw (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 383315e6edf1Sgw strrchr(path, '/')); 383415e6edf1Sgw if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 383515e6edf1Sgw struct dk_gpt *vtoc; 383615e6edf1Sgw 383715e6edf1Sgw if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 383815e6edf1Sgw if (sb != NULL) 383915e6edf1Sgw *sb = vtoc->efi_parts[0].p_start; 384015e6edf1Sgw efi_free(vtoc); 384115e6edf1Sgw } 384215e6edf1Sgw (void) close(fd); 384315e6edf1Sgw } 384415e6edf1Sgw return (err); 384515e6edf1Sgw } 384615e6edf1Sgw 38478488aeb5Staylor /* 38488488aeb5Staylor * determine where a partition starts on a disk in the current 38498488aeb5Staylor * configuration 38508488aeb5Staylor */ 38518488aeb5Staylor static diskaddr_t 38528488aeb5Staylor find_start_block(nvlist_t *config) 38538488aeb5Staylor { 38548488aeb5Staylor nvlist_t **child; 38558488aeb5Staylor uint_t c, children; 38568488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 38578488aeb5Staylor uint64_t wholedisk; 38588488aeb5Staylor 38598488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 38608488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 38618488aeb5Staylor if (nvlist_lookup_uint64(config, 38628488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 38638488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 38648488aeb5Staylor return (MAXOFFSET_T); 38658488aeb5Staylor } 386615e6edf1Sgw if (read_efi_label(config, &sb) < 0) 386715e6edf1Sgw sb = MAXOFFSET_T; 38688488aeb5Staylor return (sb); 38698488aeb5Staylor } 38708488aeb5Staylor 38718488aeb5Staylor for (c = 0; c < children; c++) { 38728488aeb5Staylor sb = find_start_block(child[c]); 38738488aeb5Staylor if (sb != MAXOFFSET_T) { 38748488aeb5Staylor return (sb); 38758488aeb5Staylor } 38768488aeb5Staylor } 38778488aeb5Staylor return (MAXOFFSET_T); 38788488aeb5Staylor } 38798488aeb5Staylor 38808488aeb5Staylor /* 38818488aeb5Staylor * Label an individual disk. The name provided is the short name, 38828488aeb5Staylor * stripped of any leading /dev path. 38838488aeb5Staylor */ 38848488aeb5Staylor int 38858488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 38868488aeb5Staylor { 38878488aeb5Staylor char path[MAXPATHLEN]; 38888488aeb5Staylor struct dk_gpt *vtoc; 38898488aeb5Staylor int fd; 38908488aeb5Staylor size_t resv = EFI_MIN_RESV_SIZE; 38918488aeb5Staylor uint64_t slice_size; 38928488aeb5Staylor diskaddr_t start_block; 38938488aeb5Staylor char errbuf[1024]; 38948488aeb5Staylor 3895c6ef114fSmmusante /* prepare an error message just in case */ 3896c6ef114fSmmusante (void) snprintf(errbuf, sizeof (errbuf), 3897c6ef114fSmmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 3898c6ef114fSmmusante 38998488aeb5Staylor if (zhp) { 39008488aeb5Staylor nvlist_t *nvroot; 39018488aeb5Staylor 39024263d13fSGeorge Wilson if (zpool_is_bootable(zhp)) { 3903b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3904b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root " 3905b5b76fecSGeorge Wilson "pools.")); 3906b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 3907b5b76fecSGeorge Wilson } 3908b5b76fecSGeorge Wilson 39098488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 39108488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 39118488aeb5Staylor 39128488aeb5Staylor if (zhp->zpool_start_block == 0) 39138488aeb5Staylor start_block = find_start_block(nvroot); 39148488aeb5Staylor else 39158488aeb5Staylor start_block = zhp->zpool_start_block; 39168488aeb5Staylor zhp->zpool_start_block = start_block; 39178488aeb5Staylor } else { 39188488aeb5Staylor /* new pool */ 39198488aeb5Staylor start_block = NEW_START_BLOCK; 39208488aeb5Staylor } 39218488aeb5Staylor 39228488aeb5Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 39238488aeb5Staylor BACKUP_SLICE); 39248488aeb5Staylor 39258488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 39268488aeb5Staylor /* 39278488aeb5Staylor * This shouldn't happen. We've long since verified that this 39288488aeb5Staylor * is a valid device. 39298488aeb5Staylor */ 3930c6ef114fSmmusante zfs_error_aux(hdl, 3931c6ef114fSmmusante dgettext(TEXT_DOMAIN, "unable to open device")); 39328488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 39338488aeb5Staylor } 39348488aeb5Staylor 39358488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 39368488aeb5Staylor /* 39378488aeb5Staylor * The only way this can fail is if we run out of memory, or we 39388488aeb5Staylor * were unable to read the disk's capacity 39398488aeb5Staylor */ 39408488aeb5Staylor if (errno == ENOMEM) 39418488aeb5Staylor (void) no_memory(hdl); 39428488aeb5Staylor 39438488aeb5Staylor (void) close(fd); 3944c6ef114fSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3945c6ef114fSmmusante "unable to read disk capacity"), name); 39468488aeb5Staylor 39478488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 39488488aeb5Staylor } 39498488aeb5Staylor 39508488aeb5Staylor slice_size = vtoc->efi_last_u_lba + 1; 39518488aeb5Staylor slice_size -= EFI_MIN_RESV_SIZE; 39528488aeb5Staylor if (start_block == MAXOFFSET_T) 39538488aeb5Staylor start_block = NEW_START_BLOCK; 39548488aeb5Staylor slice_size -= start_block; 39558488aeb5Staylor 39568488aeb5Staylor vtoc->efi_parts[0].p_start = start_block; 39578488aeb5Staylor vtoc->efi_parts[0].p_size = slice_size; 39588488aeb5Staylor 39598488aeb5Staylor /* 39608488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 39618488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 39628488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 39638488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 39648488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 39658488aeb5Staylor * can get, in the absence of V_OTHER. 39668488aeb5Staylor */ 39678488aeb5Staylor vtoc->efi_parts[0].p_tag = V_USR; 39688488aeb5Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 39698488aeb5Staylor 39708488aeb5Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 39718488aeb5Staylor vtoc->efi_parts[8].p_size = resv; 39728488aeb5Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 39738488aeb5Staylor 39748488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 39758488aeb5Staylor /* 39768488aeb5Staylor * Some block drivers (like pcata) may not support EFI 39778488aeb5Staylor * GPT labels. Print out a helpful error message dir- 39788488aeb5Staylor * ecting the user to manually label the disk and give 39798488aeb5Staylor * a specific slice. 39808488aeb5Staylor */ 39818488aeb5Staylor (void) close(fd); 39828488aeb5Staylor efi_free(vtoc); 39838488aeb5Staylor 39848488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3985c6ef114fSmmusante "try using fdisk(1M) and then provide a specific slice")); 39868488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 39878488aeb5Staylor } 39888488aeb5Staylor 39898488aeb5Staylor (void) close(fd); 39908488aeb5Staylor efi_free(vtoc); 39918488aeb5Staylor return (0); 39928488aeb5Staylor } 3993e7cbe64fSgw 3994e7cbe64fSgw static boolean_t 3995e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 3996e7cbe64fSgw { 3997e7cbe64fSgw char *type; 3998e7cbe64fSgw nvlist_t **child; 3999e7cbe64fSgw uint_t children, c; 4000e7cbe64fSgw 4001e7cbe64fSgw verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 4002810e43b2SBill Pijewski if (strcmp(type, VDEV_TYPE_FILE) == 0 || 400388ecc943SGeorge Wilson strcmp(type, VDEV_TYPE_HOLE) == 0 || 4004e7cbe64fSgw strcmp(type, VDEV_TYPE_MISSING) == 0) { 4005e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4006e7cbe64fSgw "vdev type '%s' is not supported"), type); 4007e7cbe64fSgw (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 4008e7cbe64fSgw return (B_FALSE); 4009e7cbe64fSgw } 4010e7cbe64fSgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 4011e7cbe64fSgw &child, &children) == 0) { 4012e7cbe64fSgw for (c = 0; c < children; c++) { 4013e7cbe64fSgw if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 4014e7cbe64fSgw return (B_FALSE); 4015e7cbe64fSgw } 4016e7cbe64fSgw } 4017e7cbe64fSgw return (B_TRUE); 4018e7cbe64fSgw } 4019e7cbe64fSgw 4020e7cbe64fSgw /* 4021810e43b2SBill Pijewski * Check if this zvol is allowable for use as a dump device; zero if 4022810e43b2SBill Pijewski * it is, > 0 if it isn't, < 0 if it isn't a zvol. 4023810e43b2SBill Pijewski * 4024810e43b2SBill Pijewski * Allowable storage configurations include mirrors, all raidz variants, and 4025810e43b2SBill Pijewski * pools with log, cache, and spare devices. Pools which are backed by files or 4026810e43b2SBill Pijewski * have missing/hole vdevs are not suitable. 4027e7cbe64fSgw */ 4028e7cbe64fSgw int 4029e7cbe64fSgw zvol_check_dump_config(char *arg) 4030e7cbe64fSgw { 4031e7cbe64fSgw zpool_handle_t *zhp = NULL; 4032e7cbe64fSgw nvlist_t *config, *nvroot; 4033e7cbe64fSgw char *p, *volname; 4034e7cbe64fSgw nvlist_t **top; 4035e7cbe64fSgw uint_t toplevels; 4036e7cbe64fSgw libzfs_handle_t *hdl; 4037e7cbe64fSgw char errbuf[1024]; 4038e7cbe64fSgw char poolname[ZPOOL_MAXNAMELEN]; 4039e7cbe64fSgw int pathlen = strlen(ZVOL_FULL_DEV_DIR); 4040e7cbe64fSgw int ret = 1; 4041e7cbe64fSgw 4042e7cbe64fSgw if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 4043e7cbe64fSgw return (-1); 4044e7cbe64fSgw } 4045e7cbe64fSgw 4046e7cbe64fSgw (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4047e7cbe64fSgw "dump is not supported on device '%s'"), arg); 4048e7cbe64fSgw 4049e7cbe64fSgw if ((hdl = libzfs_init()) == NULL) 4050e7cbe64fSgw return (1); 4051e7cbe64fSgw libzfs_print_on_error(hdl, B_TRUE); 4052e7cbe64fSgw 4053e7cbe64fSgw volname = arg + pathlen; 4054e7cbe64fSgw 4055e7cbe64fSgw /* check the configuration of the pool */ 4056e7cbe64fSgw if ((p = strchr(volname, '/')) == NULL) { 4057e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4058e7cbe64fSgw "malformed dataset name")); 4059e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4060e7cbe64fSgw return (1); 4061e7cbe64fSgw } else if (p - volname >= ZFS_MAXNAMELEN) { 4062e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4063e7cbe64fSgw "dataset name is too long")); 4064e7cbe64fSgw (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 4065e7cbe64fSgw return (1); 4066e7cbe64fSgw } else { 4067e7cbe64fSgw (void) strncpy(poolname, volname, p - volname); 4068e7cbe64fSgw poolname[p - volname] = '\0'; 4069e7cbe64fSgw } 4070e7cbe64fSgw 4071e7cbe64fSgw if ((zhp = zpool_open(hdl, poolname)) == NULL) { 4072e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4073e7cbe64fSgw "could not open pool '%s'"), poolname); 4074e7cbe64fSgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4075e7cbe64fSgw goto out; 4076e7cbe64fSgw } 4077e7cbe64fSgw config = zpool_get_config(zhp, NULL); 4078e7cbe64fSgw if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4079e7cbe64fSgw &nvroot) != 0) { 4080e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4081e7cbe64fSgw "could not obtain vdev configuration for '%s'"), poolname); 4082e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 4083e7cbe64fSgw goto out; 4084e7cbe64fSgw } 4085e7cbe64fSgw 4086e7cbe64fSgw verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4087e7cbe64fSgw &top, &toplevels) == 0); 4088e7cbe64fSgw 4089e7cbe64fSgw if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 4090e7cbe64fSgw goto out; 4091e7cbe64fSgw } 4092e7cbe64fSgw ret = 0; 4093e7cbe64fSgw 4094e7cbe64fSgw out: 4095e7cbe64fSgw if (zhp) 4096e7cbe64fSgw zpool_close(zhp); 4097e7cbe64fSgw libzfs_fini(hdl); 4098e7cbe64fSgw return (ret); 4099e7cbe64fSgw } 4100