1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 23379c004dSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #include <ctype.h> 28fa9e4066Sahrens #include <errno.h> 29fa9e4066Sahrens #include <devid.h> 30fa9e4066Sahrens #include <fcntl.h> 31fa9e4066Sahrens #include <libintl.h> 32fa9e4066Sahrens #include <stdio.h> 33fa9e4066Sahrens #include <stdlib.h> 34f3861e1aSahl #include <strings.h> 35fa9e4066Sahrens #include <unistd.h> 368488aeb5Staylor #include <sys/efi_partition.h> 378488aeb5Staylor #include <sys/vtoc.h> 38fa9e4066Sahrens #include <sys/zfs_ioctl.h> 39573ca77eSGeorge Wilson #include <dlfcn.h> 40fa9e4066Sahrens 41fa9e4066Sahrens #include "zfs_namecheck.h" 42b1b8ab34Slling #include "zfs_prop.h" 43fa9e4066Sahrens #include "libzfs_impl.h" 44468c413aSTim Haley #include "zfs_comutil.h" 45fa9e4066Sahrens 468f18d1faSGeorge Wilson const char *hist_event_table[LOG_END] = { 478f18d1faSGeorge Wilson "invalid event", 488f18d1faSGeorge Wilson "pool create", 498f18d1faSGeorge Wilson "vdev add", 508f18d1faSGeorge Wilson "pool remove", 518f18d1faSGeorge Wilson "pool destroy", 528f18d1faSGeorge Wilson "pool export", 538f18d1faSGeorge Wilson "pool import", 548f18d1faSGeorge Wilson "vdev attach", 558f18d1faSGeorge Wilson "vdev replace", 568f18d1faSGeorge Wilson "vdev detach", 578f18d1faSGeorge Wilson "vdev online", 588f18d1faSGeorge Wilson "vdev offline", 598f18d1faSGeorge Wilson "vdev upgrade", 608f18d1faSGeorge Wilson "pool clear", 618f18d1faSGeorge Wilson "pool scrub", 628f18d1faSGeorge Wilson "pool property set", 638f18d1faSGeorge Wilson "create", 648f18d1faSGeorge Wilson "clone", 658f18d1faSGeorge Wilson "destroy", 668f18d1faSGeorge Wilson "destroy_begin_sync", 678f18d1faSGeorge Wilson "inherit", 688f18d1faSGeorge Wilson "property set", 698f18d1faSGeorge Wilson "quota set", 708f18d1faSGeorge Wilson "permission update", 718f18d1faSGeorge Wilson "permission remove", 728f18d1faSGeorge Wilson "permission who remove", 738f18d1faSGeorge Wilson "promote", 748f18d1faSGeorge Wilson "receive", 758f18d1faSGeorge Wilson "rename", 768f18d1faSGeorge Wilson "reservation set", 778f18d1faSGeorge Wilson "replay_inc_sync", 788f18d1faSGeorge Wilson "replay_full_sync", 798f18d1faSGeorge Wilson "rollback", 808f18d1faSGeorge Wilson "snapshot", 818f18d1faSGeorge Wilson "filesystem version upgrade", 828f18d1faSGeorge Wilson "refquota set", 838f18d1faSGeorge Wilson "refreservation set", 848f18d1faSGeorge Wilson "pool scrub done", 858f18d1faSGeorge Wilson "user hold", 868f18d1faSGeorge Wilson "user release", 878f18d1faSGeorge Wilson }; 888f18d1faSGeorge Wilson 8915e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb); 90990b4856Slling 91b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64) 92b5b76fecSGeorge Wilson #define BOOTCMD "installgrub(1M)" 93b5b76fecSGeorge Wilson #else 94b5b76fecSGeorge Wilson #define BOOTCMD "installboot(1M)" 95b5b76fecSGeorge Wilson #endif 96b5b76fecSGeorge Wilson 97573ca77eSGeorge Wilson #define DISK_ROOT "/dev/dsk" 98573ca77eSGeorge Wilson #define RDISK_ROOT "/dev/rdsk" 99573ca77eSGeorge Wilson #define BACKUP_SLICE "s2" 100573ca77eSGeorge Wilson 101990b4856Slling /* 102990b4856Slling * ==================================================================== 103990b4856Slling * zpool property functions 104990b4856Slling * ==================================================================== 105990b4856Slling */ 106990b4856Slling 107990b4856Slling static int 108990b4856Slling zpool_get_all_props(zpool_handle_t *zhp) 109990b4856Slling { 110990b4856Slling zfs_cmd_t zc = { 0 }; 111990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 112990b4856Slling 113990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 114990b4856Slling 115990b4856Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 116990b4856Slling return (-1); 117990b4856Slling 118990b4856Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 119990b4856Slling if (errno == ENOMEM) { 120990b4856Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 121990b4856Slling zcmd_free_nvlists(&zc); 122990b4856Slling return (-1); 123990b4856Slling } 124990b4856Slling } else { 125990b4856Slling zcmd_free_nvlists(&zc); 126990b4856Slling return (-1); 127990b4856Slling } 128990b4856Slling } 129990b4856Slling 130990b4856Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 131990b4856Slling zcmd_free_nvlists(&zc); 132990b4856Slling return (-1); 133990b4856Slling } 134990b4856Slling 135990b4856Slling zcmd_free_nvlists(&zc); 136990b4856Slling 137990b4856Slling return (0); 138990b4856Slling } 139990b4856Slling 140990b4856Slling static int 141990b4856Slling zpool_props_refresh(zpool_handle_t *zhp) 142990b4856Slling { 143990b4856Slling nvlist_t *old_props; 144990b4856Slling 145990b4856Slling old_props = zhp->zpool_props; 146990b4856Slling 147990b4856Slling if (zpool_get_all_props(zhp) != 0) 148990b4856Slling return (-1); 149990b4856Slling 150990b4856Slling nvlist_free(old_props); 151990b4856Slling return (0); 152990b4856Slling } 153990b4856Slling 154990b4856Slling static char * 155990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 156990b4856Slling zprop_source_t *src) 157990b4856Slling { 158990b4856Slling nvlist_t *nv, *nvl; 159990b4856Slling uint64_t ival; 160990b4856Slling char *value; 161990b4856Slling zprop_source_t source; 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, &ival) == 0); 166990b4856Slling source = ival; 167990b4856Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 168990b4856Slling } else { 169990b4856Slling source = ZPROP_SRC_DEFAULT; 170990b4856Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 171990b4856Slling value = "-"; 172990b4856Slling } 173990b4856Slling 174990b4856Slling if (src) 175990b4856Slling *src = source; 176990b4856Slling 177990b4856Slling return (value); 178990b4856Slling } 179990b4856Slling 180990b4856Slling uint64_t 181990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 182990b4856Slling { 183990b4856Slling nvlist_t *nv, *nvl; 184990b4856Slling uint64_t value; 185990b4856Slling zprop_source_t source; 186990b4856Slling 187b87f3af3Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 188b87f3af3Sperrin /* 189b87f3af3Sperrin * zpool_get_all_props() has most likely failed because 190b87f3af3Sperrin * the pool is faulted, but if all we need is the top level 191b87f3af3Sperrin * vdev's guid then get it from the zhp config nvlist. 192b87f3af3Sperrin */ 193b87f3af3Sperrin if ((prop == ZPOOL_PROP_GUID) && 194b87f3af3Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 195b87f3af3Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 196b87f3af3Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 197b87f3af3Sperrin == 0)) { 198b87f3af3Sperrin return (value); 199b87f3af3Sperrin } 200990b4856Slling return (zpool_prop_default_numeric(prop)); 201b87f3af3Sperrin } 202990b4856Slling 203990b4856Slling nvl = zhp->zpool_props; 204990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 205990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 206990b4856Slling source = value; 207990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 208990b4856Slling } else { 209990b4856Slling source = ZPROP_SRC_DEFAULT; 210990b4856Slling value = zpool_prop_default_numeric(prop); 211990b4856Slling } 212990b4856Slling 213990b4856Slling if (src) 214990b4856Slling *src = source; 215990b4856Slling 216990b4856Slling return (value); 217990b4856Slling } 218990b4856Slling 219990b4856Slling /* 220990b4856Slling * Map VDEV STATE to printed strings. 221990b4856Slling */ 222990b4856Slling char * 223990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 224990b4856Slling { 225990b4856Slling switch (state) { 226990b4856Slling case VDEV_STATE_CLOSED: 227990b4856Slling case VDEV_STATE_OFFLINE: 228990b4856Slling return (gettext("OFFLINE")); 229990b4856Slling case VDEV_STATE_REMOVED: 230990b4856Slling return (gettext("REMOVED")); 231990b4856Slling case VDEV_STATE_CANT_OPEN: 232b87f3af3Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 233990b4856Slling return (gettext("FAULTED")); 234990b4856Slling else 235990b4856Slling return (gettext("UNAVAIL")); 236990b4856Slling case VDEV_STATE_FAULTED: 237990b4856Slling return (gettext("FAULTED")); 238990b4856Slling case VDEV_STATE_DEGRADED: 239990b4856Slling return (gettext("DEGRADED")); 240990b4856Slling case VDEV_STATE_HEALTHY: 241990b4856Slling return (gettext("ONLINE")); 242990b4856Slling } 243990b4856Slling 244990b4856Slling return (gettext("UNKNOWN")); 245990b4856Slling } 246990b4856Slling 247990b4856Slling /* 248990b4856Slling * Get a zpool property value for 'prop' and return the value in 249990b4856Slling * a pre-allocated buffer. 250990b4856Slling */ 251990b4856Slling int 252990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 253990b4856Slling zprop_source_t *srctype) 254990b4856Slling { 255990b4856Slling uint64_t intval; 256990b4856Slling const char *strval; 257990b4856Slling zprop_source_t src = ZPROP_SRC_NONE; 258990b4856Slling nvlist_t *nvroot; 259990b4856Slling vdev_stat_t *vs; 260990b4856Slling uint_t vsc; 261990b4856Slling 262990b4856Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 263379c004dSEric Schrock switch (prop) { 264379c004dSEric Schrock case ZPOOL_PROP_NAME: 265990b4856Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 266379c004dSEric Schrock break; 267379c004dSEric Schrock 268379c004dSEric Schrock case ZPOOL_PROP_HEALTH: 269990b4856Slling (void) strlcpy(buf, "FAULTED", len); 270379c004dSEric Schrock break; 271379c004dSEric Schrock 272379c004dSEric Schrock case ZPOOL_PROP_GUID: 273379c004dSEric Schrock intval = zpool_get_prop_int(zhp, prop, &src); 274379c004dSEric Schrock (void) snprintf(buf, len, "%llu", intval); 275379c004dSEric Schrock break; 276379c004dSEric Schrock 277379c004dSEric Schrock case ZPOOL_PROP_ALTROOT: 278379c004dSEric Schrock case ZPOOL_PROP_CACHEFILE: 279379c004dSEric Schrock if (zhp->zpool_props != NULL || 280379c004dSEric Schrock zpool_get_all_props(zhp) == 0) { 281379c004dSEric Schrock (void) strlcpy(buf, 282379c004dSEric Schrock zpool_get_prop_string(zhp, prop, &src), 283379c004dSEric Schrock len); 284379c004dSEric Schrock if (srctype != NULL) 285379c004dSEric Schrock *srctype = src; 286379c004dSEric Schrock return (0); 287379c004dSEric Schrock } 288379c004dSEric Schrock /* FALLTHROUGH */ 289379c004dSEric Schrock default: 290990b4856Slling (void) strlcpy(buf, "-", len); 291379c004dSEric Schrock break; 292379c004dSEric Schrock } 293379c004dSEric Schrock 294379c004dSEric Schrock if (srctype != NULL) 295379c004dSEric Schrock *srctype = src; 296990b4856Slling return (0); 297990b4856Slling } 298990b4856Slling 299990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 300990b4856Slling prop != ZPOOL_PROP_NAME) 301990b4856Slling return (-1); 302990b4856Slling 303990b4856Slling switch (zpool_prop_get_type(prop)) { 304990b4856Slling case PROP_TYPE_STRING: 305990b4856Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 306990b4856Slling len); 307990b4856Slling break; 308990b4856Slling 309990b4856Slling case PROP_TYPE_NUMBER: 310990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 311990b4856Slling 312990b4856Slling switch (prop) { 313990b4856Slling case ZPOOL_PROP_SIZE: 314990b4856Slling case ZPOOL_PROP_USED: 315990b4856Slling case ZPOOL_PROP_AVAILABLE: 316990b4856Slling (void) zfs_nicenum(intval, buf, len); 317990b4856Slling break; 318990b4856Slling 319990b4856Slling case ZPOOL_PROP_CAPACITY: 320990b4856Slling (void) snprintf(buf, len, "%llu%%", 321990b4856Slling (u_longlong_t)intval); 322990b4856Slling break; 323990b4856Slling 324*b24ab676SJeff Bonwick case ZPOOL_PROP_DEDUPRATIO: 325*b24ab676SJeff Bonwick (void) snprintf(buf, len, "%llu.%02llux", 326*b24ab676SJeff Bonwick (u_longlong_t)(intval / 100), 327*b24ab676SJeff Bonwick (u_longlong_t)(intval % 100)); 328*b24ab676SJeff Bonwick break; 329*b24ab676SJeff Bonwick 330990b4856Slling case ZPOOL_PROP_HEALTH: 331990b4856Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 332990b4856Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 333990b4856Slling verify(nvlist_lookup_uint64_array(nvroot, 334990b4856Slling ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); 335990b4856Slling 336990b4856Slling (void) strlcpy(buf, zpool_state_to_name(intval, 337990b4856Slling vs->vs_aux), len); 338990b4856Slling break; 339990b4856Slling default: 340990b4856Slling (void) snprintf(buf, len, "%llu", intval); 341990b4856Slling } 342990b4856Slling break; 343990b4856Slling 344990b4856Slling case PROP_TYPE_INDEX: 345990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 346990b4856Slling if (zpool_prop_index_to_string(prop, intval, &strval) 347990b4856Slling != 0) 348990b4856Slling return (-1); 349990b4856Slling (void) strlcpy(buf, strval, len); 350990b4856Slling break; 351990b4856Slling 352990b4856Slling default: 353990b4856Slling abort(); 354990b4856Slling } 355990b4856Slling 356990b4856Slling if (srctype) 357990b4856Slling *srctype = src; 358990b4856Slling 359990b4856Slling return (0); 360990b4856Slling } 361990b4856Slling 362990b4856Slling /* 363990b4856Slling * Check if the bootfs name has the same pool name as it is set to. 364990b4856Slling * Assuming bootfs is a valid dataset name. 365990b4856Slling */ 366990b4856Slling static boolean_t 367990b4856Slling bootfs_name_valid(const char *pool, char *bootfs) 368990b4856Slling { 369990b4856Slling int len = strlen(pool); 370990b4856Slling 371fe3e2633SEric Taylor if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 372990b4856Slling return (B_FALSE); 373990b4856Slling 374990b4856Slling if (strncmp(pool, bootfs, len) == 0 && 375990b4856Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 376990b4856Slling return (B_TRUE); 377990b4856Slling 378990b4856Slling return (B_FALSE); 379990b4856Slling } 380990b4856Slling 38115e6edf1Sgw /* 38215e6edf1Sgw * Inspect the configuration to determine if any of the devices contain 38315e6edf1Sgw * an EFI label. 38415e6edf1Sgw */ 38515e6edf1Sgw static boolean_t 38615e6edf1Sgw pool_uses_efi(nvlist_t *config) 38715e6edf1Sgw { 38815e6edf1Sgw nvlist_t **child; 38915e6edf1Sgw uint_t c, children; 39015e6edf1Sgw 39115e6edf1Sgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 39215e6edf1Sgw &child, &children) != 0) 39315e6edf1Sgw return (read_efi_label(config, NULL) >= 0); 39415e6edf1Sgw 39515e6edf1Sgw for (c = 0; c < children; c++) { 39615e6edf1Sgw if (pool_uses_efi(child[c])) 39715e6edf1Sgw return (B_TRUE); 39815e6edf1Sgw } 39915e6edf1Sgw return (B_FALSE); 40015e6edf1Sgw } 40115e6edf1Sgw 402b5b76fecSGeorge Wilson static boolean_t 403b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp) 404b5b76fecSGeorge Wilson { 405b5b76fecSGeorge Wilson char bootfs[ZPOOL_MAXNAMELEN]; 406b5b76fecSGeorge Wilson 407b5b76fecSGeorge Wilson return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 408b5b76fecSGeorge Wilson sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", 409b5b76fecSGeorge Wilson sizeof (bootfs)) != 0); 410b5b76fecSGeorge Wilson } 411b5b76fecSGeorge Wilson 412b5b76fecSGeorge Wilson 413990b4856Slling /* 414990b4856Slling * Given an nvlist of zpool properties to be set, validate that they are 415990b4856Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 416990b4856Slling * specified as strings. 417990b4856Slling */ 418990b4856Slling static nvlist_t * 4190a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 420990b4856Slling nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf) 421990b4856Slling { 422990b4856Slling nvpair_t *elem; 423990b4856Slling nvlist_t *retprops; 424990b4856Slling zpool_prop_t prop; 425990b4856Slling char *strval; 426990b4856Slling uint64_t intval; 4272f8aaab3Seschrock char *slash; 4282f8aaab3Seschrock struct stat64 statbuf; 42915e6edf1Sgw zpool_handle_t *zhp; 43015e6edf1Sgw nvlist_t *nvroot; 431990b4856Slling 432990b4856Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 433990b4856Slling (void) no_memory(hdl); 434990b4856Slling return (NULL); 435990b4856Slling } 436990b4856Slling 437990b4856Slling elem = NULL; 438990b4856Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 439990b4856Slling const char *propname = nvpair_name(elem); 440990b4856Slling 441990b4856Slling /* 442990b4856Slling * Make sure this property is valid and applies to this type. 443990b4856Slling */ 444990b4856Slling if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { 445990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 446990b4856Slling "invalid property '%s'"), propname); 447990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 448990b4856Slling goto error; 449990b4856Slling } 450990b4856Slling 451990b4856Slling if (zpool_prop_readonly(prop)) { 452990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 453990b4856Slling "is readonly"), propname); 454990b4856Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 455990b4856Slling goto error; 456990b4856Slling } 457990b4856Slling 458990b4856Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 459990b4856Slling &strval, &intval, errbuf) != 0) 460990b4856Slling goto error; 461990b4856Slling 462990b4856Slling /* 463990b4856Slling * Perform additional checking for specific properties. 464990b4856Slling */ 465990b4856Slling switch (prop) { 466990b4856Slling case ZPOOL_PROP_VERSION: 467990b4856Slling if (intval < version || intval > SPA_VERSION) { 468990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 469990b4856Slling "property '%s' number %d is invalid."), 470990b4856Slling propname, intval); 471990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 472990b4856Slling goto error; 473990b4856Slling } 474990b4856Slling break; 475990b4856Slling 476990b4856Slling case ZPOOL_PROP_BOOTFS: 477990b4856Slling if (create_or_import) { 478990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 479990b4856Slling "property '%s' cannot be set at creation " 480990b4856Slling "or import time"), propname); 481990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 482990b4856Slling goto error; 483990b4856Slling } 484990b4856Slling 485990b4856Slling if (version < SPA_VERSION_BOOTFS) { 486990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 487990b4856Slling "pool must be upgraded to support " 488990b4856Slling "'%s' property"), propname); 489990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 490990b4856Slling goto error; 491990b4856Slling } 492990b4856Slling 493990b4856Slling /* 494990b4856Slling * bootfs property value has to be a dataset name and 495990b4856Slling * the dataset has to be in the same pool as it sets to. 496990b4856Slling */ 497990b4856Slling if (strval[0] != '\0' && !bootfs_name_valid(poolname, 498990b4856Slling strval)) { 499990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 500990b4856Slling "is an invalid name"), strval); 501990b4856Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 502990b4856Slling goto error; 503990b4856Slling } 50415e6edf1Sgw 50515e6edf1Sgw if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 50615e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50715e6edf1Sgw "could not open pool '%s'"), poolname); 50815e6edf1Sgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 50915e6edf1Sgw goto error; 51015e6edf1Sgw } 51115e6edf1Sgw verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 51215e6edf1Sgw ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 51315e6edf1Sgw 51415e6edf1Sgw /* 51515e6edf1Sgw * bootfs property cannot be set on a disk which has 51615e6edf1Sgw * been EFI labeled. 51715e6edf1Sgw */ 51815e6edf1Sgw if (pool_uses_efi(nvroot)) { 51915e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 52015e6edf1Sgw "property '%s' not supported on " 52115e6edf1Sgw "EFI labeled devices"), propname); 52215e6edf1Sgw (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); 52315e6edf1Sgw zpool_close(zhp); 52415e6edf1Sgw goto error; 52515e6edf1Sgw } 52615e6edf1Sgw zpool_close(zhp); 527990b4856Slling break; 528990b4856Slling 5292f8aaab3Seschrock case ZPOOL_PROP_ALTROOT: 530990b4856Slling if (!create_or_import) { 531990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 532990b4856Slling "property '%s' can only be set during pool " 533990b4856Slling "creation or import"), propname); 534990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 535990b4856Slling goto error; 536990b4856Slling } 537990b4856Slling 5382f8aaab3Seschrock if (strval[0] != '/') { 539990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5402f8aaab3Seschrock "bad alternate root '%s'"), strval); 5412f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 542990b4856Slling goto error; 543990b4856Slling } 5442f8aaab3Seschrock break; 5452f8aaab3Seschrock 5462f8aaab3Seschrock case ZPOOL_PROP_CACHEFILE: 5472f8aaab3Seschrock if (strval[0] == '\0') 5482f8aaab3Seschrock break; 5492f8aaab3Seschrock 5502f8aaab3Seschrock if (strcmp(strval, "none") == 0) 5512f8aaab3Seschrock break; 552990b4856Slling 553990b4856Slling if (strval[0] != '/') { 554990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5552f8aaab3Seschrock "property '%s' must be empty, an " 5562f8aaab3Seschrock "absolute path, or 'none'"), propname); 557990b4856Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 558990b4856Slling goto error; 559990b4856Slling } 560990b4856Slling 5612f8aaab3Seschrock slash = strrchr(strval, '/'); 562990b4856Slling 5632f8aaab3Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 5642f8aaab3Seschrock strcmp(slash, "/..") == 0) { 5652f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5662f8aaab3Seschrock "'%s' is not a valid file"), strval); 5672f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5682f8aaab3Seschrock goto error; 5692f8aaab3Seschrock } 570990b4856Slling 5712f8aaab3Seschrock *slash = '\0'; 5722f8aaab3Seschrock 5732c32020fSeschrock if (strval[0] != '\0' && 5742c32020fSeschrock (stat64(strval, &statbuf) != 0 || 5752c32020fSeschrock !S_ISDIR(statbuf.st_mode))) { 5762f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5772f8aaab3Seschrock "'%s' is not a valid directory"), 5782f8aaab3Seschrock strval); 5792f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 5802f8aaab3Seschrock goto error; 5812f8aaab3Seschrock } 5822f8aaab3Seschrock 5832f8aaab3Seschrock *slash = '/'; 5842f8aaab3Seschrock break; 585990b4856Slling } 586990b4856Slling } 587990b4856Slling 588990b4856Slling return (retprops); 589990b4856Slling error: 590990b4856Slling nvlist_free(retprops); 591990b4856Slling return (NULL); 592990b4856Slling } 593990b4856Slling 594990b4856Slling /* 595990b4856Slling * Set zpool property : propname=propval. 596990b4856Slling */ 597990b4856Slling int 598990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 599990b4856Slling { 600990b4856Slling zfs_cmd_t zc = { 0 }; 601990b4856Slling int ret = -1; 602990b4856Slling char errbuf[1024]; 603990b4856Slling nvlist_t *nvl = NULL; 604990b4856Slling nvlist_t *realprops; 605990b4856Slling uint64_t version; 606990b4856Slling 607990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), 608990b4856Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 609990b4856Slling zhp->zpool_name); 610990b4856Slling 611990b4856Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 612990b4856Slling return (no_memory(zhp->zpool_hdl)); 613990b4856Slling 614990b4856Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 615990b4856Slling nvlist_free(nvl); 616990b4856Slling return (no_memory(zhp->zpool_hdl)); 617990b4856Slling } 618990b4856Slling 619990b4856Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 6200a48a24eStimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 621990b4856Slling zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) { 622990b4856Slling nvlist_free(nvl); 623990b4856Slling return (-1); 624990b4856Slling } 625990b4856Slling 626990b4856Slling nvlist_free(nvl); 627990b4856Slling nvl = realprops; 628990b4856Slling 629990b4856Slling /* 630990b4856Slling * Execute the corresponding ioctl() to set this property. 631990b4856Slling */ 632990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 633990b4856Slling 634990b4856Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 635990b4856Slling nvlist_free(nvl); 636990b4856Slling return (-1); 637990b4856Slling } 638990b4856Slling 639990b4856Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 640990b4856Slling 641990b4856Slling zcmd_free_nvlists(&zc); 642990b4856Slling nvlist_free(nvl); 643990b4856Slling 644990b4856Slling if (ret) 645990b4856Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 646990b4856Slling else 647990b4856Slling (void) zpool_props_refresh(zhp); 648990b4856Slling 649990b4856Slling return (ret); 650990b4856Slling } 651990b4856Slling 652990b4856Slling int 653990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 654990b4856Slling { 655990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 656990b4856Slling zprop_list_t *entry; 657990b4856Slling char buf[ZFS_MAXPROPLEN]; 658990b4856Slling 659990b4856Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 660990b4856Slling return (-1); 661990b4856Slling 662990b4856Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 663990b4856Slling 664990b4856Slling if (entry->pl_fixed) 665990b4856Slling continue; 666990b4856Slling 667990b4856Slling if (entry->pl_prop != ZPROP_INVAL && 668990b4856Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 669990b4856Slling NULL) == 0) { 670990b4856Slling if (strlen(buf) > entry->pl_width) 671990b4856Slling entry->pl_width = strlen(buf); 672990b4856Slling } 673990b4856Slling } 674990b4856Slling 675990b4856Slling return (0); 676990b4856Slling } 677990b4856Slling 678990b4856Slling 679573ca77eSGeorge Wilson /* 680573ca77eSGeorge Wilson * Don't start the slice at the default block of 34; many storage 681573ca77eSGeorge Wilson * devices will use a stripe width of 128k, so start there instead. 682573ca77eSGeorge Wilson */ 683573ca77eSGeorge Wilson #define NEW_START_BLOCK 256 684573ca77eSGeorge Wilson 685fa9e4066Sahrens /* 686fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 687fa9e4066Sahrens * 'buf'. 688fa9e4066Sahrens */ 689e7cbe64fSgw boolean_t 69099653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 691fa9e4066Sahrens { 692fa9e4066Sahrens namecheck_err_t why; 693fa9e4066Sahrens char what; 694b468a217Seschrock int ret; 695b468a217Seschrock 696b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 697b468a217Seschrock 698b468a217Seschrock /* 699b468a217Seschrock * The rules for reserved pool names were extended at a later point. 700b468a217Seschrock * But we need to support users with existing pools that may now be 701b468a217Seschrock * invalid. So we only check for this expanded set of names during a 702b468a217Seschrock * create (or import), and only in userland. 703b468a217Seschrock */ 704b468a217Seschrock if (ret == 0 && !isopen && 705b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 706b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 7078654d025Sperrin strncmp(pool, "spare", 5) == 0 || 7088654d025Sperrin strcmp(pool, "log") == 0)) { 709e7cbe64fSgw if (hdl != NULL) 710e7cbe64fSgw zfs_error_aux(hdl, 711e7cbe64fSgw dgettext(TEXT_DOMAIN, "name is reserved")); 71299653d4eSeschrock return (B_FALSE); 713b468a217Seschrock } 714b468a217Seschrock 715fa9e4066Sahrens 716b468a217Seschrock if (ret != 0) { 71799653d4eSeschrock if (hdl != NULL) { 718fa9e4066Sahrens switch (why) { 719b81d61a6Slling case NAME_ERR_TOOLONG: 72099653d4eSeschrock zfs_error_aux(hdl, 721b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 722b81d61a6Slling break; 723b81d61a6Slling 724fa9e4066Sahrens case NAME_ERR_INVALCHAR: 72599653d4eSeschrock zfs_error_aux(hdl, 726fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 727fa9e4066Sahrens "'%c' in pool name"), what); 728fa9e4066Sahrens break; 729fa9e4066Sahrens 730fa9e4066Sahrens case NAME_ERR_NOLETTER: 73199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 73299653d4eSeschrock "name must begin with a letter")); 733fa9e4066Sahrens break; 734fa9e4066Sahrens 735fa9e4066Sahrens case NAME_ERR_RESERVED: 73699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 73799653d4eSeschrock "name is reserved")); 738fa9e4066Sahrens break; 739fa9e4066Sahrens 740fa9e4066Sahrens case NAME_ERR_DISKLIKE: 74199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 74299653d4eSeschrock "pool name is reserved")); 743fa9e4066Sahrens break; 7445ad82045Snd 7455ad82045Snd case NAME_ERR_LEADING_SLASH: 7465ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7475ad82045Snd "leading slash in name")); 7485ad82045Snd break; 7495ad82045Snd 7505ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 7515ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7525ad82045Snd "empty component in name")); 7535ad82045Snd break; 7545ad82045Snd 7555ad82045Snd case NAME_ERR_TRAILING_SLASH: 7565ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7575ad82045Snd "trailing slash in name")); 7585ad82045Snd break; 7595ad82045Snd 7605ad82045Snd case NAME_ERR_MULTIPLE_AT: 7615ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 7625ad82045Snd "multiple '@' delimiters in name")); 7635ad82045Snd break; 7645ad82045Snd 765fa9e4066Sahrens } 766fa9e4066Sahrens } 76799653d4eSeschrock return (B_FALSE); 768fa9e4066Sahrens } 769fa9e4066Sahrens 77099653d4eSeschrock return (B_TRUE); 771fa9e4066Sahrens } 772fa9e4066Sahrens 773fa9e4066Sahrens /* 774fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 775fa9e4066Sahrens * state. 776fa9e4066Sahrens */ 777fa9e4066Sahrens zpool_handle_t * 77899653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 779fa9e4066Sahrens { 780fa9e4066Sahrens zpool_handle_t *zhp; 78194de1d4cSeschrock boolean_t missing; 782fa9e4066Sahrens 783fa9e4066Sahrens /* 784fa9e4066Sahrens * Make sure the pool name is valid. 785fa9e4066Sahrens */ 78699653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 787ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 78899653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 78999653d4eSeschrock pool); 790fa9e4066Sahrens return (NULL); 791fa9e4066Sahrens } 792fa9e4066Sahrens 79399653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 79499653d4eSeschrock return (NULL); 795fa9e4066Sahrens 79699653d4eSeschrock zhp->zpool_hdl = hdl; 797fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 798fa9e4066Sahrens 79994de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 80094de1d4cSeschrock zpool_close(zhp); 80194de1d4cSeschrock return (NULL); 80294de1d4cSeschrock } 80394de1d4cSeschrock 80494de1d4cSeschrock if (missing) { 805990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 806ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 807990b4856Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 80894de1d4cSeschrock zpool_close(zhp); 80994de1d4cSeschrock return (NULL); 810fa9e4066Sahrens } 811fa9e4066Sahrens 812fa9e4066Sahrens return (zhp); 813fa9e4066Sahrens } 814fa9e4066Sahrens 815fa9e4066Sahrens /* 816fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 817fa9e4066Sahrens * the configuration cache may be out of date). 818fa9e4066Sahrens */ 81994de1d4cSeschrock int 82094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 821fa9e4066Sahrens { 822fa9e4066Sahrens zpool_handle_t *zhp; 82394de1d4cSeschrock boolean_t missing; 824fa9e4066Sahrens 82594de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 82694de1d4cSeschrock return (-1); 827fa9e4066Sahrens 82899653d4eSeschrock zhp->zpool_hdl = hdl; 829fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 830fa9e4066Sahrens 83194de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 83294de1d4cSeschrock zpool_close(zhp); 83394de1d4cSeschrock return (-1); 834fa9e4066Sahrens } 835fa9e4066Sahrens 83694de1d4cSeschrock if (missing) { 83794de1d4cSeschrock zpool_close(zhp); 83894de1d4cSeschrock *ret = NULL; 83994de1d4cSeschrock return (0); 84094de1d4cSeschrock } 84194de1d4cSeschrock 84294de1d4cSeschrock *ret = zhp; 84394de1d4cSeschrock return (0); 844fa9e4066Sahrens } 845fa9e4066Sahrens 846fa9e4066Sahrens /* 847fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 848fa9e4066Sahrens * state. 849fa9e4066Sahrens */ 850fa9e4066Sahrens zpool_handle_t * 85199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 852fa9e4066Sahrens { 853fa9e4066Sahrens zpool_handle_t *zhp; 854fa9e4066Sahrens 85599653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 856fa9e4066Sahrens return (NULL); 857fa9e4066Sahrens 858fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 859ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 86099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 861fa9e4066Sahrens zpool_close(zhp); 862fa9e4066Sahrens return (NULL); 863fa9e4066Sahrens } 864fa9e4066Sahrens 865fa9e4066Sahrens return (zhp); 866fa9e4066Sahrens } 867fa9e4066Sahrens 868fa9e4066Sahrens /* 869fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 870fa9e4066Sahrens */ 871fa9e4066Sahrens void 872fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 873fa9e4066Sahrens { 874fa9e4066Sahrens if (zhp->zpool_config) 875fa9e4066Sahrens nvlist_free(zhp->zpool_config); 876088e9d47Seschrock if (zhp->zpool_old_config) 877088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 878b1b8ab34Slling if (zhp->zpool_props) 879b1b8ab34Slling nvlist_free(zhp->zpool_props); 880fa9e4066Sahrens free(zhp); 881fa9e4066Sahrens } 882fa9e4066Sahrens 883fa9e4066Sahrens /* 884fa9e4066Sahrens * Return the name of the pool. 885fa9e4066Sahrens */ 886fa9e4066Sahrens const char * 887fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 888fa9e4066Sahrens { 889fa9e4066Sahrens return (zhp->zpool_name); 890fa9e4066Sahrens } 891fa9e4066Sahrens 892fa9e4066Sahrens 893fa9e4066Sahrens /* 894fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 895fa9e4066Sahrens */ 896fa9e4066Sahrens int 897fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 898fa9e4066Sahrens { 899fa9e4066Sahrens return (zhp->zpool_state); 900fa9e4066Sahrens } 901fa9e4066Sahrens 902fa9e4066Sahrens /* 903fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 904fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 905fa9e4066Sahrens * don't have to worry about error semantics. 906fa9e4066Sahrens */ 907fa9e4066Sahrens int 90899653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 9090a48a24eStimh nvlist_t *props, nvlist_t *fsprops) 910fa9e4066Sahrens { 911fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 9120a48a24eStimh nvlist_t *zc_fsprops = NULL; 9130a48a24eStimh nvlist_t *zc_props = NULL; 91499653d4eSeschrock char msg[1024]; 915990b4856Slling char *altroot; 9160a48a24eStimh int ret = -1; 917fa9e4066Sahrens 91899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 91999653d4eSeschrock "cannot create '%s'"), pool); 920fa9e4066Sahrens 92199653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 92299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 923fa9e4066Sahrens 924351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 925990b4856Slling return (-1); 926fa9e4066Sahrens 9270a48a24eStimh if (props) { 9280a48a24eStimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 9290a48a24eStimh SPA_VERSION_1, B_TRUE, msg)) == NULL) { 9300a48a24eStimh goto create_failed; 9310a48a24eStimh } 9320a48a24eStimh } 93399653d4eSeschrock 9340a48a24eStimh if (fsprops) { 9350a48a24eStimh uint64_t zoned; 9360a48a24eStimh char *zonestr; 9370a48a24eStimh 9380a48a24eStimh zoned = ((nvlist_lookup_string(fsprops, 9390a48a24eStimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 9400a48a24eStimh strcmp(zonestr, "on") == 0); 9410a48a24eStimh 9420a48a24eStimh if ((zc_fsprops = zfs_valid_proplist(hdl, 9430a48a24eStimh ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) { 9440a48a24eStimh goto create_failed; 9450a48a24eStimh } 9460a48a24eStimh if (!zc_props && 9470a48a24eStimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 9480a48a24eStimh goto create_failed; 9490a48a24eStimh } 9500a48a24eStimh if (nvlist_add_nvlist(zc_props, 9510a48a24eStimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 9520a48a24eStimh goto create_failed; 9530a48a24eStimh } 954351420b3Slling } 955fa9e4066Sahrens 9560a48a24eStimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 9570a48a24eStimh goto create_failed; 9580a48a24eStimh 959990b4856Slling (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 960fa9e4066Sahrens 9610a48a24eStimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 962351420b3Slling 963e9dbad6fSeschrock zcmd_free_nvlists(&zc); 9640a48a24eStimh nvlist_free(zc_props); 9650a48a24eStimh nvlist_free(zc_fsprops); 966fa9e4066Sahrens 96799653d4eSeschrock switch (errno) { 968fa9e4066Sahrens case EBUSY: 969fa9e4066Sahrens /* 970fa9e4066Sahrens * This can happen if the user has specified the same 971fa9e4066Sahrens * device multiple times. We can't reliably detect this 972fa9e4066Sahrens * until we try to add it and see we already have a 973fa9e4066Sahrens * label. 974fa9e4066Sahrens */ 97599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 97699653d4eSeschrock "one or more vdevs refer to the same device")); 97799653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 978fa9e4066Sahrens 979fa9e4066Sahrens case EOVERFLOW: 980fa9e4066Sahrens /* 98199653d4eSeschrock * This occurs when one of the devices is below 982fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 983fa9e4066Sahrens * device was the problem device since there's no 984fa9e4066Sahrens * reliable way to determine device size from userland. 985fa9e4066Sahrens */ 986fa9e4066Sahrens { 987fa9e4066Sahrens char buf[64]; 988fa9e4066Sahrens 989fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 990fa9e4066Sahrens 99199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 99299653d4eSeschrock "one or more devices is less than the " 99399653d4eSeschrock "minimum size (%s)"), buf); 994fa9e4066Sahrens } 99599653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 996fa9e4066Sahrens 997fa9e4066Sahrens case ENOSPC: 99899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 99999653d4eSeschrock "one or more devices is out of space")); 100099653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1001fa9e4066Sahrens 1002fa94a07fSbrendan case ENOTBLK: 1003fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1004fa94a07fSbrendan "cache device must be a disk or disk slice")); 1005fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADDEV, msg)); 1006fa94a07fSbrendan 1007fa9e4066Sahrens default: 100899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1009fa9e4066Sahrens } 1010fa9e4066Sahrens } 1011fa9e4066Sahrens 1012fa9e4066Sahrens /* 1013fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 1014e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 1015fa9e4066Sahrens */ 1016990b4856Slling if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT), 1017990b4856Slling &altroot) == 0) { 1018fa9e4066Sahrens zfs_handle_t *zhp; 1019fa9e4066Sahrens 1020990b4856Slling verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL); 1021e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1022e9dbad6fSeschrock "/") == 0); 1023fa9e4066Sahrens 1024fa9e4066Sahrens zfs_close(zhp); 1025fa9e4066Sahrens } 1026fa9e4066Sahrens 10270a48a24eStimh create_failed: 1028351420b3Slling zcmd_free_nvlists(&zc); 10290a48a24eStimh nvlist_free(zc_props); 10300a48a24eStimh nvlist_free(zc_fsprops); 10310a48a24eStimh return (ret); 1032fa9e4066Sahrens } 1033fa9e4066Sahrens 1034fa9e4066Sahrens /* 1035fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1036fa9e4066Sahrens * datasets left in the pool. 1037fa9e4066Sahrens */ 1038fa9e4066Sahrens int 1039fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 1040fa9e4066Sahrens { 1041fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1042fa9e4066Sahrens zfs_handle_t *zfp = NULL; 104399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 104499653d4eSeschrock char msg[1024]; 1045fa9e4066Sahrens 1046fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 104799653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 104899653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 1049fa9e4066Sahrens return (-1); 1050fa9e4066Sahrens 1051fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1052fa9e4066Sahrens 1053ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 105499653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 105599653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 1056fa9e4066Sahrens 105799653d4eSeschrock if (errno == EROFS) { 105899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 105999653d4eSeschrock "one or more devices is read only")); 106099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 106199653d4eSeschrock } else { 106299653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1063fa9e4066Sahrens } 1064fa9e4066Sahrens 1065fa9e4066Sahrens if (zfp) 1066fa9e4066Sahrens zfs_close(zfp); 1067fa9e4066Sahrens return (-1); 1068fa9e4066Sahrens } 1069fa9e4066Sahrens 1070fa9e4066Sahrens if (zfp) { 1071fa9e4066Sahrens remove_mountpoint(zfp); 1072fa9e4066Sahrens zfs_close(zfp); 1073fa9e4066Sahrens } 1074fa9e4066Sahrens 1075fa9e4066Sahrens return (0); 1076fa9e4066Sahrens } 1077fa9e4066Sahrens 1078fa9e4066Sahrens /* 1079fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1080fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1081fa9e4066Sahrens */ 1082fa9e4066Sahrens int 1083fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1084fa9e4066Sahrens { 1085e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 108699653d4eSeschrock int ret; 108799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 108899653d4eSeschrock char msg[1024]; 1089fa94a07fSbrendan nvlist_t **spares, **l2cache; 1090fa94a07fSbrendan uint_t nspares, nl2cache; 109199653d4eSeschrock 109299653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 109399653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 109499653d4eSeschrock 1095fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1096fa94a07fSbrendan SPA_VERSION_SPARES && 109799653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 109899653d4eSeschrock &spares, &nspares) == 0) { 109999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 110099653d4eSeschrock "upgraded to add hot spares")); 110199653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 110299653d4eSeschrock } 1103fa9e4066Sahrens 1104b5b76fecSGeorge Wilson if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, 1105b5b76fecSGeorge Wilson ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { 1106b5b76fecSGeorge Wilson uint64_t s; 1107b5b76fecSGeorge Wilson 1108b5b76fecSGeorge Wilson for (s = 0; s < nspares; s++) { 1109b5b76fecSGeorge Wilson char *path; 1110b5b76fecSGeorge Wilson 1111b5b76fecSGeorge Wilson if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, 1112b5b76fecSGeorge Wilson &path) == 0 && pool_uses_efi(spares[s])) { 1113b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1114b5b76fecSGeorge Wilson "device '%s' contains an EFI label and " 1115b5b76fecSGeorge Wilson "cannot be used on root pools."), 111688ecc943SGeorge Wilson zpool_vdev_name(hdl, NULL, spares[s], 111788ecc943SGeorge Wilson B_FALSE)); 1118b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 1119b5b76fecSGeorge Wilson } 1120b5b76fecSGeorge Wilson } 1121b5b76fecSGeorge Wilson } 1122b5b76fecSGeorge Wilson 1123fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1124fa94a07fSbrendan SPA_VERSION_L2CACHE && 1125fa94a07fSbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1126fa94a07fSbrendan &l2cache, &nl2cache) == 0) { 1127fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 1128fa94a07fSbrendan "upgraded to add cache devices")); 1129fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 1130fa94a07fSbrendan } 1131fa94a07fSbrendan 1132990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 113399653d4eSeschrock return (-1); 1134fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1135fa9e4066Sahrens 1136ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1137fa9e4066Sahrens switch (errno) { 1138fa9e4066Sahrens case EBUSY: 1139fa9e4066Sahrens /* 1140fa9e4066Sahrens * This can happen if the user has specified the same 1141fa9e4066Sahrens * device multiple times. We can't reliably detect this 1142fa9e4066Sahrens * until we try to add it and see we already have a 1143fa9e4066Sahrens * label. 1144fa9e4066Sahrens */ 114599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 114699653d4eSeschrock "one or more vdevs refer to the same device")); 114799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1148fa9e4066Sahrens break; 1149fa9e4066Sahrens 1150fa9e4066Sahrens case EOVERFLOW: 1151fa9e4066Sahrens /* 1152fa9e4066Sahrens * This occurrs when one of the devices is below 1153fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1154fa9e4066Sahrens * device was the problem device since there's no 1155fa9e4066Sahrens * reliable way to determine device size from userland. 1156fa9e4066Sahrens */ 1157fa9e4066Sahrens { 1158fa9e4066Sahrens char buf[64]; 1159fa9e4066Sahrens 1160fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1161fa9e4066Sahrens 116299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116399653d4eSeschrock "device is less than the minimum " 116499653d4eSeschrock "size (%s)"), buf); 1165fa9e4066Sahrens } 116699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 116799653d4eSeschrock break; 116899653d4eSeschrock 116999653d4eSeschrock case ENOTSUP: 117099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11718654d025Sperrin "pool must be upgraded to add these vdevs")); 117299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1173fa9e4066Sahrens break; 1174fa9e4066Sahrens 1175b1b8ab34Slling case EDOM: 1176b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11778654d025Sperrin "root pool can not have multiple vdevs" 11788654d025Sperrin " or separate logs")); 1179b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 1180b1b8ab34Slling break; 1181b1b8ab34Slling 1182fa94a07fSbrendan case ENOTBLK: 1183fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1184fa94a07fSbrendan "cache device must be a disk or disk slice")); 1185fa94a07fSbrendan (void) zfs_error(hdl, EZFS_BADDEV, msg); 1186fa94a07fSbrendan break; 1187fa94a07fSbrendan 1188fa9e4066Sahrens default: 118999653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1190fa9e4066Sahrens } 1191fa9e4066Sahrens 119299653d4eSeschrock ret = -1; 119399653d4eSeschrock } else { 119499653d4eSeschrock ret = 0; 1195fa9e4066Sahrens } 1196fa9e4066Sahrens 1197e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1198fa9e4066Sahrens 119999653d4eSeschrock return (ret); 1200fa9e4066Sahrens } 1201fa9e4066Sahrens 1202fa9e4066Sahrens /* 1203fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 1204fa9e4066Sahrens * mounted datasets in the pool. 1205fa9e4066Sahrens */ 1206fa9e4066Sahrens int 1207394ab0cbSGeorge Wilson zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) 1208fa9e4066Sahrens { 1209fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 121089a89ebfSlling char msg[1024]; 1211fa9e4066Sahrens 121289a89ebfSlling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 121389a89ebfSlling "cannot export '%s'"), zhp->zpool_name); 121489a89ebfSlling 1215fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 121689a89ebfSlling zc.zc_cookie = force; 1217394ab0cbSGeorge Wilson zc.zc_guid = hardforce; 121889a89ebfSlling 121989a89ebfSlling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 122089a89ebfSlling switch (errno) { 122189a89ebfSlling case EXDEV: 122289a89ebfSlling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 122389a89ebfSlling "use '-f' to override the following errors:\n" 122489a89ebfSlling "'%s' has an active shared spare which could be" 122589a89ebfSlling " used by other pools once '%s' is exported."), 122689a89ebfSlling zhp->zpool_name, zhp->zpool_name); 122789a89ebfSlling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 122889a89ebfSlling msg)); 122989a89ebfSlling default: 123089a89ebfSlling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 123189a89ebfSlling msg)); 123289a89ebfSlling } 123389a89ebfSlling } 1234fa9e4066Sahrens 1235fa9e4066Sahrens return (0); 1236fa9e4066Sahrens } 1237fa9e4066Sahrens 1238394ab0cbSGeorge Wilson int 1239394ab0cbSGeorge Wilson zpool_export(zpool_handle_t *zhp, boolean_t force) 1240394ab0cbSGeorge Wilson { 1241394ab0cbSGeorge Wilson return (zpool_export_common(zhp, force, B_FALSE)); 1242394ab0cbSGeorge Wilson } 1243394ab0cbSGeorge Wilson 1244394ab0cbSGeorge Wilson int 1245394ab0cbSGeorge Wilson zpool_export_force(zpool_handle_t *zhp) 1246394ab0cbSGeorge Wilson { 1247394ab0cbSGeorge Wilson return (zpool_export_common(zhp, B_TRUE, B_TRUE)); 1248394ab0cbSGeorge Wilson } 1249394ab0cbSGeorge Wilson 1250468c413aSTim Haley static void 1251468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 1252468c413aSTim Haley nvlist_t *rbi) 1253468c413aSTim Haley { 1254468c413aSTim Haley uint64_t rewindto; 1255468c413aSTim Haley int64_t loss = -1; 1256468c413aSTim Haley struct tm t; 1257468c413aSTim Haley char timestr[128]; 1258468c413aSTim Haley 1259468c413aSTim Haley if (!hdl->libzfs_printerr || rbi == NULL) 1260468c413aSTim Haley return; 1261468c413aSTim Haley 1262468c413aSTim Haley if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1263468c413aSTim Haley return; 1264468c413aSTim Haley (void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss); 1265468c413aSTim Haley 1266468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1267468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1268468c413aSTim Haley if (dryrun) { 1269468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1270468c413aSTim Haley "Would be able to return %s " 1271468c413aSTim Haley "to its state as of %s.\n"), 1272468c413aSTim Haley name, timestr); 1273468c413aSTim Haley } else { 1274468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1275468c413aSTim Haley "Pool %s returned to its state as of %s.\n"), 1276468c413aSTim Haley name, timestr); 1277468c413aSTim Haley } 1278468c413aSTim Haley if (loss > 120) { 1279468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1280468c413aSTim Haley "%s approximately %lld "), 1281468c413aSTim Haley dryrun ? "Would discard" : "Discarded", 1282468c413aSTim Haley (loss + 30) / 60); 1283468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1284468c413aSTim Haley "minutes of transactions.\n")); 1285468c413aSTim Haley } else if (loss > 0) { 1286468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1287468c413aSTim Haley "%s approximately %lld "), 1288468c413aSTim Haley dryrun ? "Would discard" : "Discarded", loss); 1289468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1290468c413aSTim Haley "seconds of transactions.\n")); 1291468c413aSTim Haley } 1292468c413aSTim Haley } 1293468c413aSTim Haley } 1294468c413aSTim Haley 1295468c413aSTim Haley void 1296468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 1297468c413aSTim Haley nvlist_t *config) 1298468c413aSTim Haley { 1299468c413aSTim Haley int64_t loss = -1; 1300468c413aSTim Haley uint64_t edata = UINT64_MAX; 1301468c413aSTim Haley uint64_t rewindto; 1302468c413aSTim Haley struct tm t; 1303468c413aSTim Haley char timestr[128]; 1304468c413aSTim Haley 1305468c413aSTim Haley if (!hdl->libzfs_printerr) 1306468c413aSTim Haley return; 1307468c413aSTim Haley 1308468c413aSTim Haley if (reason >= 0) 1309468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 1310468c413aSTim Haley else 1311468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "\t")); 1312468c413aSTim Haley 1313468c413aSTim Haley /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 1314468c413aSTim Haley if (nvlist_lookup_uint64(config, 1315468c413aSTim Haley ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1316468c413aSTim Haley goto no_info; 1317468c413aSTim Haley 1318468c413aSTim Haley (void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss); 1319468c413aSTim Haley (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 1320468c413aSTim Haley &edata); 1321468c413aSTim Haley 1322468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1323468c413aSTim Haley "Recovery is possible, but will result in some data loss.\n")); 1324468c413aSTim Haley 1325468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1326468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1327468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1328468c413aSTim Haley "\tReturning the pool to its state as of %s\n" 1329468c413aSTim Haley "\tshould correct the problem. "), 1330468c413aSTim Haley timestr); 1331468c413aSTim Haley } else { 1332468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1333468c413aSTim Haley "\tReverting the pool to an earlier state " 1334468c413aSTim Haley "should correct the problem.\n\t")); 1335468c413aSTim Haley } 1336468c413aSTim Haley 1337468c413aSTim Haley if (loss > 120) { 1338468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1339468c413aSTim Haley "Approximately %lld minutes of data\n" 1340468c413aSTim Haley "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 1341468c413aSTim Haley } else if (loss > 0) { 1342468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1343468c413aSTim Haley "Approximately %lld seconds of data\n" 1344468c413aSTim Haley "\tmust be discarded, irreversibly. "), loss); 1345468c413aSTim Haley } 1346468c413aSTim Haley if (edata != 0 && edata != UINT64_MAX) { 1347468c413aSTim Haley if (edata == 1) { 1348468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1349468c413aSTim Haley "After rewind, at least\n" 1350468c413aSTim Haley "\tone persistent user-data error will remain. ")); 1351468c413aSTim Haley } else { 1352468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1353468c413aSTim Haley "After rewind, several\n" 1354468c413aSTim Haley "\tpersistent user-data errors will remain. ")); 1355468c413aSTim Haley } 1356468c413aSTim Haley } 1357468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1358468c413aSTim Haley "Recovery can be\n\tattempted by executing " 1359468c413aSTim Haley "'zpool %s -F %s'. "), reason >= 0 ? "clear" : "import", name); 1360468c413aSTim Haley 1361468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1362468c413aSTim Haley "A scrub of the pool\n" 1363468c413aSTim Haley "\tis strongly recommended after recovery.\n")); 1364468c413aSTim Haley return; 1365468c413aSTim Haley 1366468c413aSTim Haley no_info: 1367468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1368468c413aSTim Haley "Destroy and re-create the pool from\n\ta backup source.\n")); 1369468c413aSTim Haley } 1370468c413aSTim Haley 1371fa9e4066Sahrens /* 1372990b4856Slling * zpool_import() is a contracted interface. Should be kept the same 1373990b4856Slling * if possible. 1374990b4856Slling * 1375990b4856Slling * Applications should use zpool_import_props() to import a pool with 1376990b4856Slling * new properties value to be set. 1377fa9e4066Sahrens */ 1378fa9e4066Sahrens int 137999653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1380990b4856Slling char *altroot) 1381990b4856Slling { 1382990b4856Slling nvlist_t *props = NULL; 1383990b4856Slling int ret; 1384990b4856Slling 1385990b4856Slling if (altroot != NULL) { 1386990b4856Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1387990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1388990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1389990b4856Slling newname)); 1390990b4856Slling } 1391990b4856Slling 1392990b4856Slling if (nvlist_add_string(props, 1393352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 1394352d8027SGeorge Wilson nvlist_add_string(props, 1395352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 1396990b4856Slling nvlist_free(props); 1397990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1398990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1399990b4856Slling newname)); 1400990b4856Slling } 1401990b4856Slling } 1402990b4856Slling 1403c5904d13Seschrock ret = zpool_import_props(hdl, config, newname, props, B_FALSE); 1404990b4856Slling if (props) 1405990b4856Slling nvlist_free(props); 1406990b4856Slling return (ret); 1407990b4856Slling } 1408990b4856Slling 1409990b4856Slling /* 1410990b4856Slling * Import the given pool using the known configuration and a list of 1411990b4856Slling * properties to be set. The configuration should have come from 1412990b4856Slling * zpool_find_import(). The 'newname' parameters control whether the pool 1413990b4856Slling * is imported with a different name. 1414990b4856Slling */ 1415990b4856Slling int 1416990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1417c5904d13Seschrock nvlist_t *props, boolean_t importfaulted) 1418fa9e4066Sahrens { 1419e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 1420468c413aSTim Haley zpool_rewind_policy_t policy; 1421468c413aSTim Haley nvlist_t *nvi = NULL; 1422fa9e4066Sahrens char *thename; 1423fa9e4066Sahrens char *origname; 1424468c413aSTim Haley uint64_t returned_size; 1425fa9e4066Sahrens int ret; 1426990b4856Slling char errbuf[1024]; 1427fa9e4066Sahrens 1428fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1429fa9e4066Sahrens &origname) == 0); 1430fa9e4066Sahrens 1431990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1432990b4856Slling "cannot import pool '%s'"), origname); 1433990b4856Slling 1434fa9e4066Sahrens if (newname != NULL) { 143599653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 1436ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 143799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 143899653d4eSeschrock newname)); 1439fa9e4066Sahrens thename = (char *)newname; 1440fa9e4066Sahrens } else { 1441fa9e4066Sahrens thename = origname; 1442fa9e4066Sahrens } 1443fa9e4066Sahrens 1444990b4856Slling if (props) { 1445990b4856Slling uint64_t version; 1446fa9e4066Sahrens 1447990b4856Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 1448990b4856Slling &version) == 0); 1449fa9e4066Sahrens 14500a48a24eStimh if ((props = zpool_valid_proplist(hdl, origname, 1451351420b3Slling props, version, B_TRUE, errbuf)) == NULL) { 1452990b4856Slling return (-1); 1453351420b3Slling } else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 1454351420b3Slling nvlist_free(props); 1455990b4856Slling return (-1); 1456351420b3Slling } 1457990b4856Slling } 1458990b4856Slling 1459990b4856Slling (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1460fa9e4066Sahrens 1461fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1462ea8dc4b6Seschrock &zc.zc_guid) == 0); 1463fa9e4066Sahrens 1464351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 1465351420b3Slling nvlist_free(props); 146699653d4eSeschrock return (-1); 1467351420b3Slling } 1468468c413aSTim Haley returned_size = zc.zc_nvlist_conf_size + 512; 1469468c413aSTim Haley if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) { 1470468c413aSTim Haley nvlist_free(props); 1471468c413aSTim Haley return (-1); 1472468c413aSTim Haley } 1473fa9e4066Sahrens 1474c5904d13Seschrock zc.zc_cookie = (uint64_t)importfaulted; 1475fa9e4066Sahrens ret = 0; 1476ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 1477fa9e4066Sahrens char desc[1024]; 1478468c413aSTim Haley 1479468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 1480468c413aSTim Haley zpool_get_rewind_policy(config, &policy); 1481468c413aSTim Haley /* 1482468c413aSTim Haley * Dry-run failed, but we print out what success 1483468c413aSTim Haley * looks like if we found a best txg 1484468c413aSTim Haley */ 1485468c413aSTim Haley if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) { 1486468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 1487468c413aSTim Haley B_TRUE, nvi); 1488468c413aSTim Haley nvlist_free(nvi); 1489468c413aSTim Haley return (-1); 1490468c413aSTim Haley } 1491468c413aSTim Haley 1492fa9e4066Sahrens if (newname == NULL) 1493fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1494fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1495fa9e4066Sahrens thename); 1496fa9e4066Sahrens else 1497fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1498fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1499fa9e4066Sahrens origname, thename); 1500fa9e4066Sahrens 1501fa9e4066Sahrens switch (errno) { 1502ea8dc4b6Seschrock case ENOTSUP: 1503ea8dc4b6Seschrock /* 1504ea8dc4b6Seschrock * Unsupported version. 1505ea8dc4b6Seschrock */ 150699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 1507ea8dc4b6Seschrock break; 1508ea8dc4b6Seschrock 1509b5989ec7Seschrock case EINVAL: 1510b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 1511b5989ec7Seschrock break; 1512b5989ec7Seschrock 1513fa9e4066Sahrens default: 1514468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 151599653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 1516468c413aSTim Haley zpool_explain_recover(hdl, 1517468c413aSTim Haley newname ? origname : thename, -errno, nvi); 1518468c413aSTim Haley nvlist_free(nvi); 1519468c413aSTim Haley break; 1520fa9e4066Sahrens } 1521fa9e4066Sahrens 1522fa9e4066Sahrens ret = -1; 1523fa9e4066Sahrens } else { 1524fa9e4066Sahrens zpool_handle_t *zhp; 1525ecd6cf80Smarks 1526fa9e4066Sahrens /* 1527fa9e4066Sahrens * This should never fail, but play it safe anyway. 1528fa9e4066Sahrens */ 1529681d9761SEric Taylor if (zpool_open_silent(hdl, thename, &zhp) != 0) 153094de1d4cSeschrock ret = -1; 1531681d9761SEric Taylor else if (zhp != NULL) 1532fa9e4066Sahrens zpool_close(zhp); 1533468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 1534468c413aSTim Haley zpool_get_rewind_policy(config, &policy); 1535468c413aSTim Haley if (policy.zrp_request & 1536468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 1537468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 1538468c413aSTim Haley ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 1539468c413aSTim Haley nvi); 1540468c413aSTim Haley } 1541468c413aSTim Haley nvlist_free(nvi); 1542468c413aSTim Haley return (0); 1543fa9e4066Sahrens } 1544fa9e4066Sahrens 1545e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1546351420b3Slling nvlist_free(props); 1547351420b3Slling 1548fa9e4066Sahrens return (ret); 1549fa9e4066Sahrens } 1550fa9e4066Sahrens 1551fa9e4066Sahrens /* 1552fa9e4066Sahrens * Scrub the pool. 1553fa9e4066Sahrens */ 1554fa9e4066Sahrens int 1555fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 1556fa9e4066Sahrens { 1557fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1558fa9e4066Sahrens char msg[1024]; 155999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1560fa9e4066Sahrens 1561fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1562fa9e4066Sahrens zc.zc_cookie = type; 1563fa9e4066Sahrens 1564ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 1565fa9e4066Sahrens return (0); 1566fa9e4066Sahrens 1567fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 1568fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 1569fa9e4066Sahrens 157099653d4eSeschrock if (errno == EBUSY) 157199653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 157299653d4eSeschrock else 157399653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1574fa9e4066Sahrens } 1575fa9e4066Sahrens 1576a43d325bSek /* 1577573ca77eSGeorge Wilson * Find a vdev that matches the search criteria specified. We use the 1578573ca77eSGeorge Wilson * the nvpair name to determine how we should look for the device. 1579a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 1580a43d325bSek * spare; but FALSE if its an INUSE spare. 1581a43d325bSek */ 158299653d4eSeschrock static nvlist_t * 1583573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 1584573ca77eSGeorge Wilson boolean_t *l2cache, boolean_t *log) 1585ea8dc4b6Seschrock { 1586ea8dc4b6Seschrock uint_t c, children; 1587ea8dc4b6Seschrock nvlist_t **child; 158899653d4eSeschrock nvlist_t *ret; 1589ee0eb9f2SEric Schrock uint64_t is_log; 1590573ca77eSGeorge Wilson char *srchkey; 1591573ca77eSGeorge Wilson nvpair_t *pair = nvlist_next_nvpair(search, NULL); 1592573ca77eSGeorge Wilson 1593573ca77eSGeorge Wilson /* Nothing to look for */ 1594573ca77eSGeorge Wilson if (search == NULL || pair == NULL) 1595573ca77eSGeorge Wilson return (NULL); 1596ea8dc4b6Seschrock 1597573ca77eSGeorge Wilson /* Obtain the key we will use to search */ 1598573ca77eSGeorge Wilson srchkey = nvpair_name(pair); 1599573ca77eSGeorge Wilson 1600573ca77eSGeorge Wilson switch (nvpair_type(pair)) { 1601573ca77eSGeorge Wilson case DATA_TYPE_UINT64: { 1602573ca77eSGeorge Wilson uint64_t srchval, theguid, present; 1603573ca77eSGeorge Wilson 1604573ca77eSGeorge Wilson verify(nvpair_value_uint64(pair, &srchval) == 0); 1605573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 1606573ca77eSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1607573ca77eSGeorge Wilson &present) == 0) { 1608573ca77eSGeorge Wilson /* 1609573ca77eSGeorge Wilson * If the device has never been present since 1610573ca77eSGeorge Wilson * import, the only reliable way to match the 1611573ca77eSGeorge Wilson * vdev is by GUID. 1612573ca77eSGeorge Wilson */ 1613573ca77eSGeorge Wilson verify(nvlist_lookup_uint64(nv, 1614573ca77eSGeorge Wilson ZPOOL_CONFIG_GUID, &theguid) == 0); 1615573ca77eSGeorge Wilson if (theguid == srchval) 1616573ca77eSGeorge Wilson return (nv); 1617573ca77eSGeorge Wilson } 1618573ca77eSGeorge Wilson } 1619573ca77eSGeorge Wilson break; 1620573ca77eSGeorge Wilson } 1621573ca77eSGeorge Wilson 1622573ca77eSGeorge Wilson case DATA_TYPE_STRING: { 1623573ca77eSGeorge Wilson char *srchval, *val; 1624573ca77eSGeorge Wilson 1625573ca77eSGeorge Wilson verify(nvpair_value_string(pair, &srchval) == 0); 1626573ca77eSGeorge Wilson if (nvlist_lookup_string(nv, srchkey, &val) != 0) 1627573ca77eSGeorge Wilson break; 1628ea8dc4b6Seschrock 1629ea8dc4b6Seschrock /* 1630573ca77eSGeorge Wilson * Search for the requested value. We special case the search 163188ecc943SGeorge Wilson * for ZPOOL_CONFIG_PATH when it's a wholedisk and when 163288ecc943SGeorge Wilson * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 163388ecc943SGeorge Wilson * Otherwise, all other searches are simple string compares. 1634ea8dc4b6Seschrock */ 1635573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) { 1636573ca77eSGeorge Wilson uint64_t wholedisk = 0; 1637573ca77eSGeorge Wilson 1638573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1639573ca77eSGeorge Wilson &wholedisk); 1640573ca77eSGeorge Wilson if (wholedisk) { 1641573ca77eSGeorge Wilson /* 1642573ca77eSGeorge Wilson * For whole disks, the internal path has 's0', 1643573ca77eSGeorge Wilson * but the path passed in by the user doesn't. 1644573ca77eSGeorge Wilson */ 1645573ca77eSGeorge Wilson if (strlen(srchval) == strlen(val) - 2 && 1646573ca77eSGeorge Wilson strncmp(srchval, val, strlen(srchval)) == 0) 1647573ca77eSGeorge Wilson return (nv); 1648573ca77eSGeorge Wilson break; 1649573ca77eSGeorge Wilson } 165088ecc943SGeorge Wilson } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 165188ecc943SGeorge Wilson char *type, *idx, *end, *p; 165288ecc943SGeorge Wilson uint64_t id, vdev_id; 165388ecc943SGeorge Wilson 165488ecc943SGeorge Wilson /* 165588ecc943SGeorge Wilson * Determine our vdev type, keeping in mind 165688ecc943SGeorge Wilson * that the srchval is composed of a type and 165788ecc943SGeorge Wilson * vdev id pair (i.e. mirror-4). 165888ecc943SGeorge Wilson */ 165988ecc943SGeorge Wilson if ((type = strdup(srchval)) == NULL) 166088ecc943SGeorge Wilson return (NULL); 166188ecc943SGeorge Wilson 166288ecc943SGeorge Wilson if ((p = strrchr(type, '-')) == NULL) { 166388ecc943SGeorge Wilson free(type); 166488ecc943SGeorge Wilson break; 166588ecc943SGeorge Wilson } 166688ecc943SGeorge Wilson idx = p + 1; 166788ecc943SGeorge Wilson *p = '\0'; 166888ecc943SGeorge Wilson 166988ecc943SGeorge Wilson /* 167088ecc943SGeorge Wilson * If the types don't match then keep looking. 167188ecc943SGeorge Wilson */ 167288ecc943SGeorge Wilson if (strncmp(val, type, strlen(val)) != 0) { 167388ecc943SGeorge Wilson free(type); 167488ecc943SGeorge Wilson break; 167588ecc943SGeorge Wilson } 167688ecc943SGeorge Wilson 167788ecc943SGeorge Wilson verify(strncmp(type, VDEV_TYPE_RAIDZ, 167888ecc943SGeorge Wilson strlen(VDEV_TYPE_RAIDZ)) == 0 || 167988ecc943SGeorge Wilson strncmp(type, VDEV_TYPE_MIRROR, 168088ecc943SGeorge Wilson strlen(VDEV_TYPE_MIRROR)) == 0); 168188ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 168288ecc943SGeorge Wilson &id) == 0); 168388ecc943SGeorge Wilson 168488ecc943SGeorge Wilson errno = 0; 168588ecc943SGeorge Wilson vdev_id = strtoull(idx, &end, 10); 168688ecc943SGeorge Wilson 168788ecc943SGeorge Wilson free(type); 168888ecc943SGeorge Wilson if (errno != 0) 168988ecc943SGeorge Wilson return (NULL); 169088ecc943SGeorge Wilson 169188ecc943SGeorge Wilson /* 169288ecc943SGeorge Wilson * Now verify that we have the correct vdev id. 169388ecc943SGeorge Wilson */ 169488ecc943SGeorge Wilson if (vdev_id == id) 169588ecc943SGeorge Wilson return (nv); 1696ea8dc4b6Seschrock } 1697573ca77eSGeorge Wilson 1698573ca77eSGeorge Wilson /* 1699573ca77eSGeorge Wilson * Common case 1700573ca77eSGeorge Wilson */ 1701573ca77eSGeorge Wilson if (strcmp(srchval, val) == 0) 1702573ca77eSGeorge Wilson return (nv); 1703573ca77eSGeorge Wilson break; 1704573ca77eSGeorge Wilson } 1705573ca77eSGeorge Wilson 1706573ca77eSGeorge Wilson default: 1707573ca77eSGeorge Wilson break; 1708ea8dc4b6Seschrock } 1709ea8dc4b6Seschrock 1710ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1711ea8dc4b6Seschrock &child, &children) != 0) 171299653d4eSeschrock return (NULL); 1713ea8dc4b6Seschrock 1714ee0eb9f2SEric Schrock for (c = 0; c < children; c++) { 1715573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1716ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1717ee0eb9f2SEric Schrock /* 1718ee0eb9f2SEric Schrock * The 'is_log' value is only set for the toplevel 1719ee0eb9f2SEric Schrock * vdev, not the leaf vdevs. So we always lookup the 1720ee0eb9f2SEric Schrock * log device from the root of the vdev tree (where 1721ee0eb9f2SEric Schrock * 'log' is non-NULL). 1722ee0eb9f2SEric Schrock */ 1723ee0eb9f2SEric Schrock if (log != NULL && 1724ee0eb9f2SEric Schrock nvlist_lookup_uint64(child[c], 1725ee0eb9f2SEric Schrock ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 1726ee0eb9f2SEric Schrock is_log) { 1727ee0eb9f2SEric Schrock *log = B_TRUE; 1728ee0eb9f2SEric Schrock } 1729ea8dc4b6Seschrock return (ret); 1730ee0eb9f2SEric Schrock } 1731ee0eb9f2SEric Schrock } 1732ea8dc4b6Seschrock 173399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 173499653d4eSeschrock &child, &children) == 0) { 173599653d4eSeschrock for (c = 0; c < children; c++) { 1736573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1737ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1738a43d325bSek *avail_spare = B_TRUE; 173999653d4eSeschrock return (ret); 174099653d4eSeschrock } 174199653d4eSeschrock } 174299653d4eSeschrock } 174399653d4eSeschrock 1744fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1745fa94a07fSbrendan &child, &children) == 0) { 1746fa94a07fSbrendan for (c = 0; c < children; c++) { 1747573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 1748ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 1749fa94a07fSbrendan *l2cache = B_TRUE; 1750fa94a07fSbrendan return (ret); 1751fa94a07fSbrendan } 1752fa94a07fSbrendan } 1753fa94a07fSbrendan } 1754fa94a07fSbrendan 175599653d4eSeschrock return (NULL); 1756ea8dc4b6Seschrock } 1757ea8dc4b6Seschrock 1758573ca77eSGeorge Wilson /* 1759573ca77eSGeorge Wilson * Given a physical path (minus the "/devices" prefix), find the 1760573ca77eSGeorge Wilson * associated vdev. 1761573ca77eSGeorge Wilson */ 1762573ca77eSGeorge Wilson nvlist_t * 1763573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 1764573ca77eSGeorge Wilson boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 1765573ca77eSGeorge Wilson { 1766573ca77eSGeorge Wilson nvlist_t *search, *nvroot, *ret; 1767573ca77eSGeorge Wilson 1768573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1769573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 1770573ca77eSGeorge Wilson 1771573ca77eSGeorge Wilson verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1772573ca77eSGeorge Wilson &nvroot) == 0); 1773573ca77eSGeorge Wilson 1774573ca77eSGeorge Wilson *avail_spare = B_FALSE; 1775573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1776573ca77eSGeorge Wilson nvlist_free(search); 1777573ca77eSGeorge Wilson 1778573ca77eSGeorge Wilson return (ret); 1779573ca77eSGeorge Wilson } 1780573ca77eSGeorge Wilson 178188ecc943SGeorge Wilson /* 178288ecc943SGeorge Wilson * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 178388ecc943SGeorge Wilson */ 178488ecc943SGeorge Wilson boolean_t 178588ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name) 178688ecc943SGeorge Wilson { 178788ecc943SGeorge Wilson if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 178888ecc943SGeorge Wilson strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 178988ecc943SGeorge Wilson return (B_TRUE); 179088ecc943SGeorge Wilson return (B_FALSE); 179188ecc943SGeorge Wilson } 179288ecc943SGeorge Wilson 179399653d4eSeschrock nvlist_t * 1794fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 1795ee0eb9f2SEric Schrock boolean_t *l2cache, boolean_t *log) 1796ea8dc4b6Seschrock { 1797ea8dc4b6Seschrock char buf[MAXPATHLEN]; 1798ea8dc4b6Seschrock char *end; 1799573ca77eSGeorge Wilson nvlist_t *nvroot, *search, *ret; 1800ea8dc4b6Seschrock uint64_t guid; 1801ea8dc4b6Seschrock 1802573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 1803573ca77eSGeorge Wilson 18040917b783Seschrock guid = strtoull(path, &end, 10); 1805ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 1806573ca77eSGeorge Wilson verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 180788ecc943SGeorge Wilson } else if (zpool_vdev_is_interior(path)) { 180888ecc943SGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 1809ea8dc4b6Seschrock } else if (path[0] != '/') { 1810ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 1811573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 1812ea8dc4b6Seschrock } else { 1813573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 1814ea8dc4b6Seschrock } 1815ea8dc4b6Seschrock 1816ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 1817ea8dc4b6Seschrock &nvroot) == 0); 1818ea8dc4b6Seschrock 1819a43d325bSek *avail_spare = B_FALSE; 1820fa94a07fSbrendan *l2cache = B_FALSE; 1821ee0eb9f2SEric Schrock if (log != NULL) 1822ee0eb9f2SEric Schrock *log = B_FALSE; 1823573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 1824573ca77eSGeorge Wilson nvlist_free(search); 1825573ca77eSGeorge Wilson 1826573ca77eSGeorge Wilson return (ret); 1827a43d325bSek } 1828a43d325bSek 182919397407SSherry Moore static int 183019397407SSherry Moore vdev_online(nvlist_t *nv) 183119397407SSherry Moore { 183219397407SSherry Moore uint64_t ival; 183319397407SSherry Moore 183419397407SSherry Moore if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 183519397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 183619397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 183719397407SSherry Moore return (0); 183819397407SSherry Moore 183919397407SSherry Moore return (1); 184019397407SSherry Moore } 184119397407SSherry Moore 184219397407SSherry Moore /* 184321ecdf64SLin Ling * Helper function for zpool_get_physpaths(). 184419397407SSherry Moore */ 1845753a6d45SSherry Moore static int 184621ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 1847753a6d45SSherry Moore size_t *bytes_written) 184819397407SSherry Moore { 1849753a6d45SSherry Moore size_t bytes_left, pos, rsz; 1850753a6d45SSherry Moore char *tmppath; 1851753a6d45SSherry Moore const char *format; 1852753a6d45SSherry Moore 1853753a6d45SSherry Moore if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 1854753a6d45SSherry Moore &tmppath) != 0) 1855753a6d45SSherry Moore return (EZFS_NODEVICE); 1856753a6d45SSherry Moore 1857753a6d45SSherry Moore pos = *bytes_written; 1858753a6d45SSherry Moore bytes_left = physpath_size - pos; 1859753a6d45SSherry Moore format = (pos == 0) ? "%s" : " %s"; 1860753a6d45SSherry Moore 1861753a6d45SSherry Moore rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 1862753a6d45SSherry Moore *bytes_written += rsz; 1863753a6d45SSherry Moore 1864753a6d45SSherry Moore if (rsz >= bytes_left) { 1865753a6d45SSherry Moore /* if physpath was not copied properly, clear it */ 1866753a6d45SSherry Moore if (bytes_left != 0) { 1867753a6d45SSherry Moore physpath[pos] = 0; 1868753a6d45SSherry Moore } 1869753a6d45SSherry Moore return (EZFS_NOSPC); 1870753a6d45SSherry Moore } 1871753a6d45SSherry Moore return (0); 1872753a6d45SSherry Moore } 1873753a6d45SSherry Moore 187421ecdf64SLin Ling static int 187521ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 187621ecdf64SLin Ling size_t *rsz, boolean_t is_spare) 187721ecdf64SLin Ling { 187821ecdf64SLin Ling char *type; 187921ecdf64SLin Ling int ret; 188021ecdf64SLin Ling 188121ecdf64SLin Ling if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 188221ecdf64SLin Ling return (EZFS_INVALCONFIG); 188321ecdf64SLin Ling 188421ecdf64SLin Ling if (strcmp(type, VDEV_TYPE_DISK) == 0) { 188521ecdf64SLin Ling /* 188621ecdf64SLin Ling * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 188721ecdf64SLin Ling * For a spare vdev, we only want to boot from the active 188821ecdf64SLin Ling * spare device. 188921ecdf64SLin Ling */ 189021ecdf64SLin Ling if (is_spare) { 189121ecdf64SLin Ling uint64_t spare = 0; 189221ecdf64SLin Ling (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 189321ecdf64SLin Ling &spare); 189421ecdf64SLin Ling if (!spare) 189521ecdf64SLin Ling return (EZFS_INVALCONFIG); 189621ecdf64SLin Ling } 189721ecdf64SLin Ling 189821ecdf64SLin Ling if (vdev_online(nv)) { 189921ecdf64SLin Ling if ((ret = vdev_get_one_physpath(nv, physpath, 190021ecdf64SLin Ling phypath_size, rsz)) != 0) 190121ecdf64SLin Ling return (ret); 190221ecdf64SLin Ling } 190321ecdf64SLin Ling } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 190421ecdf64SLin Ling strcmp(type, VDEV_TYPE_REPLACING) == 0 || 190521ecdf64SLin Ling (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 190621ecdf64SLin Ling nvlist_t **child; 190721ecdf64SLin Ling uint_t count; 190821ecdf64SLin Ling int i, ret; 190921ecdf64SLin Ling 191021ecdf64SLin Ling if (nvlist_lookup_nvlist_array(nv, 191121ecdf64SLin Ling ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 191221ecdf64SLin Ling return (EZFS_INVALCONFIG); 191321ecdf64SLin Ling 191421ecdf64SLin Ling for (i = 0; i < count; i++) { 191521ecdf64SLin Ling ret = vdev_get_physpaths(child[i], physpath, 191621ecdf64SLin Ling phypath_size, rsz, is_spare); 191721ecdf64SLin Ling if (ret == EZFS_NOSPC) 191821ecdf64SLin Ling return (ret); 191921ecdf64SLin Ling } 192021ecdf64SLin Ling } 192121ecdf64SLin Ling 192221ecdf64SLin Ling return (EZFS_POOL_INVALARG); 192321ecdf64SLin Ling } 192421ecdf64SLin Ling 1925753a6d45SSherry Moore /* 1926753a6d45SSherry Moore * Get phys_path for a root pool config. 1927753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 1928753a6d45SSherry Moore */ 1929753a6d45SSherry Moore static int 1930753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 1931753a6d45SSherry Moore { 1932753a6d45SSherry Moore size_t rsz; 193319397407SSherry Moore nvlist_t *vdev_root; 193419397407SSherry Moore nvlist_t **child; 193519397407SSherry Moore uint_t count; 1936753a6d45SSherry Moore char *type; 1937753a6d45SSherry Moore 1938753a6d45SSherry Moore rsz = 0; 1939753a6d45SSherry Moore 1940753a6d45SSherry Moore if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1941753a6d45SSherry Moore &vdev_root) != 0) 1942753a6d45SSherry Moore return (EZFS_INVALCONFIG); 1943753a6d45SSherry Moore 1944753a6d45SSherry Moore if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 1945753a6d45SSherry Moore nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 1946753a6d45SSherry Moore &child, &count) != 0) 1947753a6d45SSherry Moore return (EZFS_INVALCONFIG); 194819397407SSherry Moore 194919397407SSherry Moore /* 1950753a6d45SSherry Moore * root pool can not have EFI labeled disks and can only have 1951753a6d45SSherry Moore * a single top-level vdev. 195219397407SSherry Moore */ 1953753a6d45SSherry Moore if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || 1954753a6d45SSherry Moore pool_uses_efi(vdev_root)) 1955753a6d45SSherry Moore return (EZFS_POOL_INVALARG); 195619397407SSherry Moore 195721ecdf64SLin Ling (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 195821ecdf64SLin Ling B_FALSE); 195919397407SSherry Moore 1960753a6d45SSherry Moore /* No online devices */ 1961753a6d45SSherry Moore if (rsz == 0) 1962753a6d45SSherry Moore return (EZFS_NODEVICE); 1963753a6d45SSherry Moore 196419397407SSherry Moore return (0); 196519397407SSherry Moore } 196619397407SSherry Moore 1967753a6d45SSherry Moore /* 1968753a6d45SSherry Moore * Get phys_path for a root pool 1969753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 1970753a6d45SSherry Moore */ 1971753a6d45SSherry Moore int 1972753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 1973753a6d45SSherry Moore { 1974753a6d45SSherry Moore return (zpool_get_config_physpath(zhp->zpool_config, physpath, 1975753a6d45SSherry Moore phypath_size)); 1976753a6d45SSherry Moore } 1977753a6d45SSherry Moore 1978573ca77eSGeorge Wilson /* 1979573ca77eSGeorge Wilson * If the device has being dynamically expanded then we need to relabel 1980573ca77eSGeorge Wilson * the disk to use the new unallocated space. 1981573ca77eSGeorge Wilson */ 1982573ca77eSGeorge Wilson static int 1983573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 1984573ca77eSGeorge Wilson { 1985573ca77eSGeorge Wilson char path[MAXPATHLEN]; 1986573ca77eSGeorge Wilson char errbuf[1024]; 1987573ca77eSGeorge Wilson int fd, error; 1988573ca77eSGeorge Wilson int (*_efi_use_whole_disk)(int); 1989573ca77eSGeorge Wilson 1990573ca77eSGeorge Wilson if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 1991573ca77eSGeorge Wilson "efi_use_whole_disk")) == NULL) 1992573ca77eSGeorge Wilson return (-1); 1993573ca77eSGeorge Wilson 1994573ca77eSGeorge Wilson (void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name); 1995573ca77eSGeorge Wilson 1996573ca77eSGeorge Wilson if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 1997573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 1998573ca77eSGeorge Wilson "relabel '%s': unable to open device"), name); 1999573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 2000573ca77eSGeorge Wilson } 2001573ca77eSGeorge Wilson 2002573ca77eSGeorge Wilson /* 2003573ca77eSGeorge Wilson * It's possible that we might encounter an error if the device 2004573ca77eSGeorge Wilson * does not have any unallocated space left. If so, we simply 2005573ca77eSGeorge Wilson * ignore that error and continue on. 2006573ca77eSGeorge Wilson */ 2007573ca77eSGeorge Wilson error = _efi_use_whole_disk(fd); 2008573ca77eSGeorge Wilson (void) close(fd); 2009573ca77eSGeorge Wilson if (error && error != VT_ENOSPC) { 2010573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 2011573ca77eSGeorge Wilson "relabel '%s': unable to read disk capacity"), name); 2012573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 2013573ca77eSGeorge Wilson } 2014573ca77eSGeorge Wilson return (0); 2015573ca77eSGeorge Wilson } 2016573ca77eSGeorge Wilson 2017fa9e4066Sahrens /* 20183d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 20193d7072f8Seschrock * ZFS_ONLINE_* flags. 2020fa9e4066Sahrens */ 2021fa9e4066Sahrens int 20223d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 20233d7072f8Seschrock vdev_state_t *newstate) 2024fa9e4066Sahrens { 2025fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2026fa9e4066Sahrens char msg[1024]; 202799653d4eSeschrock nvlist_t *tgt; 2028573ca77eSGeorge Wilson boolean_t avail_spare, l2cache, islog; 202999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2030fa9e4066Sahrens 2031573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND) { 2032573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2033573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 2034573ca77eSGeorge Wilson } else { 2035573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2036573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot online %s"), path); 2037573ca77eSGeorge Wilson } 2038ea8dc4b6Seschrock 2039fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2040ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2041573ca77eSGeorge Wilson &islog)) == NULL) 204299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2043fa9e4066Sahrens 204499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2045fa9e4066Sahrens 2046069f55e2SEric Schrock if (avail_spare) 2047a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2048a43d325bSek 2049573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND || 2050573ca77eSGeorge Wilson zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { 2051573ca77eSGeorge Wilson char *pathname = NULL; 2052573ca77eSGeorge Wilson uint64_t wholedisk = 0; 2053573ca77eSGeorge Wilson 2054573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 2055573ca77eSGeorge Wilson &wholedisk); 2056573ca77eSGeorge Wilson verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, 2057573ca77eSGeorge Wilson &pathname) == 0); 2058573ca77eSGeorge Wilson 2059573ca77eSGeorge Wilson /* 2060573ca77eSGeorge Wilson * XXX - L2ARC 1.0 devices can't support expansion. 2061573ca77eSGeorge Wilson */ 2062573ca77eSGeorge Wilson if (l2cache) { 2063573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2064573ca77eSGeorge Wilson "cannot expand cache devices")); 2065573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 2066573ca77eSGeorge Wilson } 2067573ca77eSGeorge Wilson 2068573ca77eSGeorge Wilson if (wholedisk) { 2069573ca77eSGeorge Wilson pathname += strlen(DISK_ROOT) + 1; 2070573ca77eSGeorge Wilson (void) zpool_relabel_disk(zhp->zpool_hdl, pathname); 2071573ca77eSGeorge Wilson } 2072573ca77eSGeorge Wilson } 2073573ca77eSGeorge Wilson 20743d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 20753d7072f8Seschrock zc.zc_obj = flags; 2076fa9e4066Sahrens 2077ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 20783d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 20793d7072f8Seschrock 20803d7072f8Seschrock *newstate = zc.zc_cookie; 20813d7072f8Seschrock return (0); 2082fa9e4066Sahrens } 2083fa9e4066Sahrens 2084fa9e4066Sahrens /* 2085fa9e4066Sahrens * Take the specified vdev offline 2086fa9e4066Sahrens */ 2087fa9e4066Sahrens int 20883d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2089fa9e4066Sahrens { 2090fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2091fa9e4066Sahrens char msg[1024]; 209299653d4eSeschrock nvlist_t *tgt; 2093fa94a07fSbrendan boolean_t avail_spare, l2cache; 209499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2095fa9e4066Sahrens 2096ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2097ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 2098ea8dc4b6Seschrock 2099fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2100ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2101ee0eb9f2SEric Schrock NULL)) == NULL) 210299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 210399653d4eSeschrock 210499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2105fa9e4066Sahrens 2106069f55e2SEric Schrock if (avail_spare) 2107a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2108a43d325bSek 21093d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 21103d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 21113d7072f8Seschrock 2112ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21133d7072f8Seschrock return (0); 21143d7072f8Seschrock 21153d7072f8Seschrock switch (errno) { 21163d7072f8Seschrock case EBUSY: 21173d7072f8Seschrock 21183d7072f8Seschrock /* 21193d7072f8Seschrock * There are no other replicas of this device. 21203d7072f8Seschrock */ 21213d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 21223d7072f8Seschrock 2123e6ca193dSGeorge Wilson case EEXIST: 2124e6ca193dSGeorge Wilson /* 2125e6ca193dSGeorge Wilson * The log device has unplayed logs 2126e6ca193dSGeorge Wilson */ 2127e6ca193dSGeorge Wilson return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 2128e6ca193dSGeorge Wilson 21293d7072f8Seschrock default: 21303d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 21313d7072f8Seschrock } 21323d7072f8Seschrock } 21333d7072f8Seschrock 21343d7072f8Seschrock /* 21353d7072f8Seschrock * Mark the given vdev faulted. 21363d7072f8Seschrock */ 21373d7072f8Seschrock int 2138069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21393d7072f8Seschrock { 21403d7072f8Seschrock zfs_cmd_t zc = { 0 }; 21413d7072f8Seschrock char msg[1024]; 21423d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21433d7072f8Seschrock 21443d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 21453d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 2146441d80aaSlling 21473d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21483d7072f8Seschrock zc.zc_guid = guid; 21493d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 2150069f55e2SEric Schrock zc.zc_obj = aux; 21513d7072f8Seschrock 21523d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2153fa9e4066Sahrens return (0); 2154fa9e4066Sahrens 2155fa9e4066Sahrens switch (errno) { 215699653d4eSeschrock case EBUSY: 2157fa9e4066Sahrens 2158fa9e4066Sahrens /* 2159fa9e4066Sahrens * There are no other replicas of this device. 2160fa9e4066Sahrens */ 216199653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 2162fa9e4066Sahrens 216399653d4eSeschrock default: 216499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2165fa9e4066Sahrens } 21663d7072f8Seschrock 21673d7072f8Seschrock } 21683d7072f8Seschrock 21693d7072f8Seschrock /* 21703d7072f8Seschrock * Mark the given vdev degraded. 21713d7072f8Seschrock */ 21723d7072f8Seschrock int 2173069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 21743d7072f8Seschrock { 21753d7072f8Seschrock zfs_cmd_t zc = { 0 }; 21763d7072f8Seschrock char msg[1024]; 21773d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 21783d7072f8Seschrock 21793d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 21803d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 21813d7072f8Seschrock 21823d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 21833d7072f8Seschrock zc.zc_guid = guid; 21843d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 2185069f55e2SEric Schrock zc.zc_obj = aux; 21863d7072f8Seschrock 21873d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 21883d7072f8Seschrock return (0); 21893d7072f8Seschrock 21903d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 219199653d4eSeschrock } 219299653d4eSeschrock 219399653d4eSeschrock /* 219499653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 219599653d4eSeschrock * a hot spare. 219699653d4eSeschrock */ 219799653d4eSeschrock static boolean_t 219899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 219999653d4eSeschrock { 220099653d4eSeschrock nvlist_t **child; 220199653d4eSeschrock uint_t c, children; 220299653d4eSeschrock char *type; 220399653d4eSeschrock 220499653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 220599653d4eSeschrock &children) == 0) { 220699653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 220799653d4eSeschrock &type) == 0); 220899653d4eSeschrock 220999653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 221099653d4eSeschrock children == 2 && child[which] == tgt) 221199653d4eSeschrock return (B_TRUE); 221299653d4eSeschrock 221399653d4eSeschrock for (c = 0; c < children; c++) 221499653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 221599653d4eSeschrock return (B_TRUE); 221699653d4eSeschrock } 221799653d4eSeschrock 221899653d4eSeschrock return (B_FALSE); 2219fa9e4066Sahrens } 2220fa9e4066Sahrens 2221fa9e4066Sahrens /* 2222fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 22238654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 2224fa9e4066Sahrens */ 2225fa9e4066Sahrens int 2226fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 2227fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 2228fa9e4066Sahrens { 2229fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2230fa9e4066Sahrens char msg[1024]; 2231fa9e4066Sahrens int ret; 223299653d4eSeschrock nvlist_t *tgt; 2233ee0eb9f2SEric Schrock boolean_t avail_spare, l2cache, islog; 2234ee0eb9f2SEric Schrock uint64_t val; 22350430f8daSeschrock char *path, *newname; 223699653d4eSeschrock nvlist_t **child; 223799653d4eSeschrock uint_t children; 223899653d4eSeschrock nvlist_t *config_root; 223999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2240b5b76fecSGeorge Wilson boolean_t rootpool = pool_is_bootable(zhp); 2241fa9e4066Sahrens 2242ea8dc4b6Seschrock if (replacing) 2243ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2244ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 2245ea8dc4b6Seschrock else 2246ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2247ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 2248ea8dc4b6Seschrock 2249b5b76fecSGeorge Wilson /* 2250b5b76fecSGeorge Wilson * If this is a root pool, make sure that we're not attaching an 2251b5b76fecSGeorge Wilson * EFI labeled device. 2252b5b76fecSGeorge Wilson */ 2253b5b76fecSGeorge Wilson if (rootpool && pool_uses_efi(nvroot)) { 2254b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2255b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root pools.")); 2256b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); 2257b5b76fecSGeorge Wilson } 2258b5b76fecSGeorge Wilson 2259fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2260ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 2261ee0eb9f2SEric Schrock &islog)) == 0) 226299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 226399653d4eSeschrock 2264a43d325bSek if (avail_spare) 226599653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 226699653d4eSeschrock 2267fa94a07fSbrendan if (l2cache) 2268fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2269fa94a07fSbrendan 227099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2271fa9e4066Sahrens zc.zc_cookie = replacing; 2272fa9e4066Sahrens 227399653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 227499653d4eSeschrock &child, &children) != 0 || children != 1) { 227599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 227699653d4eSeschrock "new device must be a single disk")); 227799653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 227899653d4eSeschrock } 227999653d4eSeschrock 228099653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 228199653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 228299653d4eSeschrock 228388ecc943SGeorge Wilson if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL) 22840430f8daSeschrock return (-1); 22850430f8daSeschrock 228699653d4eSeschrock /* 228799653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 228899653d4eSeschrock * replace it with another hot spare. 228999653d4eSeschrock */ 229099653d4eSeschrock if (replacing && 229199653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 2292ee0eb9f2SEric Schrock (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, 2293ee0eb9f2SEric Schrock NULL) == NULL || !avail_spare) && 2294ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 1)) { 229599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 229699653d4eSeschrock "can only be replaced by another hot spare")); 22970430f8daSeschrock free(newname); 229899653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 229999653d4eSeschrock } 230099653d4eSeschrock 230199653d4eSeschrock /* 230299653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 230399653d4eSeschrock * already spared device. 230499653d4eSeschrock */ 230599653d4eSeschrock if (replacing && 230699653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 2307ee0eb9f2SEric Schrock zpool_find_vdev(zhp, newname, &avail_spare, 2308ee0eb9f2SEric Schrock &l2cache, NULL) != NULL && avail_spare && 2309ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 0)) { 231099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 231199653d4eSeschrock "device has already been replaced with a spare")); 23120430f8daSeschrock free(newname); 231399653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 231499653d4eSeschrock } 231599653d4eSeschrock 23160430f8daSeschrock free(newname); 23170430f8daSeschrock 2318990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 231999653d4eSeschrock return (-1); 2320fa9e4066Sahrens 2321ecd6cf80Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 2322fa9e4066Sahrens 2323e9dbad6fSeschrock zcmd_free_nvlists(&zc); 2324fa9e4066Sahrens 2325b5b76fecSGeorge Wilson if (ret == 0) { 2326b5b76fecSGeorge Wilson if (rootpool) { 2327b5b76fecSGeorge Wilson /* 2328b5b76fecSGeorge Wilson * XXX - This should be removed once we can 2329b5b76fecSGeorge Wilson * automatically install the bootblocks on the 2330b5b76fecSGeorge Wilson * newly attached disk. 2331b5b76fecSGeorge Wilson */ 2332b5b76fecSGeorge Wilson (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please " 2333b5b76fecSGeorge Wilson "be sure to invoke %s to make '%s' bootable.\n"), 2334b5b76fecSGeorge Wilson BOOTCMD, new_disk); 233521ecdf64SLin Ling 233621ecdf64SLin Ling /* 233721ecdf64SLin Ling * XXX need a better way to prevent user from 233821ecdf64SLin Ling * booting up a half-baked vdev. 233921ecdf64SLin Ling */ 234021ecdf64SLin Ling (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 234121ecdf64SLin Ling "sure to wait until resilver is done " 234221ecdf64SLin Ling "before rebooting.\n")); 2343b5b76fecSGeorge Wilson } 2344fa9e4066Sahrens return (0); 2345b5b76fecSGeorge Wilson } 2346fa9e4066Sahrens 2347fa9e4066Sahrens switch (errno) { 2348ea8dc4b6Seschrock case ENOTSUP: 2349fa9e4066Sahrens /* 2350fa9e4066Sahrens * Can't attach to or replace this type of vdev. 2351fa9e4066Sahrens */ 23528654d025Sperrin if (replacing) { 2353ee0eb9f2SEric Schrock if (islog) 23548654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23558654d025Sperrin "cannot replace a log with a spare")); 23568654d025Sperrin else 23578654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 23588654d025Sperrin "cannot replace a replacing device")); 23598654d025Sperrin } else { 236099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 236199653d4eSeschrock "can only attach to mirrors and top-level " 236299653d4eSeschrock "disks")); 23638654d025Sperrin } 236499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 2365fa9e4066Sahrens break; 2366fa9e4066Sahrens 2367ea8dc4b6Seschrock case EINVAL: 2368fa9e4066Sahrens /* 2369fa9e4066Sahrens * The new device must be a single disk. 2370fa9e4066Sahrens */ 237199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 237299653d4eSeschrock "new device must be a single disk")); 237399653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 2374fa9e4066Sahrens break; 2375fa9e4066Sahrens 2376ea8dc4b6Seschrock case EBUSY: 237799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 237899653d4eSeschrock new_disk); 237999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2380fa9e4066Sahrens break; 2381fa9e4066Sahrens 2382ea8dc4b6Seschrock case EOVERFLOW: 2383fa9e4066Sahrens /* 2384fa9e4066Sahrens * The new device is too small. 2385fa9e4066Sahrens */ 238699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 238799653d4eSeschrock "device is too small")); 238899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2389fa9e4066Sahrens break; 2390fa9e4066Sahrens 2391ea8dc4b6Seschrock case EDOM: 2392fa9e4066Sahrens /* 2393fa9e4066Sahrens * The new device has a different alignment requirement. 2394fa9e4066Sahrens */ 239599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 239699653d4eSeschrock "devices have different sector alignment")); 239799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 2398fa9e4066Sahrens break; 2399fa9e4066Sahrens 2400ea8dc4b6Seschrock case ENAMETOOLONG: 2401fa9e4066Sahrens /* 2402fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 2403fa9e4066Sahrens */ 240499653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 2405fa9e4066Sahrens break; 2406fa9e4066Sahrens 2407ea8dc4b6Seschrock default: 240899653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2409fa9e4066Sahrens } 2410fa9e4066Sahrens 241199653d4eSeschrock return (-1); 2412fa9e4066Sahrens } 2413fa9e4066Sahrens 2414fa9e4066Sahrens /* 2415fa9e4066Sahrens * Detach the specified device. 2416fa9e4066Sahrens */ 2417fa9e4066Sahrens int 2418fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 2419fa9e4066Sahrens { 2420fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2421fa9e4066Sahrens char msg[1024]; 242299653d4eSeschrock nvlist_t *tgt; 2423fa94a07fSbrendan boolean_t avail_spare, l2cache; 242499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2425fa9e4066Sahrens 2426ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2427ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 2428ea8dc4b6Seschrock 2429fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2430ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2431ee0eb9f2SEric Schrock NULL)) == 0) 243299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2433fa9e4066Sahrens 2434a43d325bSek if (avail_spare) 243599653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 243699653d4eSeschrock 2437fa94a07fSbrendan if (l2cache) 2438fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 2439fa94a07fSbrendan 244099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 244199653d4eSeschrock 2442ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 2443fa9e4066Sahrens return (0); 2444fa9e4066Sahrens 2445fa9e4066Sahrens switch (errno) { 2446fa9e4066Sahrens 2447ea8dc4b6Seschrock case ENOTSUP: 2448fa9e4066Sahrens /* 2449fa9e4066Sahrens * Can't detach from this type of vdev. 2450fa9e4066Sahrens */ 245199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 245299653d4eSeschrock "applicable to mirror and replacing vdevs")); 245399653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 2454fa9e4066Sahrens break; 2455fa9e4066Sahrens 2456ea8dc4b6Seschrock case EBUSY: 2457fa9e4066Sahrens /* 2458fa9e4066Sahrens * There are no other replicas of this device. 2459fa9e4066Sahrens */ 246099653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 2461fa9e4066Sahrens break; 2462fa9e4066Sahrens 2463ea8dc4b6Seschrock default: 246499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 2465ea8dc4b6Seschrock } 2466ea8dc4b6Seschrock 246799653d4eSeschrock return (-1); 246899653d4eSeschrock } 246999653d4eSeschrock 247099653d4eSeschrock /* 2471fa94a07fSbrendan * Remove the given device. Currently, this is supported only for hot spares 2472fa94a07fSbrendan * and level 2 cache devices. 247399653d4eSeschrock */ 247499653d4eSeschrock int 247599653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 247699653d4eSeschrock { 247799653d4eSeschrock zfs_cmd_t zc = { 0 }; 247899653d4eSeschrock char msg[1024]; 247999653d4eSeschrock nvlist_t *tgt; 248088ecc943SGeorge Wilson boolean_t avail_spare, l2cache, islog; 248199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 248288ecc943SGeorge Wilson uint64_t version; 248399653d4eSeschrock 248499653d4eSeschrock (void) snprintf(msg, sizeof (msg), 248599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 248699653d4eSeschrock 248799653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2488ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 248988ecc943SGeorge Wilson &islog)) == 0) 249099653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 249188ecc943SGeorge Wilson /* 249288ecc943SGeorge Wilson * XXX - this should just go away. 249388ecc943SGeorge Wilson */ 249488ecc943SGeorge Wilson if (!avail_spare && !l2cache && !islog) { 249599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 249688ecc943SGeorge Wilson "only inactive hot spares, cache, top-level, " 249788ecc943SGeorge Wilson "or log devices can be removed")); 249899653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 249999653d4eSeschrock } 250099653d4eSeschrock 250188ecc943SGeorge Wilson version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 250288ecc943SGeorge Wilson if (islog && version < SPA_VERSION_HOLES) { 250388ecc943SGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 250488ecc943SGeorge Wilson "pool must be upgrade to support log removal")); 250588ecc943SGeorge Wilson return (zfs_error(hdl, EZFS_BADVERSION, msg)); 250688ecc943SGeorge Wilson } 250788ecc943SGeorge Wilson 250899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 250999653d4eSeschrock 2510ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 251199653d4eSeschrock return (0); 251299653d4eSeschrock 251399653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2514ea8dc4b6Seschrock } 2515ea8dc4b6Seschrock 2516ea8dc4b6Seschrock /* 2517ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 2518ea8dc4b6Seschrock */ 2519ea8dc4b6Seschrock int 2520468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 2521ea8dc4b6Seschrock { 2522ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2523ea8dc4b6Seschrock char msg[1024]; 252499653d4eSeschrock nvlist_t *tgt; 2525468c413aSTim Haley zpool_rewind_policy_t policy; 2526fa94a07fSbrendan boolean_t avail_spare, l2cache; 252799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2528468c413aSTim Haley nvlist_t *nvi = NULL; 2529ea8dc4b6Seschrock 2530ea8dc4b6Seschrock if (path) 2531ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2532ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2533e9dbad6fSeschrock path); 2534ea8dc4b6Seschrock else 2535ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2536ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 2537ea8dc4b6Seschrock zhp->zpool_name); 2538ea8dc4b6Seschrock 2539ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 254099653d4eSeschrock if (path) { 2541fa94a07fSbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 2542ee0eb9f2SEric Schrock &l2cache, NULL)) == 0) 254399653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2544ea8dc4b6Seschrock 2545fa94a07fSbrendan /* 2546fa94a07fSbrendan * Don't allow error clearing for hot spares. Do allow 2547fa94a07fSbrendan * error clearing for l2cache devices. 2548fa94a07fSbrendan */ 2549a43d325bSek if (avail_spare) 255099653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2551ea8dc4b6Seschrock 255299653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 255399653d4eSeschrock &zc.zc_guid) == 0); 2554fa9e4066Sahrens } 2555fa9e4066Sahrens 2556468c413aSTim Haley zpool_get_rewind_policy(rewindnvl, &policy); 2557468c413aSTim Haley zc.zc_cookie = policy.zrp_request; 2558468c413aSTim Haley 2559468c413aSTim Haley if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0) 2560468c413aSTim Haley return (-1); 2561468c413aSTim Haley 2562468c413aSTim Haley if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0) 2563468c413aSTim Haley return (-1); 2564468c413aSTim Haley 2565468c413aSTim Haley if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 || 2566468c413aSTim Haley ((policy.zrp_request & ZPOOL_TRY_REWIND) && 2567468c413aSTim Haley errno != EPERM && errno != EACCES)) { 2568468c413aSTim Haley if (policy.zrp_request & 2569468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 2570468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 2571468c413aSTim Haley zpool_rewind_exclaim(hdl, zc.zc_name, 2572468c413aSTim Haley ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), 2573468c413aSTim Haley nvi); 2574468c413aSTim Haley nvlist_free(nvi); 2575468c413aSTim Haley } 2576468c413aSTim Haley zcmd_free_nvlists(&zc); 257799653d4eSeschrock return (0); 2578468c413aSTim Haley } 257999653d4eSeschrock 2580468c413aSTim Haley zcmd_free_nvlists(&zc); 258199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2582fa9e4066Sahrens } 2583fa9e4066Sahrens 25843d7072f8Seschrock /* 25853d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 25863d7072f8Seschrock */ 25873d7072f8Seschrock int 25883d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 25893d7072f8Seschrock { 25903d7072f8Seschrock zfs_cmd_t zc = { 0 }; 25913d7072f8Seschrock char msg[1024]; 25923d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 25933d7072f8Seschrock 25943d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 25953d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 25963d7072f8Seschrock guid); 25973d7072f8Seschrock 25983d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 25993d7072f8Seschrock zc.zc_guid = guid; 26003d7072f8Seschrock 26013d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 26023d7072f8Seschrock return (0); 26033d7072f8Seschrock 26043d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 26053d7072f8Seschrock } 26063d7072f8Seschrock 2607c67d9675Seschrock /* 2608c67d9675Seschrock * Convert from a devid string to a path. 2609c67d9675Seschrock */ 2610c67d9675Seschrock static char * 2611c67d9675Seschrock devid_to_path(char *devid_str) 2612c67d9675Seschrock { 2613c67d9675Seschrock ddi_devid_t devid; 2614c67d9675Seschrock char *minor; 2615c67d9675Seschrock char *path; 2616c67d9675Seschrock devid_nmlist_t *list = NULL; 2617c67d9675Seschrock int ret; 2618c67d9675Seschrock 2619c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 2620c67d9675Seschrock return (NULL); 2621c67d9675Seschrock 2622c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 2623c67d9675Seschrock 2624c67d9675Seschrock devid_str_free(minor); 2625c67d9675Seschrock devid_free(devid); 2626c67d9675Seschrock 2627c67d9675Seschrock if (ret != 0) 2628c67d9675Seschrock return (NULL); 2629c67d9675Seschrock 263099653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 263199653d4eSeschrock return (NULL); 263299653d4eSeschrock 2633c67d9675Seschrock devid_free_nmlist(list); 2634c67d9675Seschrock 2635c67d9675Seschrock return (path); 2636c67d9675Seschrock } 2637c67d9675Seschrock 2638c67d9675Seschrock /* 2639c67d9675Seschrock * Convert from a path to a devid string. 2640c67d9675Seschrock */ 2641c67d9675Seschrock static char * 2642c67d9675Seschrock path_to_devid(const char *path) 2643c67d9675Seschrock { 2644c67d9675Seschrock int fd; 2645c67d9675Seschrock ddi_devid_t devid; 2646c67d9675Seschrock char *minor, *ret; 2647c67d9675Seschrock 2648c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 2649c67d9675Seschrock return (NULL); 2650c67d9675Seschrock 2651c67d9675Seschrock minor = NULL; 2652c67d9675Seschrock ret = NULL; 2653c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 2654c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 2655c67d9675Seschrock ret = devid_str_encode(devid, minor); 2656c67d9675Seschrock if (minor != NULL) 2657c67d9675Seschrock devid_str_free(minor); 2658c67d9675Seschrock devid_free(devid); 2659c67d9675Seschrock } 2660c67d9675Seschrock (void) close(fd); 2661c67d9675Seschrock 2662c67d9675Seschrock return (ret); 2663c67d9675Seschrock } 2664c67d9675Seschrock 2665c67d9675Seschrock /* 2666c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 2667c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 2668c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 2669c67d9675Seschrock */ 2670c67d9675Seschrock static void 2671c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 2672c67d9675Seschrock { 2673c67d9675Seschrock zfs_cmd_t zc = { 0 }; 2674c67d9675Seschrock 2675c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2676e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 2677c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2678ea8dc4b6Seschrock &zc.zc_guid) == 0); 2679c67d9675Seschrock 268099653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 2681c67d9675Seschrock } 2682c67d9675Seschrock 2683c67d9675Seschrock /* 2684c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 2685c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 2686c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 2687c67d9675Seschrock * trailing 's0' slice name. 2688c67d9675Seschrock * 2689c67d9675Seschrock * This routine is also responsible for identifying when disks have been 2690c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 2691c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 2692c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 2693c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 2694c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 2695c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 2696c67d9675Seschrock * of these checks. 2697c67d9675Seschrock */ 2698c67d9675Seschrock char * 269988ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 270088ecc943SGeorge Wilson boolean_t verbose) 2701c67d9675Seschrock { 2702c67d9675Seschrock char *path, *devid; 2703ea8dc4b6Seschrock uint64_t value; 2704ea8dc4b6Seschrock char buf[64]; 27053d7072f8Seschrock vdev_stat_t *vs; 27063d7072f8Seschrock uint_t vsc; 2707c67d9675Seschrock 2708ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 2709ea8dc4b6Seschrock &value) == 0) { 2710ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2711ea8dc4b6Seschrock &value) == 0); 27125ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 27135ad82045Snd (u_longlong_t)value); 2714ea8dc4b6Seschrock path = buf; 2715ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 2716c67d9675Seschrock 27173d7072f8Seschrock /* 27183d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 27193d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 27203d7072f8Seschrock * open a misbehaving device, which can have undesirable 27213d7072f8Seschrock * effects. 27223d7072f8Seschrock */ 27233d7072f8Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 27243d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 27253d7072f8Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 27263d7072f8Seschrock zhp != NULL && 2727c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 2728c67d9675Seschrock /* 2729c67d9675Seschrock * Determine if the current path is correct. 2730c67d9675Seschrock */ 2731c67d9675Seschrock char *newdevid = path_to_devid(path); 2732c67d9675Seschrock 2733c67d9675Seschrock if (newdevid == NULL || 2734c67d9675Seschrock strcmp(devid, newdevid) != 0) { 2735c67d9675Seschrock char *newpath; 2736c67d9675Seschrock 2737c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 2738c67d9675Seschrock /* 2739c67d9675Seschrock * Update the path appropriately. 2740c67d9675Seschrock */ 2741c67d9675Seschrock set_path(zhp, nv, newpath); 274299653d4eSeschrock if (nvlist_add_string(nv, 274399653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 274499653d4eSeschrock verify(nvlist_lookup_string(nv, 274599653d4eSeschrock ZPOOL_CONFIG_PATH, 274699653d4eSeschrock &path) == 0); 2747c67d9675Seschrock free(newpath); 2748c67d9675Seschrock } 2749c67d9675Seschrock } 2750c67d9675Seschrock 275199653d4eSeschrock if (newdevid) 275299653d4eSeschrock devid_str_free(newdevid); 2753c67d9675Seschrock } 2754c67d9675Seschrock 2755c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 2756c67d9675Seschrock path += 9; 2757c67d9675Seschrock 2758c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 2759ea8dc4b6Seschrock &value) == 0 && value) { 276099653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 276199653d4eSeschrock if (tmp == NULL) 276299653d4eSeschrock return (NULL); 2763c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 2764c67d9675Seschrock return (tmp); 2765c67d9675Seschrock } 2766c67d9675Seschrock } else { 2767c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 276899653d4eSeschrock 276999653d4eSeschrock /* 277099653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 277199653d4eSeschrock */ 277299653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 277399653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 277499653d4eSeschrock &value) == 0); 277599653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 27765ad82045Snd (u_longlong_t)value); 277799653d4eSeschrock path = buf; 277899653d4eSeschrock } 277988ecc943SGeorge Wilson 278088ecc943SGeorge Wilson /* 278188ecc943SGeorge Wilson * We identify each top-level vdev by using a <type-id> 278288ecc943SGeorge Wilson * naming convention. 278388ecc943SGeorge Wilson */ 278488ecc943SGeorge Wilson if (verbose) { 278588ecc943SGeorge Wilson uint64_t id; 278688ecc943SGeorge Wilson 278788ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 278888ecc943SGeorge Wilson &id) == 0); 278988ecc943SGeorge Wilson (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 279088ecc943SGeorge Wilson (u_longlong_t)id); 279188ecc943SGeorge Wilson path = buf; 279288ecc943SGeorge Wilson } 2793c67d9675Seschrock } 2794c67d9675Seschrock 279599653d4eSeschrock return (zfs_strdup(hdl, path)); 2796c67d9675Seschrock } 2797ea8dc4b6Seschrock 2798ea8dc4b6Seschrock static int 2799ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 2800ea8dc4b6Seschrock { 2801ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 2802ea8dc4b6Seschrock } 2803ea8dc4b6Seschrock 2804ea8dc4b6Seschrock /* 2805ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 2806ea8dc4b6Seschrock * caller. 2807ea8dc4b6Seschrock */ 2808ea8dc4b6Seschrock int 280955434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 2810ea8dc4b6Seschrock { 2811ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 2812ea8dc4b6Seschrock uint64_t count; 2813e9dbad6fSeschrock zbookmark_t *zb = NULL; 281455434c77Sek int i; 2815ea8dc4b6Seschrock 2816ea8dc4b6Seschrock /* 2817ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 2818ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 2819ea8dc4b6Seschrock * entire list. 2820ea8dc4b6Seschrock */ 2821ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 2822ea8dc4b6Seschrock &count) == 0); 282375519f38Sek if (count == 0) 282475519f38Sek return (0); 2825e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 28265ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 282799653d4eSeschrock return (-1); 2828e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 2829ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2830ea8dc4b6Seschrock for (;;) { 283199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 283299653d4eSeschrock &zc) != 0) { 2833e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 2834ea8dc4b6Seschrock if (errno == ENOMEM) { 2835bf561db0Svb count = zc.zc_nvlist_dst_size; 2836e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 2837bf561db0Svb zfs_alloc(zhp->zpool_hdl, count * 2838bf561db0Svb sizeof (zbookmark_t))) == (uintptr_t)NULL) 283999653d4eSeschrock return (-1); 2840ea8dc4b6Seschrock } else { 2841ea8dc4b6Seschrock return (-1); 2842ea8dc4b6Seschrock } 2843ea8dc4b6Seschrock } else { 2844ea8dc4b6Seschrock break; 2845ea8dc4b6Seschrock } 2846ea8dc4b6Seschrock } 2847ea8dc4b6Seschrock 2848ea8dc4b6Seschrock /* 2849ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 2850ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 2851e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 2852ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 2853ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 2854ea8dc4b6Seschrock */ 2855e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 2856e9dbad6fSeschrock zc.zc_nvlist_dst_size; 2857e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 2858ea8dc4b6Seschrock 2859ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 2860ea8dc4b6Seschrock 286155434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 2862ea8dc4b6Seschrock 2863ea8dc4b6Seschrock /* 286455434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 2865ea8dc4b6Seschrock */ 2866ea8dc4b6Seschrock for (i = 0; i < count; i++) { 2867ea8dc4b6Seschrock nvlist_t *nv; 2868ea8dc4b6Seschrock 2869c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 2870c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 2871c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 2872ea8dc4b6Seschrock continue; 2873ea8dc4b6Seschrock 287455434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 287555434c77Sek goto nomem; 287655434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 287755434c77Sek zb[i].zb_objset) != 0) { 287855434c77Sek nvlist_free(nv); 287999653d4eSeschrock goto nomem; 2880ea8dc4b6Seschrock } 288155434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 288255434c77Sek zb[i].zb_object) != 0) { 288355434c77Sek nvlist_free(nv); 288455434c77Sek goto nomem; 288555434c77Sek } 288655434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 288755434c77Sek nvlist_free(nv); 288855434c77Sek goto nomem; 288955434c77Sek } 289055434c77Sek nvlist_free(nv); 2891ea8dc4b6Seschrock } 2892ea8dc4b6Seschrock 28933ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 2894ea8dc4b6Seschrock return (0); 289599653d4eSeschrock 289699653d4eSeschrock nomem: 2897e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 289899653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 2899ea8dc4b6Seschrock } 2900eaca9bbdSeschrock 2901eaca9bbdSeschrock /* 2902eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 2903eaca9bbdSeschrock */ 2904eaca9bbdSeschrock int 2905990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 2906eaca9bbdSeschrock { 2907eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 290899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2909eaca9bbdSeschrock 2910eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 2911990b4856Slling zc.zc_cookie = new_version; 2912990b4856Slling 2913ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 2914ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 291599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 291699653d4eSeschrock zhp->zpool_name)); 2917eaca9bbdSeschrock return (0); 2918eaca9bbdSeschrock } 291906eeb2adSek 292006eeb2adSek void 29212a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv, 29222a6b87f0Sek char *history_str) 292306eeb2adSek { 292406eeb2adSek int i; 292506eeb2adSek 29262a6b87f0Sek (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 29272a6b87f0Sek for (i = 1; i < argc; i++) { 29282a6b87f0Sek if (strlen(history_str) + 1 + strlen(argv[i]) > 29292a6b87f0Sek HIS_MAX_RECORD_LEN) 29302a6b87f0Sek break; 29312a6b87f0Sek (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 29322a6b87f0Sek (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 29332a6b87f0Sek } 29342a6b87f0Sek } 29352a6b87f0Sek 29362a6b87f0Sek /* 29372a6b87f0Sek * Stage command history for logging. 29382a6b87f0Sek */ 29392a6b87f0Sek int 29402a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 29412a6b87f0Sek { 29422a6b87f0Sek if (history_str == NULL) 29432a6b87f0Sek return (EINVAL); 29442a6b87f0Sek 29452a6b87f0Sek if (strlen(history_str) > HIS_MAX_RECORD_LEN) 29462a6b87f0Sek return (EINVAL); 29472a6b87f0Sek 2948228975ccSek if (hdl->libzfs_log_str != NULL) 2949ecd6cf80Smarks free(hdl->libzfs_log_str); 295006eeb2adSek 29512a6b87f0Sek if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 29522a6b87f0Sek return (no_memory(hdl)); 295306eeb2adSek 29542a6b87f0Sek return (0); 295506eeb2adSek } 295606eeb2adSek 295706eeb2adSek /* 295806eeb2adSek * Perform ioctl to get some command history of a pool. 295906eeb2adSek * 296006eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 296106eeb2adSek * logical offset of the history buffer to start reading from. 296206eeb2adSek * 296306eeb2adSek * Upon return, 'off' is the next logical offset to read from and 296406eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 296506eeb2adSek */ 296606eeb2adSek static int 296706eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 296806eeb2adSek { 296906eeb2adSek zfs_cmd_t zc = { 0 }; 297006eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 297106eeb2adSek 297206eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 297306eeb2adSek 297406eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 297506eeb2adSek zc.zc_history_len = *len; 297606eeb2adSek zc.zc_history_offset = *off; 297706eeb2adSek 297806eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 297906eeb2adSek switch (errno) { 298006eeb2adSek case EPERM: 2981ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 2982ece3d9b3Slling dgettext(TEXT_DOMAIN, 298306eeb2adSek "cannot show history for pool '%s'"), 298406eeb2adSek zhp->zpool_name)); 298506eeb2adSek case ENOENT: 2986ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 298706eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 298806eeb2adSek "'%s'"), zhp->zpool_name)); 2989d7306b64Sek case ENOTSUP: 2990d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 2991d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 2992d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 299306eeb2adSek default: 2994ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 299506eeb2adSek dgettext(TEXT_DOMAIN, 299606eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 299706eeb2adSek } 299806eeb2adSek } 299906eeb2adSek 300006eeb2adSek *len = zc.zc_history_len; 300106eeb2adSek *off = zc.zc_history_offset; 300206eeb2adSek 300306eeb2adSek return (0); 300406eeb2adSek } 300506eeb2adSek 300606eeb2adSek /* 300706eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 300806eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 300906eeb2adSek * processed as there wasn't a complete record. 301006eeb2adSek */ 30118f18d1faSGeorge Wilson int 301206eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 301306eeb2adSek nvlist_t ***records, uint_t *numrecords) 301406eeb2adSek { 301506eeb2adSek uint64_t reclen; 301606eeb2adSek nvlist_t *nv; 301706eeb2adSek int i; 301806eeb2adSek 301906eeb2adSek while (bytes_read > sizeof (reclen)) { 302006eeb2adSek 302106eeb2adSek /* get length of packed record (stored as little endian) */ 302206eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 302306eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 302406eeb2adSek 302506eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 302606eeb2adSek break; 302706eeb2adSek 302806eeb2adSek /* unpack record */ 302906eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 303006eeb2adSek return (ENOMEM); 303106eeb2adSek bytes_read -= sizeof (reclen) + reclen; 303206eeb2adSek buf += sizeof (reclen) + reclen; 303306eeb2adSek 303406eeb2adSek /* add record to nvlist array */ 303506eeb2adSek (*numrecords)++; 303606eeb2adSek if (ISP2(*numrecords + 1)) { 303706eeb2adSek *records = realloc(*records, 303806eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 303906eeb2adSek } 304006eeb2adSek (*records)[*numrecords - 1] = nv; 304106eeb2adSek } 304206eeb2adSek 304306eeb2adSek *leftover = bytes_read; 304406eeb2adSek return (0); 304506eeb2adSek } 304606eeb2adSek 304706eeb2adSek #define HIS_BUF_LEN (128*1024) 304806eeb2adSek 304906eeb2adSek /* 305006eeb2adSek * Retrieve the command history of a pool. 305106eeb2adSek */ 305206eeb2adSek int 305306eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 305406eeb2adSek { 305506eeb2adSek char buf[HIS_BUF_LEN]; 305606eeb2adSek uint64_t off = 0; 305706eeb2adSek nvlist_t **records = NULL; 305806eeb2adSek uint_t numrecords = 0; 305906eeb2adSek int err, i; 306006eeb2adSek 306106eeb2adSek do { 306206eeb2adSek uint64_t bytes_read = sizeof (buf); 306306eeb2adSek uint64_t leftover; 306406eeb2adSek 306506eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 306606eeb2adSek break; 306706eeb2adSek 306806eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 306906eeb2adSek if (!bytes_read) 307006eeb2adSek break; 307106eeb2adSek 307206eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 307306eeb2adSek &leftover, &records, &numrecords)) != 0) 307406eeb2adSek break; 307506eeb2adSek off -= leftover; 307606eeb2adSek 307706eeb2adSek /* CONSTCOND */ 307806eeb2adSek } while (1); 307906eeb2adSek 308006eeb2adSek if (!err) { 308106eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 308206eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 308306eeb2adSek records, numrecords) == 0); 308406eeb2adSek } 308506eeb2adSek for (i = 0; i < numrecords; i++) 308606eeb2adSek nvlist_free(records[i]); 308706eeb2adSek free(records); 308806eeb2adSek 308906eeb2adSek return (err); 309006eeb2adSek } 309155434c77Sek 309255434c77Sek void 309355434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 309455434c77Sek char *pathname, size_t len) 309555434c77Sek { 309655434c77Sek zfs_cmd_t zc = { 0 }; 309755434c77Sek boolean_t mounted = B_FALSE; 309855434c77Sek char *mntpnt = NULL; 309955434c77Sek char dsname[MAXNAMELEN]; 310055434c77Sek 310155434c77Sek if (dsobj == 0) { 310255434c77Sek /* special case for the MOS */ 310355434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 310455434c77Sek return; 310555434c77Sek } 310655434c77Sek 310755434c77Sek /* get the dataset's name */ 310855434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 310955434c77Sek zc.zc_obj = dsobj; 311055434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 311155434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 311255434c77Sek /* just write out a path of two object numbers */ 311355434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 311455434c77Sek dsobj, obj); 311555434c77Sek return; 311655434c77Sek } 311755434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 311855434c77Sek 311955434c77Sek /* find out if the dataset is mounted */ 312055434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 312155434c77Sek 312255434c77Sek /* get the corrupted object's path */ 312355434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 312455434c77Sek zc.zc_obj = obj; 312555434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 312655434c77Sek &zc) == 0) { 312755434c77Sek if (mounted) { 312855434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 312955434c77Sek zc.zc_value); 313055434c77Sek } else { 313155434c77Sek (void) snprintf(pathname, len, "%s:%s", 313255434c77Sek dsname, zc.zc_value); 313355434c77Sek } 313455434c77Sek } else { 313555434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 313655434c77Sek } 313755434c77Sek free(mntpnt); 313855434c77Sek } 3139b1b8ab34Slling 314015e6edf1Sgw /* 314115e6edf1Sgw * Read the EFI label from the config, if a label does not exist then 314215e6edf1Sgw * pass back the error to the caller. If the caller has passed a non-NULL 314315e6edf1Sgw * diskaddr argument then we set it to the starting address of the EFI 314415e6edf1Sgw * partition. 314515e6edf1Sgw */ 314615e6edf1Sgw static int 314715e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb) 314815e6edf1Sgw { 314915e6edf1Sgw char *path; 315015e6edf1Sgw int fd; 315115e6edf1Sgw char diskname[MAXPATHLEN]; 315215e6edf1Sgw int err = -1; 315315e6edf1Sgw 315415e6edf1Sgw if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 315515e6edf1Sgw return (err); 315615e6edf1Sgw 315715e6edf1Sgw (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, 315815e6edf1Sgw strrchr(path, '/')); 315915e6edf1Sgw if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 316015e6edf1Sgw struct dk_gpt *vtoc; 316115e6edf1Sgw 316215e6edf1Sgw if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 316315e6edf1Sgw if (sb != NULL) 316415e6edf1Sgw *sb = vtoc->efi_parts[0].p_start; 316515e6edf1Sgw efi_free(vtoc); 316615e6edf1Sgw } 316715e6edf1Sgw (void) close(fd); 316815e6edf1Sgw } 316915e6edf1Sgw return (err); 317015e6edf1Sgw } 317115e6edf1Sgw 31728488aeb5Staylor /* 31738488aeb5Staylor * determine where a partition starts on a disk in the current 31748488aeb5Staylor * configuration 31758488aeb5Staylor */ 31768488aeb5Staylor static diskaddr_t 31778488aeb5Staylor find_start_block(nvlist_t *config) 31788488aeb5Staylor { 31798488aeb5Staylor nvlist_t **child; 31808488aeb5Staylor uint_t c, children; 31818488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 31828488aeb5Staylor uint64_t wholedisk; 31838488aeb5Staylor 31848488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 31858488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 31868488aeb5Staylor if (nvlist_lookup_uint64(config, 31878488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 31888488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 31898488aeb5Staylor return (MAXOFFSET_T); 31908488aeb5Staylor } 319115e6edf1Sgw if (read_efi_label(config, &sb) < 0) 319215e6edf1Sgw sb = MAXOFFSET_T; 31938488aeb5Staylor return (sb); 31948488aeb5Staylor } 31958488aeb5Staylor 31968488aeb5Staylor for (c = 0; c < children; c++) { 31978488aeb5Staylor sb = find_start_block(child[c]); 31988488aeb5Staylor if (sb != MAXOFFSET_T) { 31998488aeb5Staylor return (sb); 32008488aeb5Staylor } 32018488aeb5Staylor } 32028488aeb5Staylor return (MAXOFFSET_T); 32038488aeb5Staylor } 32048488aeb5Staylor 32058488aeb5Staylor /* 32068488aeb5Staylor * Label an individual disk. The name provided is the short name, 32078488aeb5Staylor * stripped of any leading /dev path. 32088488aeb5Staylor */ 32098488aeb5Staylor int 32108488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 32118488aeb5Staylor { 32128488aeb5Staylor char path[MAXPATHLEN]; 32138488aeb5Staylor struct dk_gpt *vtoc; 32148488aeb5Staylor int fd; 32158488aeb5Staylor size_t resv = EFI_MIN_RESV_SIZE; 32168488aeb5Staylor uint64_t slice_size; 32178488aeb5Staylor diskaddr_t start_block; 32188488aeb5Staylor char errbuf[1024]; 32198488aeb5Staylor 3220c6ef114fSmmusante /* prepare an error message just in case */ 3221c6ef114fSmmusante (void) snprintf(errbuf, sizeof (errbuf), 3222c6ef114fSmmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 3223c6ef114fSmmusante 32248488aeb5Staylor if (zhp) { 32258488aeb5Staylor nvlist_t *nvroot; 32268488aeb5Staylor 3227b5b76fecSGeorge Wilson if (pool_is_bootable(zhp)) { 3228b5b76fecSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3229b5b76fecSGeorge Wilson "EFI labeled devices are not supported on root " 3230b5b76fecSGeorge Wilson "pools.")); 3231b5b76fecSGeorge Wilson return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); 3232b5b76fecSGeorge Wilson } 3233b5b76fecSGeorge Wilson 32348488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 32358488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 32368488aeb5Staylor 32378488aeb5Staylor if (zhp->zpool_start_block == 0) 32388488aeb5Staylor start_block = find_start_block(nvroot); 32398488aeb5Staylor else 32408488aeb5Staylor start_block = zhp->zpool_start_block; 32418488aeb5Staylor zhp->zpool_start_block = start_block; 32428488aeb5Staylor } else { 32438488aeb5Staylor /* new pool */ 32448488aeb5Staylor start_block = NEW_START_BLOCK; 32458488aeb5Staylor } 32468488aeb5Staylor 32478488aeb5Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 32488488aeb5Staylor BACKUP_SLICE); 32498488aeb5Staylor 32508488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 32518488aeb5Staylor /* 32528488aeb5Staylor * This shouldn't happen. We've long since verified that this 32538488aeb5Staylor * is a valid device. 32548488aeb5Staylor */ 3255c6ef114fSmmusante zfs_error_aux(hdl, 3256c6ef114fSmmusante dgettext(TEXT_DOMAIN, "unable to open device")); 32578488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 32588488aeb5Staylor } 32598488aeb5Staylor 32608488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 32618488aeb5Staylor /* 32628488aeb5Staylor * The only way this can fail is if we run out of memory, or we 32638488aeb5Staylor * were unable to read the disk's capacity 32648488aeb5Staylor */ 32658488aeb5Staylor if (errno == ENOMEM) 32668488aeb5Staylor (void) no_memory(hdl); 32678488aeb5Staylor 32688488aeb5Staylor (void) close(fd); 3269c6ef114fSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3270c6ef114fSmmusante "unable to read disk capacity"), name); 32718488aeb5Staylor 32728488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 32738488aeb5Staylor } 32748488aeb5Staylor 32758488aeb5Staylor slice_size = vtoc->efi_last_u_lba + 1; 32768488aeb5Staylor slice_size -= EFI_MIN_RESV_SIZE; 32778488aeb5Staylor if (start_block == MAXOFFSET_T) 32788488aeb5Staylor start_block = NEW_START_BLOCK; 32798488aeb5Staylor slice_size -= start_block; 32808488aeb5Staylor 32818488aeb5Staylor vtoc->efi_parts[0].p_start = start_block; 32828488aeb5Staylor vtoc->efi_parts[0].p_size = slice_size; 32838488aeb5Staylor 32848488aeb5Staylor /* 32858488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 32868488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 32878488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 32888488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 32898488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 32908488aeb5Staylor * can get, in the absence of V_OTHER. 32918488aeb5Staylor */ 32928488aeb5Staylor vtoc->efi_parts[0].p_tag = V_USR; 32938488aeb5Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 32948488aeb5Staylor 32958488aeb5Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 32968488aeb5Staylor vtoc->efi_parts[8].p_size = resv; 32978488aeb5Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 32988488aeb5Staylor 32998488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 33008488aeb5Staylor /* 33018488aeb5Staylor * Some block drivers (like pcata) may not support EFI 33028488aeb5Staylor * GPT labels. Print out a helpful error message dir- 33038488aeb5Staylor * ecting the user to manually label the disk and give 33048488aeb5Staylor * a specific slice. 33058488aeb5Staylor */ 33068488aeb5Staylor (void) close(fd); 33078488aeb5Staylor efi_free(vtoc); 33088488aeb5Staylor 33098488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3310c6ef114fSmmusante "try using fdisk(1M) and then provide a specific slice")); 33118488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 33128488aeb5Staylor } 33138488aeb5Staylor 33148488aeb5Staylor (void) close(fd); 33158488aeb5Staylor efi_free(vtoc); 33168488aeb5Staylor return (0); 33178488aeb5Staylor } 3318e7cbe64fSgw 3319e7cbe64fSgw static boolean_t 3320e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 3321e7cbe64fSgw { 3322e7cbe64fSgw char *type; 3323e7cbe64fSgw nvlist_t **child; 3324e7cbe64fSgw uint_t children, c; 3325e7cbe64fSgw 3326e7cbe64fSgw verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 3327e7cbe64fSgw if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 3328e7cbe64fSgw strcmp(type, VDEV_TYPE_FILE) == 0 || 3329e7cbe64fSgw strcmp(type, VDEV_TYPE_LOG) == 0 || 333088ecc943SGeorge Wilson strcmp(type, VDEV_TYPE_HOLE) == 0 || 3331e7cbe64fSgw strcmp(type, VDEV_TYPE_MISSING) == 0) { 3332e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3333e7cbe64fSgw "vdev type '%s' is not supported"), type); 3334e7cbe64fSgw (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 3335e7cbe64fSgw return (B_FALSE); 3336e7cbe64fSgw } 3337e7cbe64fSgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 3338e7cbe64fSgw &child, &children) == 0) { 3339e7cbe64fSgw for (c = 0; c < children; c++) { 3340e7cbe64fSgw if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 3341e7cbe64fSgw return (B_FALSE); 3342e7cbe64fSgw } 3343e7cbe64fSgw } 3344e7cbe64fSgw return (B_TRUE); 3345e7cbe64fSgw } 3346e7cbe64fSgw 3347e7cbe64fSgw /* 3348e7cbe64fSgw * check if this zvol is allowable for use as a dump device; zero if 3349e7cbe64fSgw * it is, > 0 if it isn't, < 0 if it isn't a zvol 3350e7cbe64fSgw */ 3351e7cbe64fSgw int 3352e7cbe64fSgw zvol_check_dump_config(char *arg) 3353e7cbe64fSgw { 3354e7cbe64fSgw zpool_handle_t *zhp = NULL; 3355e7cbe64fSgw nvlist_t *config, *nvroot; 3356e7cbe64fSgw char *p, *volname; 3357e7cbe64fSgw nvlist_t **top; 3358e7cbe64fSgw uint_t toplevels; 3359e7cbe64fSgw libzfs_handle_t *hdl; 3360e7cbe64fSgw char errbuf[1024]; 3361e7cbe64fSgw char poolname[ZPOOL_MAXNAMELEN]; 3362e7cbe64fSgw int pathlen = strlen(ZVOL_FULL_DEV_DIR); 3363e7cbe64fSgw int ret = 1; 3364e7cbe64fSgw 3365e7cbe64fSgw if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 3366e7cbe64fSgw return (-1); 3367e7cbe64fSgw } 3368e7cbe64fSgw 3369e7cbe64fSgw (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3370e7cbe64fSgw "dump is not supported on device '%s'"), arg); 3371e7cbe64fSgw 3372e7cbe64fSgw if ((hdl = libzfs_init()) == NULL) 3373e7cbe64fSgw return (1); 3374e7cbe64fSgw libzfs_print_on_error(hdl, B_TRUE); 3375e7cbe64fSgw 3376e7cbe64fSgw volname = arg + pathlen; 3377e7cbe64fSgw 3378e7cbe64fSgw /* check the configuration of the pool */ 3379e7cbe64fSgw if ((p = strchr(volname, '/')) == NULL) { 3380e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3381e7cbe64fSgw "malformed dataset name")); 3382e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 3383e7cbe64fSgw return (1); 3384e7cbe64fSgw } else if (p - volname >= ZFS_MAXNAMELEN) { 3385e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3386e7cbe64fSgw "dataset name is too long")); 3387e7cbe64fSgw (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 3388e7cbe64fSgw return (1); 3389e7cbe64fSgw } else { 3390e7cbe64fSgw (void) strncpy(poolname, volname, p - volname); 3391e7cbe64fSgw poolname[p - volname] = '\0'; 3392e7cbe64fSgw } 3393e7cbe64fSgw 3394e7cbe64fSgw if ((zhp = zpool_open(hdl, poolname)) == NULL) { 3395e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3396e7cbe64fSgw "could not open pool '%s'"), poolname); 3397e7cbe64fSgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 3398e7cbe64fSgw goto out; 3399e7cbe64fSgw } 3400e7cbe64fSgw config = zpool_get_config(zhp, NULL); 3401e7cbe64fSgw if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3402e7cbe64fSgw &nvroot) != 0) { 3403e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3404e7cbe64fSgw "could not obtain vdev configuration for '%s'"), poolname); 3405e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 3406e7cbe64fSgw goto out; 3407e7cbe64fSgw } 3408e7cbe64fSgw 3409e7cbe64fSgw verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 3410e7cbe64fSgw &top, &toplevels) == 0); 3411e7cbe64fSgw if (toplevels != 1) { 3412e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3413e7cbe64fSgw "'%s' has multiple top level vdevs"), poolname); 3414e7cbe64fSgw (void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf); 3415e7cbe64fSgw goto out; 3416e7cbe64fSgw } 3417e7cbe64fSgw 3418e7cbe64fSgw if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 3419e7cbe64fSgw goto out; 3420e7cbe64fSgw } 3421e7cbe64fSgw ret = 0; 3422e7cbe64fSgw 3423e7cbe64fSgw out: 3424e7cbe64fSgw if (zhp) 3425e7cbe64fSgw zpool_close(zhp); 3426e7cbe64fSgw libzfs_fini(hdl); 3427e7cbe64fSgw return (ret); 3428e7cbe64fSgw } 3429