1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5441d80aaSlling * Common Development and Distribution License (the "License"). 6441d80aaSlling * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 245cabbc6bSPrashanth Sreenivasa * Copyright (c) 2011, 2017 by Delphix. All rights reserved. 25c1d5c2a4SKody Kantor * Copyright 2019 Joyent, Inc. 266401734dSWill Andrews * Copyright 2016 Nexenta Systems, Inc. 2788f61deeSIgor Kozhukhov * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> 281702cce7SAlek Pinchuk * Copyright (c) 2017 Datto Inc. 29663207adSDon Brady * Copyright (c) 2017, Intel Corporation. 30fa9e4066Sahrens */ 31fa9e4066Sahrens 32fa9e4066Sahrens #include <ctype.h> 33fa9e4066Sahrens #include <errno.h> 34fa9e4066Sahrens #include <devid.h> 35fa9e4066Sahrens #include <fcntl.h> 36fa9e4066Sahrens #include <libintl.h> 37fa9e4066Sahrens #include <stdio.h> 38fa9e4066Sahrens #include <stdlib.h> 39f3861e1aSahl #include <strings.h> 40fa9e4066Sahrens #include <unistd.h> 414445fffbSMatthew Ahrens #include <libgen.h> 428488aeb5Staylor #include <sys/efi_partition.h> 438488aeb5Staylor #include <sys/vtoc.h> 44fa9e4066Sahrens #include <sys/zfs_ioctl.h> 45573ca77eSGeorge Wilson #include <dlfcn.h> 46d8ab6e12SDon Brady #include <libzutil.h> 47fa9e4066Sahrens 48fa9e4066Sahrens #include "zfs_namecheck.h" 49b1b8ab34Slling #include "zfs_prop.h" 50fa9e4066Sahrens #include "libzfs_impl.h" 51468c413aSTim Haley #include "zfs_comutil.h" 52ad135b5dSChristopher Siden #include "zfeature_common.h" 53fa9e4066Sahrens 547855d95bSToomas Soome static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *); 552ba5f978SAlan Somers static boolean_t zpool_vdev_is_interior(const char *name); 56990b4856Slling 57573ca77eSGeorge Wilson #define BACKUP_SLICE "s2" 58573ca77eSGeorge Wilson 59f9af39baSGeorge Wilson typedef struct prop_flags { 60f9af39baSGeorge Wilson int create:1; /* Validate property on creation */ 61f9af39baSGeorge Wilson int import:1; /* Validate property on import */ 62f9af39baSGeorge Wilson } prop_flags_t; 63f9af39baSGeorge Wilson 64990b4856Slling /* 65990b4856Slling * ==================================================================== 66990b4856Slling * zpool property functions 67990b4856Slling * ==================================================================== 68990b4856Slling */ 69990b4856Slling 70990b4856Slling static int 71990b4856Slling zpool_get_all_props(zpool_handle_t *zhp) 72990b4856Slling { 73990b4856Slling zfs_cmd_t zc = { 0 }; 74990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 75990b4856Slling 76990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 77990b4856Slling 78990b4856Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 79990b4856Slling return (-1); 80990b4856Slling 81990b4856Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 82990b4856Slling if (errno == ENOMEM) { 83990b4856Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 84990b4856Slling zcmd_free_nvlists(&zc); 85990b4856Slling return (-1); 86990b4856Slling } 87990b4856Slling } else { 88990b4856Slling zcmd_free_nvlists(&zc); 89990b4856Slling return (-1); 90990b4856Slling } 91990b4856Slling } 92990b4856Slling 93990b4856Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 94990b4856Slling zcmd_free_nvlists(&zc); 95990b4856Slling return (-1); 96990b4856Slling } 97990b4856Slling 98990b4856Slling zcmd_free_nvlists(&zc); 99990b4856Slling 100990b4856Slling return (0); 101990b4856Slling } 102990b4856Slling 103990b4856Slling static int 104990b4856Slling zpool_props_refresh(zpool_handle_t *zhp) 105990b4856Slling { 106990b4856Slling nvlist_t *old_props; 107990b4856Slling 108990b4856Slling old_props = zhp->zpool_props; 109990b4856Slling 110990b4856Slling if (zpool_get_all_props(zhp) != 0) 111990b4856Slling return (-1); 112990b4856Slling 113990b4856Slling nvlist_free(old_props); 114990b4856Slling return (0); 115990b4856Slling } 116990b4856Slling 117990b4856Slling static char * 118990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop, 119990b4856Slling zprop_source_t *src) 120990b4856Slling { 121990b4856Slling nvlist_t *nv, *nvl; 122990b4856Slling uint64_t ival; 123990b4856Slling char *value; 124990b4856Slling zprop_source_t source; 125990b4856Slling 126990b4856Slling nvl = zhp->zpool_props; 127990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 128990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0); 129990b4856Slling source = ival; 130990b4856Slling verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 131990b4856Slling } else { 132990b4856Slling source = ZPROP_SRC_DEFAULT; 133990b4856Slling if ((value = (char *)zpool_prop_default_string(prop)) == NULL) 134990b4856Slling value = "-"; 135990b4856Slling } 136990b4856Slling 137990b4856Slling if (src) 138990b4856Slling *src = source; 139990b4856Slling 140990b4856Slling return (value); 141990b4856Slling } 142990b4856Slling 143990b4856Slling uint64_t 144990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src) 145990b4856Slling { 146990b4856Slling nvlist_t *nv, *nvl; 147990b4856Slling uint64_t value; 148990b4856Slling zprop_source_t source; 149990b4856Slling 150b87f3af3Sperrin if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) { 151b87f3af3Sperrin /* 152b87f3af3Sperrin * zpool_get_all_props() has most likely failed because 153b87f3af3Sperrin * the pool is faulted, but if all we need is the top level 154b87f3af3Sperrin * vdev's guid then get it from the zhp config nvlist. 155b87f3af3Sperrin */ 156b87f3af3Sperrin if ((prop == ZPOOL_PROP_GUID) && 157b87f3af3Sperrin (nvlist_lookup_nvlist(zhp->zpool_config, 158b87f3af3Sperrin ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) && 159b87f3af3Sperrin (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value) 160b87f3af3Sperrin == 0)) { 161b87f3af3Sperrin return (value); 162b87f3af3Sperrin } 163990b4856Slling return (zpool_prop_default_numeric(prop)); 164b87f3af3Sperrin } 165990b4856Slling 166990b4856Slling nvl = zhp->zpool_props; 167990b4856Slling if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) { 168990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0); 169990b4856Slling source = value; 170990b4856Slling verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 171990b4856Slling } else { 172990b4856Slling source = ZPROP_SRC_DEFAULT; 173990b4856Slling value = zpool_prop_default_numeric(prop); 174990b4856Slling } 175990b4856Slling 176990b4856Slling if (src) 177990b4856Slling *src = source; 178990b4856Slling 179990b4856Slling return (value); 180990b4856Slling } 181990b4856Slling 182990b4856Slling /* 183990b4856Slling * Map VDEV STATE to printed strings. 184990b4856Slling */ 1856401734dSWill Andrews const char * 186990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) 187990b4856Slling { 188990b4856Slling switch (state) { 189990b4856Slling case VDEV_STATE_CLOSED: 190990b4856Slling case VDEV_STATE_OFFLINE: 191990b4856Slling return (gettext("OFFLINE")); 192990b4856Slling case VDEV_STATE_REMOVED: 193990b4856Slling return (gettext("REMOVED")); 194990b4856Slling case VDEV_STATE_CANT_OPEN: 195b87f3af3Sperrin if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG) 196990b4856Slling return (gettext("FAULTED")); 1971195e687SMark J Musante else if (aux == VDEV_AUX_SPLIT_POOL) 1981195e687SMark J Musante return (gettext("SPLIT")); 199990b4856Slling else 200990b4856Slling return (gettext("UNAVAIL")); 201990b4856Slling case VDEV_STATE_FAULTED: 202990b4856Slling return (gettext("FAULTED")); 203990b4856Slling case VDEV_STATE_DEGRADED: 204990b4856Slling return (gettext("DEGRADED")); 205990b4856Slling case VDEV_STATE_HEALTHY: 206990b4856Slling return (gettext("ONLINE")); 20788f61deeSIgor Kozhukhov 20888f61deeSIgor Kozhukhov default: 20988f61deeSIgor Kozhukhov break; 210990b4856Slling } 211990b4856Slling 212990b4856Slling return (gettext("UNKNOWN")); 213990b4856Slling } 214990b4856Slling 2156401734dSWill Andrews /* 2166401734dSWill Andrews * Map POOL STATE to printed strings. 2176401734dSWill Andrews */ 2186401734dSWill Andrews const char * 2196401734dSWill Andrews zpool_pool_state_to_name(pool_state_t state) 2206401734dSWill Andrews { 2216401734dSWill Andrews switch (state) { 2226401734dSWill Andrews case POOL_STATE_ACTIVE: 2236401734dSWill Andrews return (gettext("ACTIVE")); 2246401734dSWill Andrews case POOL_STATE_EXPORTED: 2256401734dSWill Andrews return (gettext("EXPORTED")); 2266401734dSWill Andrews case POOL_STATE_DESTROYED: 2276401734dSWill Andrews return (gettext("DESTROYED")); 2286401734dSWill Andrews case POOL_STATE_SPARE: 2296401734dSWill Andrews return (gettext("SPARE")); 2306401734dSWill Andrews case POOL_STATE_L2CACHE: 2316401734dSWill Andrews return (gettext("L2CACHE")); 2326401734dSWill Andrews case POOL_STATE_UNINITIALIZED: 2336401734dSWill Andrews return (gettext("UNINITIALIZED")); 2346401734dSWill Andrews case POOL_STATE_UNAVAIL: 2356401734dSWill Andrews return (gettext("UNAVAIL")); 2366401734dSWill Andrews case POOL_STATE_POTENTIALLY_ACTIVE: 2376401734dSWill Andrews return (gettext("POTENTIALLY_ACTIVE")); 2386401734dSWill Andrews } 2396401734dSWill Andrews 2406401734dSWill Andrews return (gettext("UNKNOWN")); 2416401734dSWill Andrews } 2426401734dSWill Andrews 243990b4856Slling /* 244990b4856Slling * Get a zpool property value for 'prop' and return the value in 245990b4856Slling * a pre-allocated buffer. 246990b4856Slling */ 247990b4856Slling int 248990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, 249c58b3526SAdam Stevko zprop_source_t *srctype, boolean_t literal) 250990b4856Slling { 251990b4856Slling uint64_t intval; 252990b4856Slling const char *strval; 253990b4856Slling zprop_source_t src = ZPROP_SRC_NONE; 254990b4856Slling nvlist_t *nvroot; 255990b4856Slling vdev_stat_t *vs; 256990b4856Slling uint_t vsc; 257990b4856Slling 258990b4856Slling if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 259379c004dSEric Schrock switch (prop) { 260379c004dSEric Schrock case ZPOOL_PROP_NAME: 261990b4856Slling (void) strlcpy(buf, zpool_get_name(zhp), len); 262379c004dSEric Schrock break; 263379c004dSEric Schrock 264379c004dSEric Schrock case ZPOOL_PROP_HEALTH: 265990b4856Slling (void) strlcpy(buf, "FAULTED", len); 266379c004dSEric Schrock break; 267379c004dSEric Schrock 268379c004dSEric Schrock case ZPOOL_PROP_GUID: 269379c004dSEric Schrock intval = zpool_get_prop_int(zhp, prop, &src); 270379c004dSEric Schrock (void) snprintf(buf, len, "%llu", intval); 271379c004dSEric Schrock break; 272379c004dSEric Schrock 273379c004dSEric Schrock case ZPOOL_PROP_ALTROOT: 274379c004dSEric Schrock case ZPOOL_PROP_CACHEFILE: 2758704186eSDan McDonald case ZPOOL_PROP_COMMENT: 276379c004dSEric Schrock if (zhp->zpool_props != NULL || 277379c004dSEric Schrock zpool_get_all_props(zhp) == 0) { 278379c004dSEric Schrock (void) strlcpy(buf, 279379c004dSEric Schrock zpool_get_prop_string(zhp, prop, &src), 280379c004dSEric Schrock len); 281c58b3526SAdam Stevko break; 282379c004dSEric Schrock } 283379c004dSEric Schrock /* FALLTHROUGH */ 284379c004dSEric Schrock default: 285990b4856Slling (void) strlcpy(buf, "-", len); 286379c004dSEric Schrock break; 287379c004dSEric Schrock } 288379c004dSEric Schrock 289379c004dSEric Schrock if (srctype != NULL) 290379c004dSEric Schrock *srctype = src; 291990b4856Slling return (0); 292990b4856Slling } 293990b4856Slling 294990b4856Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 295990b4856Slling prop != ZPOOL_PROP_NAME) 296990b4856Slling return (-1); 297990b4856Slling 298990b4856Slling switch (zpool_prop_get_type(prop)) { 299990b4856Slling case PROP_TYPE_STRING: 300990b4856Slling (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), 301990b4856Slling len); 302990b4856Slling break; 303990b4856Slling 304990b4856Slling case PROP_TYPE_NUMBER: 305990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 306990b4856Slling 307990b4856Slling switch (prop) { 308990b4856Slling case ZPOOL_PROP_SIZE: 309485bbbf5SGeorge Wilson case ZPOOL_PROP_ALLOCATED: 310485bbbf5SGeorge Wilson case ZPOOL_PROP_FREE: 311ad135b5dSChristopher Siden case ZPOOL_PROP_FREEING: 3127fd05ac4SMatthew Ahrens case ZPOOL_PROP_LEAKED: 3135711d393Sloli case ZPOOL_PROP_ASHIFT: 314c58b3526SAdam Stevko if (literal) { 315c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu", 316c58b3526SAdam Stevko (u_longlong_t)intval); 317c58b3526SAdam Stevko } else { 318c58b3526SAdam Stevko (void) zfs_nicenum(intval, buf, len); 319c58b3526SAdam Stevko } 320990b4856Slling break; 3217855d95bSToomas Soome case ZPOOL_PROP_BOOTSIZE: 3227a09f97bSGeorge Wilson case ZPOOL_PROP_EXPANDSZ: 32386714001SSerapheim Dimitropoulos case ZPOOL_PROP_CHECKPOINT: 3247a09f97bSGeorge Wilson if (intval == 0) { 3257a09f97bSGeorge Wilson (void) strlcpy(buf, "-", len); 3267a09f97bSGeorge Wilson } else if (literal) { 3277a09f97bSGeorge Wilson (void) snprintf(buf, len, "%llu", 3287a09f97bSGeorge Wilson (u_longlong_t)intval); 3297a09f97bSGeorge Wilson } else { 3307a09f97bSGeorge Wilson (void) zfs_nicenum(intval, buf, len); 3317a09f97bSGeorge Wilson } 3327a09f97bSGeorge Wilson break; 333990b4856Slling case ZPOOL_PROP_CAPACITY: 334c58b3526SAdam Stevko if (literal) { 335c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu", 336c58b3526SAdam Stevko (u_longlong_t)intval); 337c58b3526SAdam Stevko } else { 338c58b3526SAdam Stevko (void) snprintf(buf, len, "%llu%%", 339c58b3526SAdam Stevko (u_longlong_t)intval); 340c58b3526SAdam Stevko } 341990b4856Slling break; 3422e4c9986SGeorge Wilson case ZPOOL_PROP_FRAGMENTATION: 3432e4c9986SGeorge Wilson if (intval == UINT64_MAX) { 3442e4c9986SGeorge Wilson (void) strlcpy(buf, "-", len); 3452e4c9986SGeorge Wilson } else { 3462e4c9986SGeorge Wilson (void) snprintf(buf, len, "%llu%%", 3472e4c9986SGeorge Wilson (u_longlong_t)intval); 3482e4c9986SGeorge Wilson } 3492e4c9986SGeorge Wilson break; 350b24ab676SJeff Bonwick case ZPOOL_PROP_DEDUPRATIO: 351b24ab676SJeff Bonwick (void) snprintf(buf, len, "%llu.%02llux", 352b24ab676SJeff Bonwick (u_longlong_t)(intval / 100), 353b24ab676SJeff Bonwick (u_longlong_t)(intval % 100)); 354b24ab676SJeff Bonwick break; 355990b4856Slling case ZPOOL_PROP_HEALTH: 356990b4856Slling verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 357990b4856Slling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 358990b4856Slling verify(nvlist_lookup_uint64_array(nvroot, 3593f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) 3603f9d6ad7SLin Ling == 0); 361990b4856Slling 362990b4856Slling (void) strlcpy(buf, zpool_state_to_name(intval, 363990b4856Slling vs->vs_aux), len); 364990b4856Slling break; 365ad135b5dSChristopher Siden case ZPOOL_PROP_VERSION: 366ad135b5dSChristopher Siden if (intval >= SPA_VERSION_FEATURES) { 367ad135b5dSChristopher Siden (void) snprintf(buf, len, "-"); 368ad135b5dSChristopher Siden break; 369ad135b5dSChristopher Siden } 370ad135b5dSChristopher Siden /* FALLTHROUGH */ 371990b4856Slling default: 372990b4856Slling (void) snprintf(buf, len, "%llu", intval); 373990b4856Slling } 374990b4856Slling break; 375990b4856Slling 376990b4856Slling case PROP_TYPE_INDEX: 377990b4856Slling intval = zpool_get_prop_int(zhp, prop, &src); 378990b4856Slling if (zpool_prop_index_to_string(prop, intval, &strval) 379990b4856Slling != 0) 380990b4856Slling return (-1); 381990b4856Slling (void) strlcpy(buf, strval, len); 382990b4856Slling break; 383990b4856Slling 384990b4856Slling default: 385990b4856Slling abort(); 386990b4856Slling } 387990b4856Slling 388990b4856Slling if (srctype) 389990b4856Slling *srctype = src; 390990b4856Slling 391990b4856Slling return (0); 392990b4856Slling } 393990b4856Slling 394990b4856Slling /* 395990b4856Slling * Check if the bootfs name has the same pool name as it is set to. 396990b4856Slling * Assuming bootfs is a valid dataset name. 397990b4856Slling */ 398990b4856Slling static boolean_t 399990b4856Slling bootfs_name_valid(const char *pool, char *bootfs) 400990b4856Slling { 401990b4856Slling int len = strlen(pool); 402015f38bbSPaul Dagnelie if (bootfs[0] == '\0') 403015f38bbSPaul Dagnelie return (B_TRUE); 404990b4856Slling 405fe3e2633SEric Taylor if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT)) 406990b4856Slling return (B_FALSE); 407990b4856Slling 408990b4856Slling if (strncmp(pool, bootfs, len) == 0 && 409990b4856Slling (bootfs[len] == '/' || bootfs[len] == '\0')) 410990b4856Slling return (B_TRUE); 411990b4856Slling 412990b4856Slling return (B_FALSE); 413990b4856Slling } 414990b4856Slling 4154263d13fSGeorge Wilson boolean_t 4164263d13fSGeorge Wilson zpool_is_bootable(zpool_handle_t *zhp) 417b5b76fecSGeorge Wilson { 4189adfa60dSMatthew Ahrens char bootfs[ZFS_MAX_DATASET_NAME_LEN]; 419b5b76fecSGeorge Wilson 420b5b76fecSGeorge Wilson return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, 421c58b3526SAdam Stevko sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-", 422b5b76fecSGeorge Wilson sizeof (bootfs)) != 0); 423b5b76fecSGeorge Wilson } 424b5b76fecSGeorge Wilson 425b5b76fecSGeorge Wilson 426990b4856Slling /* 427990b4856Slling * Given an nvlist of zpool properties to be set, validate that they are 428990b4856Slling * correct, and parse any numeric properties (index, boolean, etc) if they are 429990b4856Slling * specified as strings. 430990b4856Slling */ 431990b4856Slling static nvlist_t * 4320a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, 433f9af39baSGeorge Wilson nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf) 434990b4856Slling { 435990b4856Slling nvpair_t *elem; 436990b4856Slling nvlist_t *retprops; 437990b4856Slling zpool_prop_t prop; 438990b4856Slling char *strval; 439990b4856Slling uint64_t intval; 4408704186eSDan McDonald char *slash, *check; 4412f8aaab3Seschrock struct stat64 statbuf; 44215e6edf1Sgw zpool_handle_t *zhp; 443990b4856Slling 444990b4856Slling if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { 445990b4856Slling (void) no_memory(hdl); 446990b4856Slling return (NULL); 447990b4856Slling } 448990b4856Slling 449990b4856Slling elem = NULL; 450990b4856Slling while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 451990b4856Slling const char *propname = nvpair_name(elem); 452990b4856Slling 453ad135b5dSChristopher Siden prop = zpool_name_to_prop(propname); 4544ae5f5f0SAlan Somers if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) { 455ad135b5dSChristopher Siden int err; 456ad135b5dSChristopher Siden char *fname = strchr(propname, '@') + 1; 457ad135b5dSChristopher Siden 4582acef22dSMatthew Ahrens err = zfeature_lookup_name(fname, NULL); 459ad135b5dSChristopher Siden if (err != 0) { 460ad135b5dSChristopher Siden ASSERT3U(err, ==, ENOENT); 461ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4625711d393Sloli "invalid feature '%s', '%s'"), fname, 4635711d393Sloli propname); 464ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 465ad135b5dSChristopher Siden goto error; 466ad135b5dSChristopher Siden } 467ad135b5dSChristopher Siden 468ad135b5dSChristopher Siden if (nvpair_type(elem) != DATA_TYPE_STRING) { 469ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 470ad135b5dSChristopher Siden "'%s' must be a string"), propname); 471ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 472ad135b5dSChristopher Siden goto error; 473ad135b5dSChristopher Siden } 474ad135b5dSChristopher Siden 475ad135b5dSChristopher Siden (void) nvpair_value_string(elem, &strval); 476*f3434519SLOLi if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0 && 477*f3434519SLOLi strcmp(strval, ZFS_FEATURE_DISABLED) != 0) { 478ad135b5dSChristopher Siden zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 479ad135b5dSChristopher Siden "property '%s' can only be set to " 480*f3434519SLOLi "'enabled' or 'disabled'"), propname); 481ad135b5dSChristopher Siden (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 482ad135b5dSChristopher Siden goto error; 483ad135b5dSChristopher Siden } 484ad135b5dSChristopher Siden 485ad135b5dSChristopher Siden if (nvlist_add_uint64(retprops, propname, 0) != 0) { 486ad135b5dSChristopher Siden (void) no_memory(hdl); 487ad135b5dSChristopher Siden goto error; 488ad135b5dSChristopher Siden } 489ad135b5dSChristopher Siden continue; 490ad135b5dSChristopher Siden } 491ad135b5dSChristopher Siden 492990b4856Slling /* 493990b4856Slling * Make sure this property is valid and applies to this type. 494990b4856Slling */ 4954ae5f5f0SAlan Somers if (prop == ZPOOL_PROP_INVAL) { 496990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 497990b4856Slling "invalid property '%s'"), propname); 498990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 499990b4856Slling goto error; 500990b4856Slling } 501990b4856Slling 502990b4856Slling if (zpool_prop_readonly(prop)) { 503990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 504990b4856Slling "is readonly"), propname); 505990b4856Slling (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 506990b4856Slling goto error; 507990b4856Slling } 508990b4856Slling 509990b4856Slling if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops, 510990b4856Slling &strval, &intval, errbuf) != 0) 511990b4856Slling goto error; 512990b4856Slling 513990b4856Slling /* 514990b4856Slling * Perform additional checking for specific properties. 515990b4856Slling */ 516990b4856Slling switch (prop) { 517990b4856Slling case ZPOOL_PROP_VERSION: 518ad135b5dSChristopher Siden if (intval < version || 519ad135b5dSChristopher Siden !SPA_VERSION_IS_SUPPORTED(intval)) { 520990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 521990b4856Slling "property '%s' number %d is invalid."), 522990b4856Slling propname, intval); 523990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 524990b4856Slling goto error; 525990b4856Slling } 526990b4856Slling break; 527990b4856Slling 5287855d95bSToomas Soome case ZPOOL_PROP_BOOTSIZE: 5297855d95bSToomas Soome if (!flags.create) { 5307855d95bSToomas Soome zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5317855d95bSToomas Soome "property '%s' can only be set during pool " 5327855d95bSToomas Soome "creation"), propname); 5337855d95bSToomas Soome (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 5347855d95bSToomas Soome goto error; 5357855d95bSToomas Soome } 5367855d95bSToomas Soome break; 5377855d95bSToomas Soome 5385711d393Sloli case ZPOOL_PROP_ASHIFT: 5395711d393Sloli if (intval != 0 && 5405711d393Sloli (intval < ASHIFT_MIN || intval > ASHIFT_MAX)) { 5415711d393Sloli zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5425711d393Sloli "invalid '%s=%d' property: only values " 5435711d393Sloli "between %" PRId32 " and %" PRId32 " " 5445711d393Sloli "are allowed.\n"), 5455711d393Sloli propname, intval, ASHIFT_MIN, ASHIFT_MAX); 5465711d393Sloli (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 5475711d393Sloli goto error; 5485711d393Sloli } 5495711d393Sloli break; 5505711d393Sloli 551990b4856Slling case ZPOOL_PROP_BOOTFS: 552f9af39baSGeorge Wilson if (flags.create || flags.import) { 553990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 554990b4856Slling "property '%s' cannot be set at creation " 555990b4856Slling "or import time"), propname); 556990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 557990b4856Slling goto error; 558990b4856Slling } 559990b4856Slling 560990b4856Slling if (version < SPA_VERSION_BOOTFS) { 561990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 562990b4856Slling "pool must be upgraded to support " 563990b4856Slling "'%s' property"), propname); 564990b4856Slling (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 565990b4856Slling goto error; 566990b4856Slling } 567990b4856Slling 568990b4856Slling /* 569990b4856Slling * bootfs property value has to be a dataset name and 570990b4856Slling * the dataset has to be in the same pool as it sets to. 571990b4856Slling */ 572015f38bbSPaul Dagnelie if (!bootfs_name_valid(poolname, strval)) { 573990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 574990b4856Slling "is an invalid name"), strval); 575990b4856Slling (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 576990b4856Slling goto error; 577990b4856Slling } 57815e6edf1Sgw 57915e6edf1Sgw if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { 58015e6edf1Sgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 58115e6edf1Sgw "could not open pool '%s'"), poolname); 58215e6edf1Sgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 58315e6edf1Sgw goto error; 58415e6edf1Sgw } 58515e6edf1Sgw zpool_close(zhp); 586990b4856Slling break; 587990b4856Slling 5882f8aaab3Seschrock case ZPOOL_PROP_ALTROOT: 589f9af39baSGeorge Wilson if (!flags.create && !flags.import) { 590990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 591990b4856Slling "property '%s' can only be set during pool " 592990b4856Slling "creation or import"), propname); 593990b4856Slling (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 594990b4856Slling goto error; 595990b4856Slling } 596990b4856Slling 5972f8aaab3Seschrock if (strval[0] != '/') { 598990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5992f8aaab3Seschrock "bad alternate root '%s'"), strval); 6002f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 601990b4856Slling goto error; 602990b4856Slling } 6032f8aaab3Seschrock break; 6042f8aaab3Seschrock 6052f8aaab3Seschrock case ZPOOL_PROP_CACHEFILE: 6062f8aaab3Seschrock if (strval[0] == '\0') 6072f8aaab3Seschrock break; 6082f8aaab3Seschrock 6092f8aaab3Seschrock if (strcmp(strval, "none") == 0) 6102f8aaab3Seschrock break; 611990b4856Slling 612990b4856Slling if (strval[0] != '/') { 613990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6142f8aaab3Seschrock "property '%s' must be empty, an " 6152f8aaab3Seschrock "absolute path, or 'none'"), propname); 616990b4856Slling (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 617990b4856Slling goto error; 618990b4856Slling } 619990b4856Slling 6202f8aaab3Seschrock slash = strrchr(strval, '/'); 621990b4856Slling 6222f8aaab3Seschrock if (slash[1] == '\0' || strcmp(slash, "/.") == 0 || 6232f8aaab3Seschrock strcmp(slash, "/..") == 0) { 6242f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6252f8aaab3Seschrock "'%s' is not a valid file"), strval); 6262f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 6272f8aaab3Seschrock goto error; 6282f8aaab3Seschrock } 629990b4856Slling 6302f8aaab3Seschrock *slash = '\0'; 6312f8aaab3Seschrock 6322c32020fSeschrock if (strval[0] != '\0' && 6332c32020fSeschrock (stat64(strval, &statbuf) != 0 || 6342c32020fSeschrock !S_ISDIR(statbuf.st_mode))) { 6352f8aaab3Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6362f8aaab3Seschrock "'%s' is not a valid directory"), 6372f8aaab3Seschrock strval); 6382f8aaab3Seschrock (void) zfs_error(hdl, EZFS_BADPATH, errbuf); 6392f8aaab3Seschrock goto error; 6402f8aaab3Seschrock } 6412f8aaab3Seschrock 6422f8aaab3Seschrock *slash = '/'; 6432f8aaab3Seschrock break; 644f9af39baSGeorge Wilson 6458704186eSDan McDonald case ZPOOL_PROP_COMMENT: 6468704186eSDan McDonald for (check = strval; *check != '\0'; check++) { 6478704186eSDan McDonald if (!isprint(*check)) { 6488704186eSDan McDonald zfs_error_aux(hdl, 6498704186eSDan McDonald dgettext(TEXT_DOMAIN, 6508704186eSDan McDonald "comment may only have printable " 6518704186eSDan McDonald "characters")); 6528704186eSDan McDonald (void) zfs_error(hdl, EZFS_BADPROP, 6538704186eSDan McDonald errbuf); 6548704186eSDan McDonald goto error; 6558704186eSDan McDonald } 6568704186eSDan McDonald } 6578704186eSDan McDonald if (strlen(strval) > ZPROP_MAX_COMMENT) { 6588704186eSDan McDonald zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 6598704186eSDan McDonald "comment must not exceed %d characters"), 6608704186eSDan McDonald ZPROP_MAX_COMMENT); 6618704186eSDan McDonald (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 6628704186eSDan McDonald goto error; 6638704186eSDan McDonald } 6648704186eSDan McDonald break; 66504e56356SAndriy Gapon 666f9af39baSGeorge Wilson case ZPOOL_PROP_READONLY: 667f9af39baSGeorge Wilson if (!flags.import) { 668f9af39baSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 669f9af39baSGeorge Wilson "property '%s' can only be set at " 670f9af39baSGeorge Wilson "import time"), propname); 671f9af39baSGeorge Wilson (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 672f9af39baSGeorge Wilson goto error; 673f9af39baSGeorge Wilson } 674f9af39baSGeorge Wilson break; 67588f61deeSIgor Kozhukhov 67604e56356SAndriy Gapon case ZPOOL_PROP_TNAME: 67704e56356SAndriy Gapon if (!flags.create) { 67804e56356SAndriy Gapon zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 67904e56356SAndriy Gapon "property '%s' can only be set at " 68004e56356SAndriy Gapon "creation time"), propname); 68104e56356SAndriy Gapon (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 68204e56356SAndriy Gapon goto error; 68304e56356SAndriy Gapon } 68404e56356SAndriy Gapon break; 68504e56356SAndriy Gapon 686e0f1c0afSOlaf Faaland case ZPOOL_PROP_MULTIHOST: 687e0f1c0afSOlaf Faaland if (get_system_hostid() == 0) { 688e0f1c0afSOlaf Faaland zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 689e0f1c0afSOlaf Faaland "requires a non-zero system hostid")); 690e0f1c0afSOlaf Faaland (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 691e0f1c0afSOlaf Faaland goto error; 692e0f1c0afSOlaf Faaland } 693e0f1c0afSOlaf Faaland break; 694e0f1c0afSOlaf Faaland 69588f61deeSIgor Kozhukhov default: 69688f61deeSIgor Kozhukhov zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 69788f61deeSIgor Kozhukhov "property '%s'(%d) not defined"), propname, prop); 69888f61deeSIgor Kozhukhov break; 699990b4856Slling } 700990b4856Slling } 701990b4856Slling 702990b4856Slling return (retprops); 703990b4856Slling error: 704990b4856Slling nvlist_free(retprops); 705990b4856Slling return (NULL); 706990b4856Slling } 707990b4856Slling 708990b4856Slling /* 709990b4856Slling * Set zpool property : propname=propval. 710990b4856Slling */ 711990b4856Slling int 712990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 713990b4856Slling { 714990b4856Slling zfs_cmd_t zc = { 0 }; 715990b4856Slling int ret = -1; 716990b4856Slling char errbuf[1024]; 717990b4856Slling nvlist_t *nvl = NULL; 718990b4856Slling nvlist_t *realprops; 719990b4856Slling uint64_t version; 720f9af39baSGeorge Wilson prop_flags_t flags = { 0 }; 721990b4856Slling 722990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), 723990b4856Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 724990b4856Slling zhp->zpool_name); 725990b4856Slling 726990b4856Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 727990b4856Slling return (no_memory(zhp->zpool_hdl)); 728990b4856Slling 729990b4856Slling if (nvlist_add_string(nvl, propname, propval) != 0) { 730990b4856Slling nvlist_free(nvl); 731990b4856Slling return (no_memory(zhp->zpool_hdl)); 732990b4856Slling } 733990b4856Slling 734990b4856Slling version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 7350a48a24eStimh if ((realprops = zpool_valid_proplist(zhp->zpool_hdl, 736f9af39baSGeorge Wilson zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) { 737990b4856Slling nvlist_free(nvl); 738990b4856Slling return (-1); 739990b4856Slling } 740990b4856Slling 741990b4856Slling nvlist_free(nvl); 742990b4856Slling nvl = realprops; 743990b4856Slling 744990b4856Slling /* 745990b4856Slling * Execute the corresponding ioctl() to set this property. 746990b4856Slling */ 747990b4856Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 748990b4856Slling 749990b4856Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) { 750990b4856Slling nvlist_free(nvl); 751990b4856Slling return (-1); 752990b4856Slling } 753990b4856Slling 754990b4856Slling ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 755990b4856Slling 756990b4856Slling zcmd_free_nvlists(&zc); 757990b4856Slling nvlist_free(nvl); 758990b4856Slling 759990b4856Slling if (ret) 760990b4856Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 761990b4856Slling else 762990b4856Slling (void) zpool_props_refresh(zhp); 763990b4856Slling 764990b4856Slling return (ret); 765990b4856Slling } 766990b4856Slling 767990b4856Slling int 768990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) 769990b4856Slling { 770990b4856Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 771990b4856Slling zprop_list_t *entry; 772990b4856Slling char buf[ZFS_MAXPROPLEN]; 773ad135b5dSChristopher Siden nvlist_t *features = NULL; 774ad135b5dSChristopher Siden zprop_list_t **last; 775ad135b5dSChristopher Siden boolean_t firstexpand = (NULL == *plp); 776990b4856Slling 777990b4856Slling if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) 778990b4856Slling return (-1); 779990b4856Slling 780ad135b5dSChristopher Siden last = plp; 781ad135b5dSChristopher Siden while (*last != NULL) 782ad135b5dSChristopher Siden last = &(*last)->pl_next; 783ad135b5dSChristopher Siden 784ad135b5dSChristopher Siden if ((*plp)->pl_all) 785ad135b5dSChristopher Siden features = zpool_get_features(zhp); 786ad135b5dSChristopher Siden 787ad135b5dSChristopher Siden if ((*plp)->pl_all && firstexpand) { 788ad135b5dSChristopher Siden for (int i = 0; i < SPA_FEATURES; i++) { 789ad135b5dSChristopher Siden zprop_list_t *entry = zfs_alloc(hdl, 790ad135b5dSChristopher Siden sizeof (zprop_list_t)); 791ad135b5dSChristopher Siden entry->pl_prop = ZPROP_INVAL; 792ad135b5dSChristopher Siden entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s", 793ad135b5dSChristopher Siden spa_feature_table[i].fi_uname); 794ad135b5dSChristopher Siden entry->pl_width = strlen(entry->pl_user_prop); 795ad135b5dSChristopher Siden entry->pl_all = B_TRUE; 796ad135b5dSChristopher Siden 797ad135b5dSChristopher Siden *last = entry; 798ad135b5dSChristopher Siden last = &entry->pl_next; 799ad135b5dSChristopher Siden } 800ad135b5dSChristopher Siden } 801ad135b5dSChristopher Siden 802ad135b5dSChristopher Siden /* add any unsupported features */ 803ad135b5dSChristopher Siden for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL); 804ad135b5dSChristopher Siden nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) { 805ad135b5dSChristopher Siden char *propname; 806ad135b5dSChristopher Siden boolean_t found; 807ad135b5dSChristopher Siden zprop_list_t *entry; 808ad135b5dSChristopher Siden 809ad135b5dSChristopher Siden if (zfeature_is_supported(nvpair_name(nvp))) 810ad135b5dSChristopher Siden continue; 811ad135b5dSChristopher Siden 812ad135b5dSChristopher Siden propname = zfs_asprintf(hdl, "unsupported@%s", 813ad135b5dSChristopher Siden nvpair_name(nvp)); 814ad135b5dSChristopher Siden 815ad135b5dSChristopher Siden /* 816ad135b5dSChristopher Siden * Before adding the property to the list make sure that no 817ad135b5dSChristopher Siden * other pool already added the same property. 818ad135b5dSChristopher Siden */ 819ad135b5dSChristopher Siden found = B_FALSE; 820ad135b5dSChristopher Siden entry = *plp; 821ad135b5dSChristopher Siden while (entry != NULL) { 822ad135b5dSChristopher Siden if (entry->pl_user_prop != NULL && 823ad135b5dSChristopher Siden strcmp(propname, entry->pl_user_prop) == 0) { 824ad135b5dSChristopher Siden found = B_TRUE; 825ad135b5dSChristopher Siden break; 826ad135b5dSChristopher Siden } 827ad135b5dSChristopher Siden entry = entry->pl_next; 828ad135b5dSChristopher Siden } 829ad135b5dSChristopher Siden if (found) { 830ad135b5dSChristopher Siden free(propname); 831ad135b5dSChristopher Siden continue; 832ad135b5dSChristopher Siden } 833ad135b5dSChristopher Siden 834ad135b5dSChristopher Siden entry = zfs_alloc(hdl, sizeof (zprop_list_t)); 835ad135b5dSChristopher Siden entry->pl_prop = ZPROP_INVAL; 836ad135b5dSChristopher Siden entry->pl_user_prop = propname; 837ad135b5dSChristopher Siden entry->pl_width = strlen(entry->pl_user_prop); 838ad135b5dSChristopher Siden entry->pl_all = B_TRUE; 839ad135b5dSChristopher Siden 840ad135b5dSChristopher Siden *last = entry; 841ad135b5dSChristopher Siden last = &entry->pl_next; 842ad135b5dSChristopher Siden } 843ad135b5dSChristopher Siden 844990b4856Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 845990b4856Slling 846990b4856Slling if (entry->pl_fixed) 847990b4856Slling continue; 848990b4856Slling 849990b4856Slling if (entry->pl_prop != ZPROP_INVAL && 850990b4856Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 851c58b3526SAdam Stevko NULL, B_FALSE) == 0) { 852990b4856Slling if (strlen(buf) > entry->pl_width) 853990b4856Slling entry->pl_width = strlen(buf); 854990b4856Slling } 855990b4856Slling } 856990b4856Slling 857990b4856Slling return (0); 858990b4856Slling } 859990b4856Slling 860ad135b5dSChristopher Siden /* 861ad135b5dSChristopher Siden * Get the state for the given feature on the given ZFS pool. 862ad135b5dSChristopher Siden */ 863ad135b5dSChristopher Siden int 864ad135b5dSChristopher Siden zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf, 865ad135b5dSChristopher Siden size_t len) 866ad135b5dSChristopher Siden { 867ad135b5dSChristopher Siden uint64_t refcount; 868ad135b5dSChristopher Siden boolean_t found = B_FALSE; 869ad135b5dSChristopher Siden nvlist_t *features = zpool_get_features(zhp); 870ad135b5dSChristopher Siden boolean_t supported; 871ad135b5dSChristopher Siden const char *feature = strchr(propname, '@') + 1; 872ad135b5dSChristopher Siden 873ad135b5dSChristopher Siden supported = zpool_prop_feature(propname); 8747c13517fSSerapheim Dimitropoulos ASSERT(supported || zpool_prop_unsupported(propname)); 875ad135b5dSChristopher Siden 876ad135b5dSChristopher Siden /* 877ad135b5dSChristopher Siden * Convert from feature name to feature guid. This conversion is 878ad135b5dSChristopher Siden * unecessary for unsupported@... properties because they already 879ad135b5dSChristopher Siden * use guids. 880ad135b5dSChristopher Siden */ 881ad135b5dSChristopher Siden if (supported) { 882ad135b5dSChristopher Siden int ret; 8832acef22dSMatthew Ahrens spa_feature_t fid; 884ad135b5dSChristopher Siden 8852acef22dSMatthew Ahrens ret = zfeature_lookup_name(feature, &fid); 886ad135b5dSChristopher Siden if (ret != 0) { 887ad135b5dSChristopher Siden (void) strlcpy(buf, "-", len); 888ad135b5dSChristopher Siden return (ENOTSUP); 889ad135b5dSChristopher Siden } 8902acef22dSMatthew Ahrens feature = spa_feature_table[fid].fi_guid; 891ad135b5dSChristopher Siden } 892ad135b5dSChristopher Siden 893ad135b5dSChristopher Siden if (nvlist_lookup_uint64(features, feature, &refcount) == 0) 894ad135b5dSChristopher Siden found = B_TRUE; 895ad135b5dSChristopher Siden 896ad135b5dSChristopher Siden if (supported) { 897ad135b5dSChristopher Siden if (!found) { 898ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len); 899ad135b5dSChristopher Siden } else { 900ad135b5dSChristopher Siden if (refcount == 0) 901ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len); 902ad135b5dSChristopher Siden else 903ad135b5dSChristopher Siden (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len); 904ad135b5dSChristopher Siden } 905ad135b5dSChristopher Siden } else { 906ad135b5dSChristopher Siden if (found) { 907ad135b5dSChristopher Siden if (refcount == 0) { 908ad135b5dSChristopher Siden (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE); 909ad135b5dSChristopher Siden } else { 910ad135b5dSChristopher Siden (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY); 911ad135b5dSChristopher Siden } 912ad135b5dSChristopher Siden } else { 913ad135b5dSChristopher Siden (void) strlcpy(buf, "-", len); 914ad135b5dSChristopher Siden return (ENOTSUP); 915ad135b5dSChristopher Siden } 916ad135b5dSChristopher Siden } 917ad135b5dSChristopher Siden 918ad135b5dSChristopher Siden return (0); 919ad135b5dSChristopher Siden } 920990b4856Slling 921573ca77eSGeorge Wilson /* 922573ca77eSGeorge Wilson * Don't start the slice at the default block of 34; many storage 923573ca77eSGeorge Wilson * devices will use a stripe width of 128k, so start there instead. 924573ca77eSGeorge Wilson */ 925573ca77eSGeorge Wilson #define NEW_START_BLOCK 256 926573ca77eSGeorge Wilson 927fa9e4066Sahrens /* 928fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 929fa9e4066Sahrens * 'buf'. 930fa9e4066Sahrens */ 931e7cbe64fSgw boolean_t 93299653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 933fa9e4066Sahrens { 934fa9e4066Sahrens namecheck_err_t why; 935fa9e4066Sahrens char what; 936b468a217Seschrock int ret; 937b468a217Seschrock 938b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 939b468a217Seschrock 940b468a217Seschrock /* 941b468a217Seschrock * The rules for reserved pool names were extended at a later point. 942b468a217Seschrock * But we need to support users with existing pools that may now be 943b468a217Seschrock * invalid. So we only check for this expanded set of names during a 944b468a217Seschrock * create (or import), and only in userland. 945b468a217Seschrock */ 946b468a217Seschrock if (ret == 0 && !isopen && 947b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 948b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 9498654d025Sperrin strncmp(pool, "spare", 5) == 0 || 9508654d025Sperrin strcmp(pool, "log") == 0)) { 951e7cbe64fSgw if (hdl != NULL) 952e7cbe64fSgw zfs_error_aux(hdl, 953e7cbe64fSgw dgettext(TEXT_DOMAIN, "name is reserved")); 95499653d4eSeschrock return (B_FALSE); 955b468a217Seschrock } 956b468a217Seschrock 957fa9e4066Sahrens 958b468a217Seschrock if (ret != 0) { 95999653d4eSeschrock if (hdl != NULL) { 960fa9e4066Sahrens switch (why) { 961b81d61a6Slling case NAME_ERR_TOOLONG: 96299653d4eSeschrock zfs_error_aux(hdl, 963b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 964b81d61a6Slling break; 965b81d61a6Slling 966fa9e4066Sahrens case NAME_ERR_INVALCHAR: 96799653d4eSeschrock zfs_error_aux(hdl, 968fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 969fa9e4066Sahrens "'%c' in pool name"), what); 970fa9e4066Sahrens break; 971fa9e4066Sahrens 972fa9e4066Sahrens case NAME_ERR_NOLETTER: 97399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 97499653d4eSeschrock "name must begin with a letter")); 975fa9e4066Sahrens break; 976fa9e4066Sahrens 977fa9e4066Sahrens case NAME_ERR_RESERVED: 97899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 97999653d4eSeschrock "name is reserved")); 980fa9e4066Sahrens break; 981fa9e4066Sahrens 982fa9e4066Sahrens case NAME_ERR_DISKLIKE: 98399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 98499653d4eSeschrock "pool name is reserved")); 985fa9e4066Sahrens break; 9865ad82045Snd 9875ad82045Snd case NAME_ERR_LEADING_SLASH: 9885ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9895ad82045Snd "leading slash in name")); 9905ad82045Snd break; 9915ad82045Snd 9925ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 9935ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9945ad82045Snd "empty component in name")); 9955ad82045Snd break; 9965ad82045Snd 9975ad82045Snd case NAME_ERR_TRAILING_SLASH: 9985ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9995ad82045Snd "trailing slash in name")); 10005ad82045Snd break; 10015ad82045Snd 1002edb901aaSMarcel Telka case NAME_ERR_MULTIPLE_DELIMITERS: 10035ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1004edb901aaSMarcel Telka "multiple '@' and/or '#' delimiters in " 1005edb901aaSMarcel Telka "name")); 10065ad82045Snd break; 10075ad82045Snd 100888f61deeSIgor Kozhukhov default: 100988f61deeSIgor Kozhukhov zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 101088f61deeSIgor Kozhukhov "(%d) not defined"), why); 101188f61deeSIgor Kozhukhov break; 1012fa9e4066Sahrens } 1013fa9e4066Sahrens } 101499653d4eSeschrock return (B_FALSE); 1015fa9e4066Sahrens } 1016fa9e4066Sahrens 101799653d4eSeschrock return (B_TRUE); 1018fa9e4066Sahrens } 1019fa9e4066Sahrens 1020fa9e4066Sahrens /* 1021fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 1022fa9e4066Sahrens * state. 1023fa9e4066Sahrens */ 1024fa9e4066Sahrens zpool_handle_t * 102599653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 1026fa9e4066Sahrens { 1027fa9e4066Sahrens zpool_handle_t *zhp; 102894de1d4cSeschrock boolean_t missing; 1029fa9e4066Sahrens 1030fa9e4066Sahrens /* 1031fa9e4066Sahrens * Make sure the pool name is valid. 1032fa9e4066Sahrens */ 103399653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 1034ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 103599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 103699653d4eSeschrock pool); 1037fa9e4066Sahrens return (NULL); 1038fa9e4066Sahrens } 1039fa9e4066Sahrens 104099653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 104199653d4eSeschrock return (NULL); 1042fa9e4066Sahrens 104399653d4eSeschrock zhp->zpool_hdl = hdl; 1044fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 1045fa9e4066Sahrens 104694de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 104794de1d4cSeschrock zpool_close(zhp); 104894de1d4cSeschrock return (NULL); 104994de1d4cSeschrock } 105094de1d4cSeschrock 105194de1d4cSeschrock if (missing) { 1052990b4856Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool")); 1053ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 1054990b4856Slling dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool); 105594de1d4cSeschrock zpool_close(zhp); 105694de1d4cSeschrock return (NULL); 1057fa9e4066Sahrens } 1058fa9e4066Sahrens 1059fa9e4066Sahrens return (zhp); 1060fa9e4066Sahrens } 1061fa9e4066Sahrens 1062fa9e4066Sahrens /* 1063fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 1064fa9e4066Sahrens * the configuration cache may be out of date). 1065fa9e4066Sahrens */ 106694de1d4cSeschrock int 106794de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 1068fa9e4066Sahrens { 1069fa9e4066Sahrens zpool_handle_t *zhp; 107094de1d4cSeschrock boolean_t missing; 1071fa9e4066Sahrens 107294de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 107394de1d4cSeschrock return (-1); 1074fa9e4066Sahrens 107599653d4eSeschrock zhp->zpool_hdl = hdl; 1076fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 1077fa9e4066Sahrens 107894de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 107994de1d4cSeschrock zpool_close(zhp); 108094de1d4cSeschrock return (-1); 1081fa9e4066Sahrens } 1082fa9e4066Sahrens 108394de1d4cSeschrock if (missing) { 108494de1d4cSeschrock zpool_close(zhp); 108594de1d4cSeschrock *ret = NULL; 108694de1d4cSeschrock return (0); 108794de1d4cSeschrock } 108894de1d4cSeschrock 108994de1d4cSeschrock *ret = zhp; 109094de1d4cSeschrock return (0); 1091fa9e4066Sahrens } 1092fa9e4066Sahrens 1093fa9e4066Sahrens /* 1094fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 1095fa9e4066Sahrens * state. 1096fa9e4066Sahrens */ 1097fa9e4066Sahrens zpool_handle_t * 109899653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 1099fa9e4066Sahrens { 1100fa9e4066Sahrens zpool_handle_t *zhp; 1101fa9e4066Sahrens 110299653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 1103fa9e4066Sahrens return (NULL); 1104fa9e4066Sahrens 1105fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 1106ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 110799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 1108fa9e4066Sahrens zpool_close(zhp); 1109fa9e4066Sahrens return (NULL); 1110fa9e4066Sahrens } 1111fa9e4066Sahrens 1112fa9e4066Sahrens return (zhp); 1113fa9e4066Sahrens } 1114fa9e4066Sahrens 1115fa9e4066Sahrens /* 1116fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 1117fa9e4066Sahrens */ 1118fa9e4066Sahrens void 1119fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 1120fa9e4066Sahrens { 1121aab83bb8SJosef 'Jeff' Sipek nvlist_free(zhp->zpool_config); 1122aab83bb8SJosef 'Jeff' Sipek nvlist_free(zhp->zpool_old_config); 1123aab83bb8SJosef 'Jeff' Sipek nvlist_free(zhp->zpool_props); 1124fa9e4066Sahrens free(zhp); 1125fa9e4066Sahrens } 1126fa9e4066Sahrens 1127fa9e4066Sahrens /* 1128fa9e4066Sahrens * Return the name of the pool. 1129fa9e4066Sahrens */ 1130fa9e4066Sahrens const char * 1131fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 1132fa9e4066Sahrens { 1133fa9e4066Sahrens return (zhp->zpool_name); 1134fa9e4066Sahrens } 1135fa9e4066Sahrens 1136fa9e4066Sahrens 1137fa9e4066Sahrens /* 1138fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 1139fa9e4066Sahrens */ 1140fa9e4066Sahrens int 1141fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 1142fa9e4066Sahrens { 1143fa9e4066Sahrens return (zhp->zpool_state); 1144fa9e4066Sahrens } 1145fa9e4066Sahrens 1146663207adSDon Brady /* 1147663207adSDon Brady * Check if vdev list contains a special vdev 1148663207adSDon Brady */ 1149663207adSDon Brady static boolean_t 1150663207adSDon Brady zpool_has_special_vdev(nvlist_t *nvroot) 1151663207adSDon Brady { 1152663207adSDon Brady nvlist_t **child; 1153663207adSDon Brady uint_t children; 1154663207adSDon Brady 1155663207adSDon Brady if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &child, 1156663207adSDon Brady &children) == 0) { 1157663207adSDon Brady for (uint_t c = 0; c < children; c++) { 1158663207adSDon Brady char *bias; 1159663207adSDon Brady 1160663207adSDon Brady if (nvlist_lookup_string(child[c], 1161663207adSDon Brady ZPOOL_CONFIG_ALLOCATION_BIAS, &bias) == 0 && 1162663207adSDon Brady strcmp(bias, VDEV_ALLOC_BIAS_SPECIAL) == 0) { 1163663207adSDon Brady return (B_TRUE); 1164663207adSDon Brady } 1165663207adSDon Brady } 1166663207adSDon Brady } 1167663207adSDon Brady return (B_FALSE); 1168663207adSDon Brady } 1169663207adSDon Brady 1170fa9e4066Sahrens /* 1171fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 1172fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 1173fa9e4066Sahrens * don't have to worry about error semantics. 1174fa9e4066Sahrens */ 1175fa9e4066Sahrens int 117699653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 11770a48a24eStimh nvlist_t *props, nvlist_t *fsprops) 1178fa9e4066Sahrens { 1179fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 11800a48a24eStimh nvlist_t *zc_fsprops = NULL; 11810a48a24eStimh nvlist_t *zc_props = NULL; 1182eb633035STom Caputi nvlist_t *hidden_args = NULL; 1183eb633035STom Caputi uint8_t *wkeydata = NULL; 1184eb633035STom Caputi uint_t wkeylen = 0; 118599653d4eSeschrock char msg[1024]; 11860a48a24eStimh int ret = -1; 1187fa9e4066Sahrens 118899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 118999653d4eSeschrock "cannot create '%s'"), pool); 1190fa9e4066Sahrens 119199653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 119299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 1193fa9e4066Sahrens 1194351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 1195990b4856Slling return (-1); 1196fa9e4066Sahrens 11970a48a24eStimh if (props) { 1198f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE }; 1199f9af39baSGeorge Wilson 12000a48a24eStimh if ((zc_props = zpool_valid_proplist(hdl, pool, props, 1201f9af39baSGeorge Wilson SPA_VERSION_1, flags, msg)) == NULL) { 12020a48a24eStimh goto create_failed; 12030a48a24eStimh } 12040a48a24eStimh } 120599653d4eSeschrock 12060a48a24eStimh if (fsprops) { 12070a48a24eStimh uint64_t zoned; 12080a48a24eStimh char *zonestr; 12090a48a24eStimh 12100a48a24eStimh zoned = ((nvlist_lookup_string(fsprops, 12110a48a24eStimh zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) && 12120a48a24eStimh strcmp(zonestr, "on") == 0); 12130a48a24eStimh 1214e9316f76SJoe Stein if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM, 1215eb633035STom Caputi fsprops, zoned, NULL, NULL, B_TRUE, msg)) == NULL) { 12160a48a24eStimh goto create_failed; 12170a48a24eStimh } 1218663207adSDon Brady 1219663207adSDon Brady if (nvlist_exists(zc_fsprops, 1220663207adSDon Brady zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS)) && 1221663207adSDon Brady !zpool_has_special_vdev(nvroot)) { 1222663207adSDon Brady zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1223663207adSDon Brady "%s property requires a special vdev"), 1224663207adSDon Brady zfs_prop_to_name(ZFS_PROP_SPECIAL_SMALL_BLOCKS)); 1225663207adSDon Brady (void) zfs_error(hdl, EZFS_BADPROP, msg); 1226663207adSDon Brady goto create_failed; 1227663207adSDon Brady } 1228663207adSDon Brady 12290a48a24eStimh if (!zc_props && 12300a48a24eStimh (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) { 12310a48a24eStimh goto create_failed; 12320a48a24eStimh } 12336ccda740Sloli if (zfs_crypto_create(hdl, NULL, zc_fsprops, props, B_TRUE, 1234eb633035STom Caputi &wkeydata, &wkeylen) != 0) { 1235eb633035STom Caputi (void) zfs_error(hdl, EZFS_CRYPTOFAILED, msg); 1236eb633035STom Caputi goto create_failed; 1237eb633035STom Caputi } 12380a48a24eStimh if (nvlist_add_nvlist(zc_props, 12390a48a24eStimh ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) { 12400a48a24eStimh goto create_failed; 12410a48a24eStimh } 1242eb633035STom Caputi if (wkeydata != NULL) { 1243eb633035STom Caputi if (nvlist_alloc(&hidden_args, NV_UNIQUE_NAME, 0) != 0) 1244eb633035STom Caputi goto create_failed; 1245eb633035STom Caputi 1246eb633035STom Caputi if (nvlist_add_uint8_array(hidden_args, "wkeydata", 1247eb633035STom Caputi wkeydata, wkeylen) != 0) 1248eb633035STom Caputi goto create_failed; 1249eb633035STom Caputi 1250eb633035STom Caputi if (nvlist_add_nvlist(zc_props, ZPOOL_HIDDEN_ARGS, 1251eb633035STom Caputi hidden_args) != 0) 1252eb633035STom Caputi goto create_failed; 1253eb633035STom Caputi } 1254351420b3Slling } 1255fa9e4066Sahrens 12560a48a24eStimh if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 12570a48a24eStimh goto create_failed; 12580a48a24eStimh 1259990b4856Slling (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 1260fa9e4066Sahrens 12610a48a24eStimh if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) { 1262351420b3Slling 1263e9dbad6fSeschrock zcmd_free_nvlists(&zc); 12640a48a24eStimh nvlist_free(zc_props); 12650a48a24eStimh nvlist_free(zc_fsprops); 1266eb633035STom Caputi nvlist_free(hidden_args); 1267eb633035STom Caputi if (wkeydata != NULL) 1268eb633035STom Caputi free(wkeydata); 1269fa9e4066Sahrens 127099653d4eSeschrock switch (errno) { 1271fa9e4066Sahrens case EBUSY: 1272fa9e4066Sahrens /* 1273fa9e4066Sahrens * This can happen if the user has specified the same 1274fa9e4066Sahrens * device multiple times. We can't reliably detect this 1275fa9e4066Sahrens * until we try to add it and see we already have a 1276fa9e4066Sahrens * label. 1277fa9e4066Sahrens */ 127899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 127999653d4eSeschrock "one or more vdevs refer to the same device")); 128099653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1281fa9e4066Sahrens 1282e9316f76SJoe Stein case ERANGE: 1283e9316f76SJoe Stein /* 1284e9316f76SJoe Stein * This happens if the record size is smaller or larger 1285e9316f76SJoe Stein * than the allowed size range, or not a power of 2. 1286e9316f76SJoe Stein * 1287e9316f76SJoe Stein * NOTE: although zfs_valid_proplist is called earlier, 1288e9316f76SJoe Stein * this case may have slipped through since the 1289e9316f76SJoe Stein * pool does not exist yet and it is therefore 1290e9316f76SJoe Stein * impossible to read properties e.g. max blocksize 1291e9316f76SJoe Stein * from the pool. 1292e9316f76SJoe Stein */ 1293e9316f76SJoe Stein zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1294e9316f76SJoe Stein "record size invalid")); 1295e9316f76SJoe Stein return (zfs_error(hdl, EZFS_BADPROP, msg)); 1296e9316f76SJoe Stein 1297fa9e4066Sahrens case EOVERFLOW: 1298fa9e4066Sahrens /* 129999653d4eSeschrock * This occurs when one of the devices is below 1300fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1301fa9e4066Sahrens * device was the problem device since there's no 1302fa9e4066Sahrens * reliable way to determine device size from userland. 1303fa9e4066Sahrens */ 1304fa9e4066Sahrens { 1305fa9e4066Sahrens char buf[64]; 1306fa9e4066Sahrens 1307fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1308fa9e4066Sahrens 130999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 131099653d4eSeschrock "one or more devices is less than the " 131199653d4eSeschrock "minimum size (%s)"), buf); 1312fa9e4066Sahrens } 131399653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1314fa9e4066Sahrens 1315fa9e4066Sahrens case ENOSPC: 131699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 131799653d4eSeschrock "one or more devices is out of space")); 131899653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 1319fa9e4066Sahrens 1320fa9e4066Sahrens default: 132199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1322fa9e4066Sahrens } 1323fa9e4066Sahrens } 1324fa9e4066Sahrens 13250a48a24eStimh create_failed: 1326351420b3Slling zcmd_free_nvlists(&zc); 13270a48a24eStimh nvlist_free(zc_props); 13280a48a24eStimh nvlist_free(zc_fsprops); 1329eb633035STom Caputi nvlist_free(hidden_args); 1330eb633035STom Caputi if (wkeydata != NULL) 1331eb633035STom Caputi free(wkeydata); 13320a48a24eStimh return (ret); 1333fa9e4066Sahrens } 1334fa9e4066Sahrens 1335fa9e4066Sahrens /* 1336fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 1337fa9e4066Sahrens * datasets left in the pool. 1338fa9e4066Sahrens */ 1339fa9e4066Sahrens int 13404445fffbSMatthew Ahrens zpool_destroy(zpool_handle_t *zhp, const char *log_str) 1341fa9e4066Sahrens { 1342fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1343fa9e4066Sahrens zfs_handle_t *zfp = NULL; 134499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 134599653d4eSeschrock char msg[1024]; 1346fa9e4066Sahrens 1347fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 1348cb04b873SMark J Musante (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL) 1349fa9e4066Sahrens return (-1); 1350fa9e4066Sahrens 1351fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 13524445fffbSMatthew Ahrens zc.zc_history = (uint64_t)(uintptr_t)log_str; 1353fa9e4066Sahrens 1354cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 135599653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 135699653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 1357fa9e4066Sahrens 135899653d4eSeschrock if (errno == EROFS) { 135999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 136099653d4eSeschrock "one or more devices is read only")); 136199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 136299653d4eSeschrock } else { 136399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1364fa9e4066Sahrens } 1365fa9e4066Sahrens 1366fa9e4066Sahrens if (zfp) 1367fa9e4066Sahrens zfs_close(zfp); 1368fa9e4066Sahrens return (-1); 1369fa9e4066Sahrens } 1370fa9e4066Sahrens 1371fa9e4066Sahrens if (zfp) { 1372fa9e4066Sahrens remove_mountpoint(zfp); 1373fa9e4066Sahrens zfs_close(zfp); 1374fa9e4066Sahrens } 1375fa9e4066Sahrens 1376fa9e4066Sahrens return (0); 1377fa9e4066Sahrens } 1378fa9e4066Sahrens 137986714001SSerapheim Dimitropoulos /* 138086714001SSerapheim Dimitropoulos * Create a checkpoint in the given pool. 138186714001SSerapheim Dimitropoulos */ 138286714001SSerapheim Dimitropoulos int 138386714001SSerapheim Dimitropoulos zpool_checkpoint(zpool_handle_t *zhp) 138486714001SSerapheim Dimitropoulos { 138586714001SSerapheim Dimitropoulos libzfs_handle_t *hdl = zhp->zpool_hdl; 138686714001SSerapheim Dimitropoulos char msg[1024]; 138786714001SSerapheim Dimitropoulos int error; 138886714001SSerapheim Dimitropoulos 138986714001SSerapheim Dimitropoulos error = lzc_pool_checkpoint(zhp->zpool_name); 139086714001SSerapheim Dimitropoulos if (error != 0) { 139186714001SSerapheim Dimitropoulos (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 139286714001SSerapheim Dimitropoulos "cannot checkpoint '%s'"), zhp->zpool_name); 139386714001SSerapheim Dimitropoulos (void) zpool_standard_error(hdl, error, msg); 139486714001SSerapheim Dimitropoulos return (-1); 139586714001SSerapheim Dimitropoulos } 139686714001SSerapheim Dimitropoulos 139786714001SSerapheim Dimitropoulos return (0); 139886714001SSerapheim Dimitropoulos } 139986714001SSerapheim Dimitropoulos 140086714001SSerapheim Dimitropoulos /* 140186714001SSerapheim Dimitropoulos * Discard the checkpoint from the given pool. 140286714001SSerapheim Dimitropoulos */ 140386714001SSerapheim Dimitropoulos int 140486714001SSerapheim Dimitropoulos zpool_discard_checkpoint(zpool_handle_t *zhp) 140586714001SSerapheim Dimitropoulos { 140686714001SSerapheim Dimitropoulos libzfs_handle_t *hdl = zhp->zpool_hdl; 140786714001SSerapheim Dimitropoulos char msg[1024]; 140886714001SSerapheim Dimitropoulos int error; 140986714001SSerapheim Dimitropoulos 141086714001SSerapheim Dimitropoulos error = lzc_pool_checkpoint_discard(zhp->zpool_name); 141186714001SSerapheim Dimitropoulos if (error != 0) { 141286714001SSerapheim Dimitropoulos (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 141386714001SSerapheim Dimitropoulos "cannot discard checkpoint in '%s'"), zhp->zpool_name); 141486714001SSerapheim Dimitropoulos (void) zpool_standard_error(hdl, error, msg); 141586714001SSerapheim Dimitropoulos return (-1); 141686714001SSerapheim Dimitropoulos } 141786714001SSerapheim Dimitropoulos 141886714001SSerapheim Dimitropoulos return (0); 141986714001SSerapheim Dimitropoulos } 142086714001SSerapheim Dimitropoulos 1421fa9e4066Sahrens /* 1422fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 1423fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 1424fa9e4066Sahrens */ 1425fa9e4066Sahrens int 1426fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 1427fa9e4066Sahrens { 1428e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 142999653d4eSeschrock int ret; 143099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 143199653d4eSeschrock char msg[1024]; 1432fa94a07fSbrendan nvlist_t **spares, **l2cache; 1433fa94a07fSbrendan uint_t nspares, nl2cache; 143499653d4eSeschrock 143599653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 143699653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 143799653d4eSeschrock 1438fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1439fa94a07fSbrendan SPA_VERSION_SPARES && 144099653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 144199653d4eSeschrock &spares, &nspares) == 0) { 144299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 144399653d4eSeschrock "upgraded to add hot spares")); 144499653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 144599653d4eSeschrock } 1446fa9e4066Sahrens 1447fa94a07fSbrendan if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < 1448fa94a07fSbrendan SPA_VERSION_L2CACHE && 1449fa94a07fSbrendan nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1450fa94a07fSbrendan &l2cache, &nl2cache) == 0) { 1451fa94a07fSbrendan zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 1452fa94a07fSbrendan "upgraded to add cache devices")); 1453fa94a07fSbrendan return (zfs_error(hdl, EZFS_BADVERSION, msg)); 1454fa94a07fSbrendan } 1455fa94a07fSbrendan 1456990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 145799653d4eSeschrock return (-1); 1458fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1459fa9e4066Sahrens 1460cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 1461fa9e4066Sahrens switch (errno) { 1462fa9e4066Sahrens case EBUSY: 1463fa9e4066Sahrens /* 1464fa9e4066Sahrens * This can happen if the user has specified the same 1465fa9e4066Sahrens * device multiple times. We can't reliably detect this 1466fa9e4066Sahrens * until we try to add it and see we already have a 1467fa9e4066Sahrens * label. 1468fa9e4066Sahrens */ 146999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 147099653d4eSeschrock "one or more vdevs refer to the same device")); 147199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1472fa9e4066Sahrens break; 1473fa9e4066Sahrens 14745cabbc6bSPrashanth Sreenivasa case EINVAL: 14755cabbc6bSPrashanth Sreenivasa zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 14765cabbc6bSPrashanth Sreenivasa "invalid config; a pool with removing/removed " 14775cabbc6bSPrashanth Sreenivasa "vdevs does not support adding raidz vdevs")); 14785cabbc6bSPrashanth Sreenivasa (void) zfs_error(hdl, EZFS_BADDEV, msg); 14795cabbc6bSPrashanth Sreenivasa break; 14805cabbc6bSPrashanth Sreenivasa 1481fa9e4066Sahrens case EOVERFLOW: 1482fa9e4066Sahrens /* 1483fa9e4066Sahrens * This occurrs when one of the devices is below 1484fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 1485fa9e4066Sahrens * device was the problem device since there's no 1486fa9e4066Sahrens * reliable way to determine device size from userland. 1487fa9e4066Sahrens */ 1488fa9e4066Sahrens { 1489fa9e4066Sahrens char buf[64]; 1490fa9e4066Sahrens 1491fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 1492fa9e4066Sahrens 149399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 149499653d4eSeschrock "device is less than the minimum " 149599653d4eSeschrock "size (%s)"), buf); 1496fa9e4066Sahrens } 149799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 149899653d4eSeschrock break; 149999653d4eSeschrock 150099653d4eSeschrock case ENOTSUP: 150199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 15028654d025Sperrin "pool must be upgraded to add these vdevs")); 150399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 1504fa9e4066Sahrens break; 1505fa9e4066Sahrens 1506b1b8ab34Slling case EDOM: 1507b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 15088654d025Sperrin "root pool can not have multiple vdevs" 15098654d025Sperrin " or separate logs")); 1510b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 1511b1b8ab34Slling break; 1512b1b8ab34Slling 1513fa9e4066Sahrens default: 151499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1515fa9e4066Sahrens } 1516fa9e4066Sahrens 151799653d4eSeschrock ret = -1; 151899653d4eSeschrock } else { 151999653d4eSeschrock ret = 0; 1520fa9e4066Sahrens } 1521fa9e4066Sahrens 1522e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1523fa9e4066Sahrens 152499653d4eSeschrock return (ret); 1525fa9e4066Sahrens } 1526fa9e4066Sahrens 1527fa9e4066Sahrens /* 1528fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 1529fa9e4066Sahrens * mounted datasets in the pool. 1530fa9e4066Sahrens */ 15314445fffbSMatthew Ahrens static int 15324445fffbSMatthew Ahrens zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce, 15334445fffbSMatthew Ahrens const char *log_str) 1534fa9e4066Sahrens { 1535fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 153689a89ebfSlling char msg[1024]; 1537fa9e4066Sahrens 153889a89ebfSlling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 153989a89ebfSlling "cannot export '%s'"), zhp->zpool_name); 154089a89ebfSlling 1541fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 154289a89ebfSlling zc.zc_cookie = force; 1543394ab0cbSGeorge Wilson zc.zc_guid = hardforce; 15444445fffbSMatthew Ahrens zc.zc_history = (uint64_t)(uintptr_t)log_str; 154589a89ebfSlling 154689a89ebfSlling if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) { 154789a89ebfSlling switch (errno) { 154889a89ebfSlling case EXDEV: 154989a89ebfSlling zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, 155089a89ebfSlling "use '-f' to override the following errors:\n" 155189a89ebfSlling "'%s' has an active shared spare which could be" 155289a89ebfSlling " used by other pools once '%s' is exported."), 155389a89ebfSlling zhp->zpool_name, zhp->zpool_name); 155489a89ebfSlling return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE, 155589a89ebfSlling msg)); 155689a89ebfSlling default: 155789a89ebfSlling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 155889a89ebfSlling msg)); 155989a89ebfSlling } 156089a89ebfSlling } 1561fa9e4066Sahrens 1562fa9e4066Sahrens return (0); 1563fa9e4066Sahrens } 1564fa9e4066Sahrens 1565394ab0cbSGeorge Wilson int 15664445fffbSMatthew Ahrens zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str) 1567394ab0cbSGeorge Wilson { 15684445fffbSMatthew Ahrens return (zpool_export_common(zhp, force, B_FALSE, log_str)); 1569394ab0cbSGeorge Wilson } 1570394ab0cbSGeorge Wilson 1571394ab0cbSGeorge Wilson int 15724445fffbSMatthew Ahrens zpool_export_force(zpool_handle_t *zhp, const char *log_str) 1573394ab0cbSGeorge Wilson { 15744445fffbSMatthew Ahrens return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str)); 1575394ab0cbSGeorge Wilson } 1576394ab0cbSGeorge Wilson 1577468c413aSTim Haley static void 1578468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, 15794b964adaSGeorge Wilson nvlist_t *config) 1580468c413aSTim Haley { 15814b964adaSGeorge Wilson nvlist_t *nv = NULL; 1582468c413aSTim Haley uint64_t rewindto; 1583468c413aSTim Haley int64_t loss = -1; 1584468c413aSTim Haley struct tm t; 1585468c413aSTim Haley char timestr[128]; 1586468c413aSTim Haley 15874b964adaSGeorge Wilson if (!hdl->libzfs_printerr || config == NULL) 15884b964adaSGeorge Wilson return; 15894b964adaSGeorge Wilson 1590ad135b5dSChristopher Siden if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || 1591ad135b5dSChristopher Siden nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) { 1592468c413aSTim Haley return; 1593ad135b5dSChristopher Siden } 1594468c413aSTim Haley 15954b964adaSGeorge Wilson if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1596468c413aSTim Haley return; 15974b964adaSGeorge Wilson (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 1598468c413aSTim Haley 1599468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1600468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1601468c413aSTim Haley if (dryrun) { 1602468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1603468c413aSTim Haley "Would be able to return %s " 1604468c413aSTim Haley "to its state as of %s.\n"), 1605468c413aSTim Haley name, timestr); 1606468c413aSTim Haley } else { 1607468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1608468c413aSTim Haley "Pool %s returned to its state as of %s.\n"), 1609468c413aSTim Haley name, timestr); 1610468c413aSTim Haley } 1611468c413aSTim Haley if (loss > 120) { 1612468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1613468c413aSTim Haley "%s approximately %lld "), 1614468c413aSTim Haley dryrun ? "Would discard" : "Discarded", 1615468c413aSTim Haley (loss + 30) / 60); 1616468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1617468c413aSTim Haley "minutes of transactions.\n")); 1618468c413aSTim Haley } else if (loss > 0) { 1619468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1620468c413aSTim Haley "%s approximately %lld "), 1621468c413aSTim Haley dryrun ? "Would discard" : "Discarded", loss); 1622468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1623468c413aSTim Haley "seconds of transactions.\n")); 1624468c413aSTim Haley } 1625468c413aSTim Haley } 1626468c413aSTim Haley } 1627468c413aSTim Haley 1628468c413aSTim Haley void 1629468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 1630468c413aSTim Haley nvlist_t *config) 1631468c413aSTim Haley { 16324b964adaSGeorge Wilson nvlist_t *nv = NULL; 1633468c413aSTim Haley int64_t loss = -1; 1634468c413aSTim Haley uint64_t edata = UINT64_MAX; 1635468c413aSTim Haley uint64_t rewindto; 1636468c413aSTim Haley struct tm t; 1637468c413aSTim Haley char timestr[128]; 1638468c413aSTim Haley 1639468c413aSTim Haley if (!hdl->libzfs_printerr) 1640468c413aSTim Haley return; 1641468c413aSTim Haley 1642468c413aSTim Haley if (reason >= 0) 1643468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "action: ")); 1644468c413aSTim Haley else 1645468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, "\t")); 1646468c413aSTim Haley 1647468c413aSTim Haley /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ 16484b964adaSGeorge Wilson if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || 1649ad135b5dSChristopher Siden nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 || 16504b964adaSGeorge Wilson nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) 1651468c413aSTim Haley goto no_info; 1652468c413aSTim Haley 16534b964adaSGeorge Wilson (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss); 16544b964adaSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS, 1655468c413aSTim Haley &edata); 1656468c413aSTim Haley 1657468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1658468c413aSTim Haley "Recovery is possible, but will result in some data loss.\n")); 1659468c413aSTim Haley 1660468c413aSTim Haley if (localtime_r((time_t *)&rewindto, &t) != NULL && 1661468c413aSTim Haley strftime(timestr, 128, 0, &t) != 0) { 1662468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1663468c413aSTim Haley "\tReturning the pool to its state as of %s\n" 1664468c413aSTim Haley "\tshould correct the problem. "), 1665468c413aSTim Haley timestr); 1666468c413aSTim Haley } else { 1667468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1668468c413aSTim Haley "\tReverting the pool to an earlier state " 1669468c413aSTim Haley "should correct the problem.\n\t")); 1670468c413aSTim Haley } 1671468c413aSTim Haley 1672468c413aSTim Haley if (loss > 120) { 1673468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1674468c413aSTim Haley "Approximately %lld minutes of data\n" 1675468c413aSTim Haley "\tmust be discarded, irreversibly. "), (loss + 30) / 60); 1676468c413aSTim Haley } else if (loss > 0) { 1677468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1678468c413aSTim Haley "Approximately %lld seconds of data\n" 1679468c413aSTim Haley "\tmust be discarded, irreversibly. "), loss); 1680468c413aSTim Haley } 1681468c413aSTim Haley if (edata != 0 && edata != UINT64_MAX) { 1682468c413aSTim Haley if (edata == 1) { 1683468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1684468c413aSTim Haley "After rewind, at least\n" 1685468c413aSTim Haley "\tone persistent user-data error will remain. ")); 1686468c413aSTim Haley } else { 1687468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1688468c413aSTim Haley "After rewind, several\n" 1689468c413aSTim Haley "\tpersistent user-data errors will remain. ")); 1690468c413aSTim Haley } 1691468c413aSTim Haley } 1692468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1693a33cae98STim Haley "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "), 1694a33cae98STim Haley reason >= 0 ? "clear" : "import", name); 1695468c413aSTim Haley 1696468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1697468c413aSTim Haley "A scrub of the pool\n" 1698468c413aSTim Haley "\tis strongly recommended after recovery.\n")); 1699468c413aSTim Haley return; 1700468c413aSTim Haley 1701468c413aSTim Haley no_info: 1702468c413aSTim Haley (void) printf(dgettext(TEXT_DOMAIN, 1703468c413aSTim Haley "Destroy and re-create the pool from\n\ta backup source.\n")); 1704468c413aSTim Haley } 1705468c413aSTim Haley 1706fa9e4066Sahrens /* 1707990b4856Slling * zpool_import() is a contracted interface. Should be kept the same 1708990b4856Slling * if possible. 1709990b4856Slling * 1710990b4856Slling * Applications should use zpool_import_props() to import a pool with 1711990b4856Slling * new properties value to be set. 1712fa9e4066Sahrens */ 1713fa9e4066Sahrens int 171499653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 1715990b4856Slling char *altroot) 1716990b4856Slling { 1717990b4856Slling nvlist_t *props = NULL; 1718990b4856Slling int ret; 1719990b4856Slling 1720990b4856Slling if (altroot != NULL) { 1721990b4856Slling if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 1722990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1723990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1724990b4856Slling newname)); 1725990b4856Slling } 1726990b4856Slling 1727990b4856Slling if (nvlist_add_string(props, 1728352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 || 1729352d8027SGeorge Wilson nvlist_add_string(props, 1730352d8027SGeorge Wilson zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) { 1731990b4856Slling nvlist_free(props); 1732990b4856Slling return (zfs_error_fmt(hdl, EZFS_NOMEM, 1733990b4856Slling dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1734990b4856Slling newname)); 1735990b4856Slling } 1736990b4856Slling } 1737990b4856Slling 17384b964adaSGeorge Wilson ret = zpool_import_props(hdl, config, newname, props, 17394b964adaSGeorge Wilson ZFS_IMPORT_NORMAL); 1740aab83bb8SJosef 'Jeff' Sipek nvlist_free(props); 1741990b4856Slling return (ret); 1742990b4856Slling } 1743990b4856Slling 17444b964adaSGeorge Wilson static void 17454b964adaSGeorge Wilson print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv, 17464b964adaSGeorge Wilson int indent) 17474b964adaSGeorge Wilson { 17484b964adaSGeorge Wilson nvlist_t **child; 17494b964adaSGeorge Wilson uint_t c, children; 17504b964adaSGeorge Wilson char *vname; 17514b964adaSGeorge Wilson uint64_t is_log = 0; 17524b964adaSGeorge Wilson 17534b964adaSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, 17544b964adaSGeorge Wilson &is_log); 17554b964adaSGeorge Wilson 17564b964adaSGeorge Wilson if (name != NULL) 17574b964adaSGeorge Wilson (void) printf("\t%*s%s%s\n", indent, "", name, 17584b964adaSGeorge Wilson is_log ? " [log]" : ""); 17594b964adaSGeorge Wilson 17604b964adaSGeorge Wilson if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 17614b964adaSGeorge Wilson &child, &children) != 0) 17624b964adaSGeorge Wilson return; 17634b964adaSGeorge Wilson 17644b964adaSGeorge Wilson for (c = 0; c < children; c++) { 1765663207adSDon Brady vname = zpool_vdev_name(hdl, NULL, child[c], VDEV_NAME_TYPE_ID); 17664b964adaSGeorge Wilson print_vdev_tree(hdl, vname, child[c], indent + 2); 17674b964adaSGeorge Wilson free(vname); 17684b964adaSGeorge Wilson } 17694b964adaSGeorge Wilson } 17704b964adaSGeorge Wilson 1771ad135b5dSChristopher Siden void 1772ad135b5dSChristopher Siden zpool_print_unsup_feat(nvlist_t *config) 1773ad135b5dSChristopher Siden { 1774ad135b5dSChristopher Siden nvlist_t *nvinfo, *unsup_feat; 1775ad135b5dSChristopher Siden 1776ad135b5dSChristopher Siden verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 1777ad135b5dSChristopher Siden 0); 1778ad135b5dSChristopher Siden verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT, 1779ad135b5dSChristopher Siden &unsup_feat) == 0); 1780ad135b5dSChristopher Siden 1781ad135b5dSChristopher Siden for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL; 1782ad135b5dSChristopher Siden nvp = nvlist_next_nvpair(unsup_feat, nvp)) { 1783ad135b5dSChristopher Siden char *desc; 1784ad135b5dSChristopher Siden 1785ad135b5dSChristopher Siden verify(nvpair_type(nvp) == DATA_TYPE_STRING); 1786ad135b5dSChristopher Siden verify(nvpair_value_string(nvp, &desc) == 0); 1787ad135b5dSChristopher Siden 1788ad135b5dSChristopher Siden if (strlen(desc) > 0) 1789ad135b5dSChristopher Siden (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc); 1790ad135b5dSChristopher Siden else 1791ad135b5dSChristopher Siden (void) printf("\t%s\n", nvpair_name(nvp)); 1792ad135b5dSChristopher Siden } 1793ad135b5dSChristopher Siden } 1794ad135b5dSChristopher Siden 1795990b4856Slling /* 1796990b4856Slling * Import the given pool using the known configuration and a list of 1797990b4856Slling * properties to be set. The configuration should have come from 1798990b4856Slling * zpool_find_import(). The 'newname' parameters control whether the pool 1799990b4856Slling * is imported with a different name. 1800990b4856Slling */ 1801990b4856Slling int 1802990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 18034b964adaSGeorge Wilson nvlist_t *props, int flags) 1804fa9e4066Sahrens { 1805e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 18065dafeea3SPavel Zakharov zpool_load_policy_t policy; 18074b964adaSGeorge Wilson nvlist_t *nv = NULL; 18084b964adaSGeorge Wilson nvlist_t *nvinfo = NULL; 18094b964adaSGeorge Wilson nvlist_t *missing = NULL; 1810fa9e4066Sahrens char *thename; 1811fa9e4066Sahrens char *origname; 1812fa9e4066Sahrens int ret; 18134b964adaSGeorge Wilson int error = 0; 1814990b4856Slling char errbuf[1024]; 1815fa9e4066Sahrens 1816fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1817fa9e4066Sahrens &origname) == 0); 1818fa9e4066Sahrens 1819990b4856Slling (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1820990b4856Slling "cannot import pool '%s'"), origname); 1821990b4856Slling 1822fa9e4066Sahrens if (newname != NULL) { 182399653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 1824ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 182599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 182699653d4eSeschrock newname)); 1827fa9e4066Sahrens thename = (char *)newname; 1828fa9e4066Sahrens } else { 1829fa9e4066Sahrens thename = origname; 1830fa9e4066Sahrens } 1831fa9e4066Sahrens 1832078266a5SMarcel Telka if (props != NULL) { 1833990b4856Slling uint64_t version; 1834f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 1835fa9e4066Sahrens 1836990b4856Slling verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 1837990b4856Slling &version) == 0); 1838fa9e4066Sahrens 18390a48a24eStimh if ((props = zpool_valid_proplist(hdl, origname, 1840078266a5SMarcel Telka props, version, flags, errbuf)) == NULL) 1841990b4856Slling return (-1); 1842078266a5SMarcel Telka if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 1843351420b3Slling nvlist_free(props); 1844990b4856Slling return (-1); 1845351420b3Slling } 1846078266a5SMarcel Telka nvlist_free(props); 1847990b4856Slling } 1848990b4856Slling 1849990b4856Slling (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 1850fa9e4066Sahrens 1851fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1852ea8dc4b6Seschrock &zc.zc_guid) == 0); 1853fa9e4066Sahrens 1854351420b3Slling if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) { 1855078266a5SMarcel Telka zcmd_free_nvlists(&zc); 185699653d4eSeschrock return (-1); 1857351420b3Slling } 185857f304caSGeorge Wilson if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) { 1859078266a5SMarcel Telka zcmd_free_nvlists(&zc); 1860468c413aSTim Haley return (-1); 1861468c413aSTim Haley } 1862fa9e4066Sahrens 18634b964adaSGeorge Wilson zc.zc_cookie = flags; 18644b964adaSGeorge Wilson while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 && 18654b964adaSGeorge Wilson errno == ENOMEM) { 18664b964adaSGeorge Wilson if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 18674b964adaSGeorge Wilson zcmd_free_nvlists(&zc); 18684b964adaSGeorge Wilson return (-1); 18694b964adaSGeorge Wilson } 18704b964adaSGeorge Wilson } 18714b964adaSGeorge Wilson if (ret != 0) 18724b964adaSGeorge Wilson error = errno; 18734b964adaSGeorge Wilson 18744b964adaSGeorge Wilson (void) zcmd_read_dst_nvlist(hdl, &zc, &nv); 1875078266a5SMarcel Telka 1876078266a5SMarcel Telka zcmd_free_nvlists(&zc); 1877078266a5SMarcel Telka 18785dafeea3SPavel Zakharov zpool_get_load_policy(config, &policy); 18794b964adaSGeorge Wilson 18804b964adaSGeorge Wilson if (error) { 1881fa9e4066Sahrens char desc[1024]; 1882e0f1c0afSOlaf Faaland char aux[256]; 1883468c413aSTim Haley 1884468c413aSTim Haley /* 1885468c413aSTim Haley * Dry-run failed, but we print out what success 1886468c413aSTim Haley * looks like if we found a best txg 1887468c413aSTim Haley */ 18885dafeea3SPavel Zakharov if (policy.zlp_rewind & ZPOOL_TRY_REWIND) { 1889468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 18904b964adaSGeorge Wilson B_TRUE, nv); 18914b964adaSGeorge Wilson nvlist_free(nv); 1892468c413aSTim Haley return (-1); 1893468c413aSTim Haley } 1894468c413aSTim Haley 1895fa9e4066Sahrens if (newname == NULL) 1896fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1897fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 1898fa9e4066Sahrens thename); 1899fa9e4066Sahrens else 1900fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 1901fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 1902fa9e4066Sahrens origname, thename); 1903fa9e4066Sahrens 19044b964adaSGeorge Wilson switch (error) { 1905ea8dc4b6Seschrock case ENOTSUP: 1906ad135b5dSChristopher Siden if (nv != NULL && nvlist_lookup_nvlist(nv, 1907ad135b5dSChristopher Siden ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && 1908ad135b5dSChristopher Siden nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) { 1909ad135b5dSChristopher Siden (void) printf(dgettext(TEXT_DOMAIN, "This " 1910ad135b5dSChristopher Siden "pool uses the following feature(s) not " 1911ad135b5dSChristopher Siden "supported by this system:\n")); 1912ad135b5dSChristopher Siden zpool_print_unsup_feat(nv); 1913ad135b5dSChristopher Siden if (nvlist_exists(nvinfo, 1914ad135b5dSChristopher Siden ZPOOL_CONFIG_CAN_RDONLY)) { 1915ad135b5dSChristopher Siden (void) printf(dgettext(TEXT_DOMAIN, 1916ad135b5dSChristopher Siden "All unsupported features are only " 1917ad135b5dSChristopher Siden "required for writing to the pool." 1918ad135b5dSChristopher Siden "\nThe pool can be imported using " 1919ad135b5dSChristopher Siden "'-o readonly=on'.\n")); 1920ad135b5dSChristopher Siden } 1921ad135b5dSChristopher Siden } 1922ea8dc4b6Seschrock /* 1923ea8dc4b6Seschrock * Unsupported version. 1924ea8dc4b6Seschrock */ 192599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 1926ea8dc4b6Seschrock break; 1927ea8dc4b6Seschrock 1928e0f1c0afSOlaf Faaland case EREMOTEIO: 1929e0f1c0afSOlaf Faaland if (nv != NULL && nvlist_lookup_nvlist(nv, 1930e0f1c0afSOlaf Faaland ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) { 1931e0f1c0afSOlaf Faaland char *hostname = "<unknown>"; 1932e0f1c0afSOlaf Faaland uint64_t hostid = 0; 1933e0f1c0afSOlaf Faaland mmp_state_t mmp_state; 1934e0f1c0afSOlaf Faaland 1935e0f1c0afSOlaf Faaland mmp_state = fnvlist_lookup_uint64(nvinfo, 1936e0f1c0afSOlaf Faaland ZPOOL_CONFIG_MMP_STATE); 1937e0f1c0afSOlaf Faaland 1938e0f1c0afSOlaf Faaland if (nvlist_exists(nvinfo, 1939e0f1c0afSOlaf Faaland ZPOOL_CONFIG_MMP_HOSTNAME)) 1940e0f1c0afSOlaf Faaland hostname = fnvlist_lookup_string(nvinfo, 1941e0f1c0afSOlaf Faaland ZPOOL_CONFIG_MMP_HOSTNAME); 1942e0f1c0afSOlaf Faaland 1943e0f1c0afSOlaf Faaland if (nvlist_exists(nvinfo, 1944e0f1c0afSOlaf Faaland ZPOOL_CONFIG_MMP_HOSTID)) 1945e0f1c0afSOlaf Faaland hostid = fnvlist_lookup_uint64(nvinfo, 1946e0f1c0afSOlaf Faaland ZPOOL_CONFIG_MMP_HOSTID); 1947e0f1c0afSOlaf Faaland 1948e0f1c0afSOlaf Faaland if (mmp_state == MMP_STATE_ACTIVE) { 1949e0f1c0afSOlaf Faaland (void) snprintf(aux, sizeof (aux), 1950e0f1c0afSOlaf Faaland dgettext(TEXT_DOMAIN, "pool is imp" 1951e0f1c0afSOlaf Faaland "orted on host '%s' (hostid=%lx).\n" 1952e0f1c0afSOlaf Faaland "Export the pool on the other " 1953e0f1c0afSOlaf Faaland "system, then run 'zpool import'."), 1954e0f1c0afSOlaf Faaland hostname, (unsigned long) hostid); 1955e0f1c0afSOlaf Faaland } else if (mmp_state == MMP_STATE_NO_HOSTID) { 1956e0f1c0afSOlaf Faaland (void) snprintf(aux, sizeof (aux), 1957e0f1c0afSOlaf Faaland dgettext(TEXT_DOMAIN, "pool has " 1958e0f1c0afSOlaf Faaland "the multihost property on and " 1959e0f1c0afSOlaf Faaland "the\nsystem's hostid is not " 1960e0f1c0afSOlaf Faaland "set.\n")); 1961e0f1c0afSOlaf Faaland } 1962e0f1c0afSOlaf Faaland 1963e0f1c0afSOlaf Faaland (void) zfs_error_aux(hdl, aux); 1964e0f1c0afSOlaf Faaland } 1965e0f1c0afSOlaf Faaland (void) zfs_error(hdl, EZFS_ACTIVE_POOL, desc); 1966e0f1c0afSOlaf Faaland break; 1967e0f1c0afSOlaf Faaland 1968b5989ec7Seschrock case EINVAL: 1969b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 1970b5989ec7Seschrock break; 1971b5989ec7Seschrock 197254a91118SChris Kirby case EROFS: 197354a91118SChris Kirby zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 197454a91118SChris Kirby "one or more devices is read only")); 197554a91118SChris Kirby (void) zfs_error(hdl, EZFS_BADDEV, desc); 197654a91118SChris Kirby break; 197754a91118SChris Kirby 19784b964adaSGeorge Wilson case ENXIO: 19794b964adaSGeorge Wilson if (nv && nvlist_lookup_nvlist(nv, 19804b964adaSGeorge Wilson ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && 19814b964adaSGeorge Wilson nvlist_lookup_nvlist(nvinfo, 19824b964adaSGeorge Wilson ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) { 19834b964adaSGeorge Wilson (void) printf(dgettext(TEXT_DOMAIN, 19846f793812SPavel Zakharov "The devices below are missing or " 19856f793812SPavel Zakharov "corrupted, use '-m' to import the pool " 19866f793812SPavel Zakharov "anyway:\n")); 19874b964adaSGeorge Wilson print_vdev_tree(hdl, NULL, missing, 2); 19884b964adaSGeorge Wilson (void) printf("\n"); 19894b964adaSGeorge Wilson } 19904b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 19914b964adaSGeorge Wilson break; 19924b964adaSGeorge Wilson 19934b964adaSGeorge Wilson case EEXIST: 19944b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 19954b964adaSGeorge Wilson break; 1996c971037bSPaul Dagnelie case ENAMETOOLONG: 1997c971037bSPaul Dagnelie zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1998c971037bSPaul Dagnelie "new name of at least one dataset is longer than " 1999c971037bSPaul Dagnelie "the maximum allowable length")); 2000c971037bSPaul Dagnelie (void) zfs_error(hdl, EZFS_NAMETOOLONG, desc); 2001c971037bSPaul Dagnelie break; 2002fa9e4066Sahrens default: 20034b964adaSGeorge Wilson (void) zpool_standard_error(hdl, error, desc); 2004468c413aSTim Haley zpool_explain_recover(hdl, 20054b964adaSGeorge Wilson newname ? origname : thename, -error, nv); 2006468c413aSTim Haley break; 2007fa9e4066Sahrens } 2008fa9e4066Sahrens 20094b964adaSGeorge Wilson nvlist_free(nv); 2010fa9e4066Sahrens ret = -1; 2011fa9e4066Sahrens } else { 2012fa9e4066Sahrens zpool_handle_t *zhp; 2013ecd6cf80Smarks 2014fa9e4066Sahrens /* 2015fa9e4066Sahrens * This should never fail, but play it safe anyway. 2016fa9e4066Sahrens */ 2017681d9761SEric Taylor if (zpool_open_silent(hdl, thename, &zhp) != 0) 201894de1d4cSeschrock ret = -1; 2019681d9761SEric Taylor else if (zhp != NULL) 2020fa9e4066Sahrens zpool_close(zhp); 20215dafeea3SPavel Zakharov if (policy.zlp_rewind & 2022468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 2023468c413aSTim Haley zpool_rewind_exclaim(hdl, newname ? origname : thename, 20245dafeea3SPavel Zakharov ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0), nv); 2025468c413aSTim Haley } 20264b964adaSGeorge Wilson nvlist_free(nv); 2027468c413aSTim Haley return (0); 2028fa9e4066Sahrens } 2029fa9e4066Sahrens 2030fa9e4066Sahrens return (ret); 2031fa9e4066Sahrens } 2032fa9e4066Sahrens 2033084fd14fSBrian Behlendorf /* 2034084fd14fSBrian Behlendorf * Translate vdev names to guids. If a vdev_path is determined to be 2035084fd14fSBrian Behlendorf * unsuitable then a vd_errlist is allocated and the vdev path and errno 2036084fd14fSBrian Behlendorf * are added to it. 2037084fd14fSBrian Behlendorf */ 2038084fd14fSBrian Behlendorf static int 2039084fd14fSBrian Behlendorf zpool_translate_vdev_guids(zpool_handle_t *zhp, nvlist_t *vds, 2040084fd14fSBrian Behlendorf nvlist_t *vdev_guids, nvlist_t *guids_to_paths, nvlist_t **vd_errlist) 2041084fd14fSBrian Behlendorf { 2042084fd14fSBrian Behlendorf nvlist_t *errlist = NULL; 2043084fd14fSBrian Behlendorf int error = 0; 2044084fd14fSBrian Behlendorf 2045084fd14fSBrian Behlendorf for (nvpair_t *elem = nvlist_next_nvpair(vds, NULL); elem != NULL; 2046084fd14fSBrian Behlendorf elem = nvlist_next_nvpair(vds, elem)) { 2047084fd14fSBrian Behlendorf boolean_t spare, cache; 2048084fd14fSBrian Behlendorf 2049084fd14fSBrian Behlendorf char *vd_path = nvpair_name(elem); 2050084fd14fSBrian Behlendorf nvlist_t *tgt = zpool_find_vdev(zhp, vd_path, &spare, &cache, 2051084fd14fSBrian Behlendorf NULL); 2052084fd14fSBrian Behlendorf 2053084fd14fSBrian Behlendorf if ((tgt == NULL) || cache || spare) { 2054084fd14fSBrian Behlendorf if (errlist == NULL) { 2055084fd14fSBrian Behlendorf errlist = fnvlist_alloc(); 2056084fd14fSBrian Behlendorf error = EINVAL; 2057084fd14fSBrian Behlendorf } 2058084fd14fSBrian Behlendorf 2059084fd14fSBrian Behlendorf uint64_t err = (tgt == NULL) ? EZFS_NODEVICE : 2060084fd14fSBrian Behlendorf (spare ? EZFS_ISSPARE : EZFS_ISL2CACHE); 2061084fd14fSBrian Behlendorf fnvlist_add_int64(errlist, vd_path, err); 2062084fd14fSBrian Behlendorf continue; 2063084fd14fSBrian Behlendorf } 2064084fd14fSBrian Behlendorf 2065084fd14fSBrian Behlendorf uint64_t guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID); 2066084fd14fSBrian Behlendorf fnvlist_add_uint64(vdev_guids, vd_path, guid); 2067084fd14fSBrian Behlendorf 2068084fd14fSBrian Behlendorf char msg[MAXNAMELEN]; 2069084fd14fSBrian Behlendorf (void) snprintf(msg, sizeof (msg), "%llu", (u_longlong_t)guid); 2070084fd14fSBrian Behlendorf fnvlist_add_string(guids_to_paths, msg, vd_path); 2071084fd14fSBrian Behlendorf } 2072084fd14fSBrian Behlendorf 2073084fd14fSBrian Behlendorf if (error != 0) { 2074084fd14fSBrian Behlendorf verify(errlist != NULL); 2075084fd14fSBrian Behlendorf if (vd_errlist != NULL) 2076084fd14fSBrian Behlendorf *vd_errlist = errlist; 2077084fd14fSBrian Behlendorf else 2078084fd14fSBrian Behlendorf fnvlist_free(errlist); 2079084fd14fSBrian Behlendorf } 2080084fd14fSBrian Behlendorf 2081084fd14fSBrian Behlendorf return (error); 2082084fd14fSBrian Behlendorf } 2083084fd14fSBrian Behlendorf 2084fa9e4066Sahrens /* 20853f9d6ad7SLin Ling * Scan the pool. 2086fa9e4066Sahrens */ 2087fa9e4066Sahrens int 20881702cce7SAlek Pinchuk zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd) 2089fa9e4066Sahrens { 2090fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2091fa9e4066Sahrens char msg[1024]; 20921702cce7SAlek Pinchuk int err; 209399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2094fa9e4066Sahrens 2095fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 20963f9d6ad7SLin Ling zc.zc_cookie = func; 20971702cce7SAlek Pinchuk zc.zc_flags = cmd; 2098fa9e4066Sahrens 20991702cce7SAlek Pinchuk if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0) 21001702cce7SAlek Pinchuk return (0); 21011702cce7SAlek Pinchuk 21021702cce7SAlek Pinchuk err = errno; 21031702cce7SAlek Pinchuk 21041702cce7SAlek Pinchuk /* ECANCELED on a scrub means we resumed a paused scrub */ 21051702cce7SAlek Pinchuk if (err == ECANCELED && func == POOL_SCAN_SCRUB && 21061702cce7SAlek Pinchuk cmd == POOL_SCRUB_NORMAL) 21071702cce7SAlek Pinchuk return (0); 21081702cce7SAlek Pinchuk 21091702cce7SAlek Pinchuk if (err == ENOENT && func != POOL_SCAN_NONE && cmd == POOL_SCRUB_NORMAL) 2110fa9e4066Sahrens return (0); 2111fa9e4066Sahrens 21123f9d6ad7SLin Ling if (func == POOL_SCAN_SCRUB) { 21131702cce7SAlek Pinchuk if (cmd == POOL_SCRUB_PAUSE) { 21141702cce7SAlek Pinchuk (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 21151702cce7SAlek Pinchuk "cannot pause scrubbing %s"), zc.zc_name); 21161702cce7SAlek Pinchuk } else { 21171702cce7SAlek Pinchuk assert(cmd == POOL_SCRUB_NORMAL); 21181702cce7SAlek Pinchuk (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 21191702cce7SAlek Pinchuk "cannot scrub %s"), zc.zc_name); 21201702cce7SAlek Pinchuk } 2121e4c795beSTom Caputi } else if (func == POOL_SCAN_RESILVER) { 2122e4c795beSTom Caputi assert(cmd == POOL_SCRUB_NORMAL); 2123e4c795beSTom Caputi (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2124e4c795beSTom Caputi "cannot restart resilver on %s"), zc.zc_name); 21253f9d6ad7SLin Ling } else if (func == POOL_SCAN_NONE) { 21263f9d6ad7SLin Ling (void) snprintf(msg, sizeof (msg), 21273f9d6ad7SLin Ling dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"), 21283f9d6ad7SLin Ling zc.zc_name); 21293f9d6ad7SLin Ling } else { 21303f9d6ad7SLin Ling assert(!"unexpected result"); 21313f9d6ad7SLin Ling } 2132fa9e4066Sahrens 21331702cce7SAlek Pinchuk if (err == EBUSY) { 21343f9d6ad7SLin Ling nvlist_t *nvroot; 21353f9d6ad7SLin Ling pool_scan_stat_t *ps = NULL; 21363f9d6ad7SLin Ling uint_t psc; 21373f9d6ad7SLin Ling 21383f9d6ad7SLin Ling verify(nvlist_lookup_nvlist(zhp->zpool_config, 21393f9d6ad7SLin Ling ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 21403f9d6ad7SLin Ling (void) nvlist_lookup_uint64_array(nvroot, 21413f9d6ad7SLin Ling ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc); 21421702cce7SAlek Pinchuk if (ps && ps->pss_func == POOL_SCAN_SCRUB) { 21431702cce7SAlek Pinchuk if (cmd == POOL_SCRUB_PAUSE) 21441702cce7SAlek Pinchuk return (zfs_error(hdl, EZFS_SCRUB_PAUSED, msg)); 21451702cce7SAlek Pinchuk else 21461702cce7SAlek Pinchuk return (zfs_error(hdl, EZFS_SCRUBBING, msg)); 21471702cce7SAlek Pinchuk } else { 21483f9d6ad7SLin Ling return (zfs_error(hdl, EZFS_RESILVERING, msg)); 21491702cce7SAlek Pinchuk } 21501702cce7SAlek Pinchuk } else if (err == ENOENT) { 21513f9d6ad7SLin Ling return (zfs_error(hdl, EZFS_NO_SCRUB, msg)); 2152e4c795beSTom Caputi } else if (err == ENOTSUP && func == POOL_SCAN_RESILVER) { 2153e4c795beSTom Caputi return (zfs_error(hdl, EZFS_NO_RESILVER_DEFER, msg)); 21543f9d6ad7SLin Ling } else { 21551702cce7SAlek Pinchuk return (zpool_standard_error(hdl, err, msg)); 21563f9d6ad7SLin Ling } 2157fa9e4066Sahrens } 2158fa9e4066Sahrens 2159094e47e9SGeorge Wilson static int 2160094e47e9SGeorge Wilson xlate_init_err(int err) 2161094e47e9SGeorge Wilson { 2162094e47e9SGeorge Wilson switch (err) { 2163094e47e9SGeorge Wilson case ENODEV: 2164094e47e9SGeorge Wilson return (EZFS_NODEVICE); 2165094e47e9SGeorge Wilson case EINVAL: 2166094e47e9SGeorge Wilson case EROFS: 2167094e47e9SGeorge Wilson return (EZFS_BADDEV); 2168094e47e9SGeorge Wilson case EBUSY: 2169094e47e9SGeorge Wilson return (EZFS_INITIALIZING); 2170094e47e9SGeorge Wilson case ESRCH: 2171094e47e9SGeorge Wilson return (EZFS_NO_INITIALIZE); 2172094e47e9SGeorge Wilson } 2173094e47e9SGeorge Wilson return (err); 2174094e47e9SGeorge Wilson } 2175094e47e9SGeorge Wilson 2176094e47e9SGeorge Wilson /* 2177094e47e9SGeorge Wilson * Begin, suspend, or cancel the initialization (initializing of all free 2178094e47e9SGeorge Wilson * blocks) for the given vdevs in the given pool. 2179094e47e9SGeorge Wilson */ 2180094e47e9SGeorge Wilson int 2181094e47e9SGeorge Wilson zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, 2182094e47e9SGeorge Wilson nvlist_t *vds) 2183094e47e9SGeorge Wilson { 2184094e47e9SGeorge Wilson char msg[1024]; 2185084fd14fSBrian Behlendorf int err; 2186094e47e9SGeorge Wilson 2187094e47e9SGeorge Wilson nvlist_t *vdev_guids = fnvlist_alloc(); 2188094e47e9SGeorge Wilson nvlist_t *guids_to_paths = fnvlist_alloc(); 2189084fd14fSBrian Behlendorf nvlist_t *vd_errlist = NULL; 2190084fd14fSBrian Behlendorf nvlist_t *errlist; 2191094e47e9SGeorge Wilson nvpair_t *elem; 2192094e47e9SGeorge Wilson 2193084fd14fSBrian Behlendorf err = zpool_translate_vdev_guids(zhp, vds, vdev_guids, 2194084fd14fSBrian Behlendorf guids_to_paths, &vd_errlist); 2195094e47e9SGeorge Wilson 2196084fd14fSBrian Behlendorf if (err == 0) { 2197084fd14fSBrian Behlendorf err = lzc_initialize(zhp->zpool_name, cmd_type, 2198084fd14fSBrian Behlendorf vdev_guids, &errlist); 2199084fd14fSBrian Behlendorf if (err == 0) { 2200094e47e9SGeorge Wilson fnvlist_free(vdev_guids); 2201094e47e9SGeorge Wilson fnvlist_free(guids_to_paths); 2202084fd14fSBrian Behlendorf return (0); 2203094e47e9SGeorge Wilson } 2204094e47e9SGeorge Wilson 2205084fd14fSBrian Behlendorf if (errlist != NULL) { 2206084fd14fSBrian Behlendorf vd_errlist = fnvlist_lookup_nvlist(errlist, 2207084fd14fSBrian Behlendorf ZPOOL_INITIALIZE_VDEVS); 2208084fd14fSBrian Behlendorf } 2209094e47e9SGeorge Wilson 2210084fd14fSBrian Behlendorf (void) snprintf(msg, sizeof (msg), 2211084fd14fSBrian Behlendorf dgettext(TEXT_DOMAIN, "operation failed")); 2212084fd14fSBrian Behlendorf } else { 2213084fd14fSBrian Behlendorf verify(vd_errlist != NULL); 2214084fd14fSBrian Behlendorf } 2215084fd14fSBrian Behlendorf 2216084fd14fSBrian Behlendorf for (elem = nvlist_next_nvpair(vd_errlist, NULL); elem != NULL; 2217084fd14fSBrian Behlendorf elem = nvlist_next_nvpair(vd_errlist, elem)) { 2218084fd14fSBrian Behlendorf int64_t vd_error = xlate_init_err(fnvpair_value_int64(elem)); 2219084fd14fSBrian Behlendorf char *path; 2220084fd14fSBrian Behlendorf 2221084fd14fSBrian Behlendorf if (nvlist_lookup_string(guids_to_paths, nvpair_name(elem), 2222084fd14fSBrian Behlendorf &path) != 0) 2223084fd14fSBrian Behlendorf path = nvpair_name(elem); 2224084fd14fSBrian Behlendorf 2225084fd14fSBrian Behlendorf (void) zfs_error_fmt(zhp->zpool_hdl, vd_error, 2226084fd14fSBrian Behlendorf "cannot initialize '%s'", path); 2227094e47e9SGeorge Wilson } 2228094e47e9SGeorge Wilson 2229094e47e9SGeorge Wilson fnvlist_free(vdev_guids); 2230084fd14fSBrian Behlendorf fnvlist_free(guids_to_paths); 2231094e47e9SGeorge Wilson 2232084fd14fSBrian Behlendorf if (vd_errlist != NULL) { 2233084fd14fSBrian Behlendorf fnvlist_free(vd_errlist); 2234084fd14fSBrian Behlendorf return (-1); 2235084fd14fSBrian Behlendorf } 2236084fd14fSBrian Behlendorf 2237084fd14fSBrian Behlendorf return (zpool_standard_error(zhp->zpool_hdl, err, msg)); 2238084fd14fSBrian Behlendorf } 2239084fd14fSBrian Behlendorf 2240084fd14fSBrian Behlendorf static int 2241084fd14fSBrian Behlendorf xlate_trim_err(int err) 2242084fd14fSBrian Behlendorf { 2243084fd14fSBrian Behlendorf switch (err) { 2244084fd14fSBrian Behlendorf case ENODEV: 2245084fd14fSBrian Behlendorf return (EZFS_NODEVICE); 2246084fd14fSBrian Behlendorf case EINVAL: 2247084fd14fSBrian Behlendorf case EROFS: 2248084fd14fSBrian Behlendorf return (EZFS_BADDEV); 2249084fd14fSBrian Behlendorf case EBUSY: 2250084fd14fSBrian Behlendorf return (EZFS_TRIMMING); 2251084fd14fSBrian Behlendorf case ESRCH: 2252084fd14fSBrian Behlendorf return (EZFS_NO_TRIM); 2253084fd14fSBrian Behlendorf case EOPNOTSUPP: 2254084fd14fSBrian Behlendorf return (EZFS_TRIM_NOTSUP); 2255094e47e9SGeorge Wilson } 2256084fd14fSBrian Behlendorf return (err); 2257084fd14fSBrian Behlendorf } 2258084fd14fSBrian Behlendorf 2259084fd14fSBrian Behlendorf /* 2260084fd14fSBrian Behlendorf * Begin, suspend, or cancel the TRIM (discarding of all free blocks) for 2261084fd14fSBrian Behlendorf * the given vdevs in the given pool. 2262084fd14fSBrian Behlendorf */ 2263084fd14fSBrian Behlendorf int 2264084fd14fSBrian Behlendorf zpool_trim(zpool_handle_t *zhp, pool_trim_func_t cmd_type, nvlist_t *vds, 2265084fd14fSBrian Behlendorf trimflags_t *trim_flags) 2266084fd14fSBrian Behlendorf { 2267084fd14fSBrian Behlendorf char msg[1024]; 2268084fd14fSBrian Behlendorf int err; 2269094e47e9SGeorge Wilson 2270084fd14fSBrian Behlendorf nvlist_t *vdev_guids = fnvlist_alloc(); 2271084fd14fSBrian Behlendorf nvlist_t *guids_to_paths = fnvlist_alloc(); 2272094e47e9SGeorge Wilson nvlist_t *vd_errlist = NULL; 2273084fd14fSBrian Behlendorf nvlist_t *errlist; 2274084fd14fSBrian Behlendorf nvpair_t *elem; 2275084fd14fSBrian Behlendorf 2276084fd14fSBrian Behlendorf err = zpool_translate_vdev_guids(zhp, vds, vdev_guids, 2277084fd14fSBrian Behlendorf guids_to_paths, &vd_errlist); 2278084fd14fSBrian Behlendorf if (err == 0) { 2279084fd14fSBrian Behlendorf err = lzc_trim(zhp->zpool_name, cmd_type, trim_flags->rate, 2280084fd14fSBrian Behlendorf trim_flags->secure, vdev_guids, &errlist); 2281084fd14fSBrian Behlendorf if (err == 0) { 2282084fd14fSBrian Behlendorf fnvlist_free(vdev_guids); 2283084fd14fSBrian Behlendorf fnvlist_free(guids_to_paths); 2284084fd14fSBrian Behlendorf return (0); 2285084fd14fSBrian Behlendorf } 2286084fd14fSBrian Behlendorf 2287084fd14fSBrian Behlendorf if (errlist != NULL) { 2288084fd14fSBrian Behlendorf vd_errlist = fnvlist_lookup_nvlist(errlist, 2289084fd14fSBrian Behlendorf ZPOOL_TRIM_VDEVS); 2290084fd14fSBrian Behlendorf } 2291084fd14fSBrian Behlendorf 2292084fd14fSBrian Behlendorf (void) snprintf(msg, sizeof (msg), 2293084fd14fSBrian Behlendorf dgettext(TEXT_DOMAIN, "operation failed")); 2294084fd14fSBrian Behlendorf } else { 2295084fd14fSBrian Behlendorf verify(vd_errlist != NULL); 2296094e47e9SGeorge Wilson } 2297094e47e9SGeorge Wilson 2298084fd14fSBrian Behlendorf for (elem = nvlist_next_nvpair(vd_errlist, NULL); 2299084fd14fSBrian Behlendorf elem != NULL; elem = nvlist_next_nvpair(vd_errlist, elem)) { 2300084fd14fSBrian Behlendorf int64_t vd_error = xlate_trim_err(fnvpair_value_int64(elem)); 2301084fd14fSBrian Behlendorf char *path; 2302084fd14fSBrian Behlendorf /* 2303084fd14fSBrian Behlendorf * If only the pool was specified, and it was not a secure 2304084fd14fSBrian Behlendorf * trim then suppress warnings for individual vdevs which 2305084fd14fSBrian Behlendorf * do not support trimming. 2306084fd14fSBrian Behlendorf */ 2307084fd14fSBrian Behlendorf if (vd_error == EZFS_TRIM_NOTSUP && 2308084fd14fSBrian Behlendorf trim_flags->fullpool && 2309084fd14fSBrian Behlendorf !trim_flags->secure) { 2310084fd14fSBrian Behlendorf continue; 2311084fd14fSBrian Behlendorf } 2312094e47e9SGeorge Wilson 2313084fd14fSBrian Behlendorf if (nvlist_lookup_string(guids_to_paths, nvpair_name(elem), 2314084fd14fSBrian Behlendorf &path) != 0) 2315084fd14fSBrian Behlendorf path = nvpair_name(elem); 2316084fd14fSBrian Behlendorf 2317084fd14fSBrian Behlendorf (void) zfs_error_fmt(zhp->zpool_hdl, vd_error, 2318084fd14fSBrian Behlendorf "cannot trim '%s'", path); 2319094e47e9SGeorge Wilson } 2320094e47e9SGeorge Wilson 2321084fd14fSBrian Behlendorf fnvlist_free(vdev_guids); 2322094e47e9SGeorge Wilson fnvlist_free(guids_to_paths); 2323084fd14fSBrian Behlendorf 2324084fd14fSBrian Behlendorf if (vd_errlist != NULL) { 2325084fd14fSBrian Behlendorf fnvlist_free(vd_errlist); 2326094e47e9SGeorge Wilson return (-1); 2327084fd14fSBrian Behlendorf } 2328094e47e9SGeorge Wilson 2329084fd14fSBrian Behlendorf return (zpool_standard_error(zhp->zpool_hdl, err, msg)); 2330094e47e9SGeorge Wilson } 2331094e47e9SGeorge Wilson 23323fdda499SJohn Harres /* 23333fdda499SJohn Harres * This provides a very minimal check whether a given string is likely a 23343fdda499SJohn Harres * c#t#d# style string. Users of this are expected to do their own 23353fdda499SJohn Harres * verification of the s# part. 23363fdda499SJohn Harres */ 23373fdda499SJohn Harres #define CTD_CHECK(str) (str && str[0] == 'c' && isdigit(str[1])) 23383fdda499SJohn Harres 23393fdda499SJohn Harres /* 23403fdda499SJohn Harres * More elaborate version for ones which may start with "/dev/dsk/" 23413fdda499SJohn Harres * and the like. 23423fdda499SJohn Harres */ 23433fdda499SJohn Harres static int 23449a686fbcSPaul Dagnelie ctd_check_path(char *str) 23459a686fbcSPaul Dagnelie { 23463fdda499SJohn Harres /* 23473fdda499SJohn Harres * If it starts with a slash, check the last component. 23483fdda499SJohn Harres */ 23493fdda499SJohn Harres if (str && str[0] == '/') { 23503fdda499SJohn Harres char *tmp = strrchr(str, '/'); 23513fdda499SJohn Harres 23523fdda499SJohn Harres /* 23533fdda499SJohn Harres * If it ends in "/old", check the second-to-last 23543fdda499SJohn Harres * component of the string instead. 23553fdda499SJohn Harres */ 23563fdda499SJohn Harres if (tmp != str && strcmp(tmp, "/old") == 0) { 23573fdda499SJohn Harres for (tmp--; *tmp != '/'; tmp--) 23583fdda499SJohn Harres ; 23593fdda499SJohn Harres } 23603fdda499SJohn Harres str = tmp + 1; 23613fdda499SJohn Harres } 23623fdda499SJohn Harres return (CTD_CHECK(str)); 23633fdda499SJohn Harres } 23643fdda499SJohn Harres 2365a43d325bSek /* 2366573ca77eSGeorge Wilson * Find a vdev that matches the search criteria specified. We use the 2367573ca77eSGeorge Wilson * the nvpair name to determine how we should look for the device. 2368a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 2369a43d325bSek * spare; but FALSE if its an INUSE spare. 2370a43d325bSek */ 237199653d4eSeschrock static nvlist_t * 2372573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 2373573ca77eSGeorge Wilson boolean_t *l2cache, boolean_t *log) 2374ea8dc4b6Seschrock { 2375ea8dc4b6Seschrock uint_t c, children; 2376ea8dc4b6Seschrock nvlist_t **child; 237799653d4eSeschrock nvlist_t *ret; 2378ee0eb9f2SEric Schrock uint64_t is_log; 2379573ca77eSGeorge Wilson char *srchkey; 2380573ca77eSGeorge Wilson nvpair_t *pair = nvlist_next_nvpair(search, NULL); 2381573ca77eSGeorge Wilson 2382573ca77eSGeorge Wilson /* Nothing to look for */ 2383573ca77eSGeorge Wilson if (search == NULL || pair == NULL) 2384573ca77eSGeorge Wilson return (NULL); 2385ea8dc4b6Seschrock 2386573ca77eSGeorge Wilson /* Obtain the key we will use to search */ 2387573ca77eSGeorge Wilson srchkey = nvpair_name(pair); 2388573ca77eSGeorge Wilson 2389573ca77eSGeorge Wilson switch (nvpair_type(pair)) { 2390cb04b873SMark J Musante case DATA_TYPE_UINT64: 2391573ca77eSGeorge Wilson if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 2392cb04b873SMark J Musante uint64_t srchval, theguid; 2393cb04b873SMark J Musante 2394cb04b873SMark J Musante verify(nvpair_value_uint64(pair, &srchval) == 0); 2395cb04b873SMark J Musante verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 2396cb04b873SMark J Musante &theguid) == 0); 2397cb04b873SMark J Musante if (theguid == srchval) 2398cb04b873SMark J Musante return (nv); 2399573ca77eSGeorge Wilson } 2400573ca77eSGeorge Wilson break; 2401573ca77eSGeorge Wilson 2402573ca77eSGeorge Wilson case DATA_TYPE_STRING: { 2403573ca77eSGeorge Wilson char *srchval, *val; 2404573ca77eSGeorge Wilson 2405573ca77eSGeorge Wilson verify(nvpair_value_string(pair, &srchval) == 0); 2406573ca77eSGeorge Wilson if (nvlist_lookup_string(nv, srchkey, &val) != 0) 2407573ca77eSGeorge Wilson break; 2408ea8dc4b6Seschrock 2409ea8dc4b6Seschrock /* 24103fdda499SJohn Harres * Search for the requested value. Special cases: 24113fdda499SJohn Harres * 24127855d95bSToomas Soome * - ZPOOL_CONFIG_PATH for whole disk entries. To support 24137855d95bSToomas Soome * UEFI boot, these end in "s0" or "s0/old" or "s1" or 24147855d95bSToomas Soome * "s1/old". The "s0" or "s1" part is hidden from the user, 24153fdda499SJohn Harres * but included in the string, so this matches around it. 24163fdda499SJohn Harres * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE). 24173fdda499SJohn Harres * 241888ecc943SGeorge Wilson * Otherwise, all other searches are simple string compares. 2419ea8dc4b6Seschrock */ 24203fdda499SJohn Harres if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && 24213fdda499SJohn Harres ctd_check_path(val)) { 2422573ca77eSGeorge Wilson uint64_t wholedisk = 0; 2423573ca77eSGeorge Wilson 2424573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 2425573ca77eSGeorge Wilson &wholedisk); 2426573ca77eSGeorge Wilson if (wholedisk) { 24273fdda499SJohn Harres int slen = strlen(srchval); 24283fdda499SJohn Harres int vlen = strlen(val); 24293fdda499SJohn Harres 24303fdda499SJohn Harres if (slen != vlen - 2) 24313fdda499SJohn Harres break; 24323fdda499SJohn Harres 24333fdda499SJohn Harres /* 24343fdda499SJohn Harres * make_leaf_vdev() should only set 24353fdda499SJohn Harres * wholedisk for ZPOOL_CONFIG_PATHs which 24363fdda499SJohn Harres * will include "/dev/dsk/", giving plenty of 24373fdda499SJohn Harres * room for the indices used next. 24383fdda499SJohn Harres */ 24393fdda499SJohn Harres ASSERT(vlen >= 6); 24403fdda499SJohn Harres 24413fdda499SJohn Harres /* 24423fdda499SJohn Harres * strings identical except trailing "s0" 24433fdda499SJohn Harres */ 24447855d95bSToomas Soome if ((strcmp(&val[vlen - 2], "s0") == 0 || 24457855d95bSToomas Soome strcmp(&val[vlen - 2], "s1") == 0) && 24463fdda499SJohn Harres strncmp(srchval, val, slen) == 0) 24473fdda499SJohn Harres return (nv); 24483fdda499SJohn Harres 2449573ca77eSGeorge Wilson /* 24503fdda499SJohn Harres * strings identical except trailing "s0/old" 2451573ca77eSGeorge Wilson */ 24527855d95bSToomas Soome if ((strcmp(&val[vlen - 6], "s0/old") == 0 || 24537855d95bSToomas Soome strcmp(&val[vlen - 6], "s1/old") == 0) && 24543fdda499SJohn Harres strcmp(&srchval[slen - 4], "/old") == 0 && 24553fdda499SJohn Harres strncmp(srchval, val, slen - 4) == 0) 2456573ca77eSGeorge Wilson return (nv); 24573fdda499SJohn Harres 2458573ca77eSGeorge Wilson break; 2459573ca77eSGeorge Wilson } 246088ecc943SGeorge Wilson } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { 246188ecc943SGeorge Wilson char *type, *idx, *end, *p; 246288ecc943SGeorge Wilson uint64_t id, vdev_id; 246388ecc943SGeorge Wilson 246488ecc943SGeorge Wilson /* 246588ecc943SGeorge Wilson * Determine our vdev type, keeping in mind 246688ecc943SGeorge Wilson * that the srchval is composed of a type and 246788ecc943SGeorge Wilson * vdev id pair (i.e. mirror-4). 246888ecc943SGeorge Wilson */ 246988ecc943SGeorge Wilson if ((type = strdup(srchval)) == NULL) 247088ecc943SGeorge Wilson return (NULL); 247188ecc943SGeorge Wilson 247288ecc943SGeorge Wilson if ((p = strrchr(type, '-')) == NULL) { 247388ecc943SGeorge Wilson free(type); 247488ecc943SGeorge Wilson break; 247588ecc943SGeorge Wilson } 247688ecc943SGeorge Wilson idx = p + 1; 247788ecc943SGeorge Wilson *p = '\0'; 247888ecc943SGeorge Wilson 247988ecc943SGeorge Wilson /* 248088ecc943SGeorge Wilson * If the types don't match then keep looking. 248188ecc943SGeorge Wilson */ 248288ecc943SGeorge Wilson if (strncmp(val, type, strlen(val)) != 0) { 248388ecc943SGeorge Wilson free(type); 248488ecc943SGeorge Wilson break; 248588ecc943SGeorge Wilson } 248688ecc943SGeorge Wilson 24872ba5f978SAlan Somers verify(zpool_vdev_is_interior(type)); 248888ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 248988ecc943SGeorge Wilson &id) == 0); 249088ecc943SGeorge Wilson 249188ecc943SGeorge Wilson errno = 0; 249288ecc943SGeorge Wilson vdev_id = strtoull(idx, &end, 10); 249388ecc943SGeorge Wilson 249488ecc943SGeorge Wilson free(type); 249588ecc943SGeorge Wilson if (errno != 0) 249688ecc943SGeorge Wilson return (NULL); 249788ecc943SGeorge Wilson 249888ecc943SGeorge Wilson /* 249988ecc943SGeorge Wilson * Now verify that we have the correct vdev id. 250088ecc943SGeorge Wilson */ 250188ecc943SGeorge Wilson if (vdev_id == id) 250288ecc943SGeorge Wilson return (nv); 2503ea8dc4b6Seschrock } 2504573ca77eSGeorge Wilson 2505573ca77eSGeorge Wilson /* 2506573ca77eSGeorge Wilson * Common case 2507573ca77eSGeorge Wilson */ 2508573ca77eSGeorge Wilson if (strcmp(srchval, val) == 0) 2509573ca77eSGeorge Wilson return (nv); 2510573ca77eSGeorge Wilson break; 2511573ca77eSGeorge Wilson } 2512573ca77eSGeorge Wilson 2513573ca77eSGeorge Wilson default: 2514573ca77eSGeorge Wilson break; 2515ea8dc4b6Seschrock } 2516ea8dc4b6Seschrock 2517ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2518ea8dc4b6Seschrock &child, &children) != 0) 251999653d4eSeschrock return (NULL); 2520ea8dc4b6Seschrock 2521ee0eb9f2SEric Schrock for (c = 0; c < children; c++) { 2522573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2523ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2524ee0eb9f2SEric Schrock /* 2525ee0eb9f2SEric Schrock * The 'is_log' value is only set for the toplevel 2526ee0eb9f2SEric Schrock * vdev, not the leaf vdevs. So we always lookup the 2527ee0eb9f2SEric Schrock * log device from the root of the vdev tree (where 2528ee0eb9f2SEric Schrock * 'log' is non-NULL). 2529ee0eb9f2SEric Schrock */ 2530ee0eb9f2SEric Schrock if (log != NULL && 2531ee0eb9f2SEric Schrock nvlist_lookup_uint64(child[c], 2532ee0eb9f2SEric Schrock ZPOOL_CONFIG_IS_LOG, &is_log) == 0 && 2533ee0eb9f2SEric Schrock is_log) { 2534ee0eb9f2SEric Schrock *log = B_TRUE; 2535ee0eb9f2SEric Schrock } 2536ea8dc4b6Seschrock return (ret); 2537ee0eb9f2SEric Schrock } 2538ee0eb9f2SEric Schrock } 2539ea8dc4b6Seschrock 254099653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 254199653d4eSeschrock &child, &children) == 0) { 254299653d4eSeschrock for (c = 0; c < children; c++) { 2543573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2544ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2545a43d325bSek *avail_spare = B_TRUE; 254699653d4eSeschrock return (ret); 254799653d4eSeschrock } 254899653d4eSeschrock } 254999653d4eSeschrock } 255099653d4eSeschrock 2551fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 2552fa94a07fSbrendan &child, &children) == 0) { 2553fa94a07fSbrendan for (c = 0; c < children; c++) { 2554573ca77eSGeorge Wilson if ((ret = vdev_to_nvlist_iter(child[c], search, 2555ee0eb9f2SEric Schrock avail_spare, l2cache, NULL)) != NULL) { 2556fa94a07fSbrendan *l2cache = B_TRUE; 2557fa94a07fSbrendan return (ret); 2558fa94a07fSbrendan } 2559fa94a07fSbrendan } 2560fa94a07fSbrendan } 2561fa94a07fSbrendan 256299653d4eSeschrock return (NULL); 2563ea8dc4b6Seschrock } 2564ea8dc4b6Seschrock 2565573ca77eSGeorge Wilson /* 2566573ca77eSGeorge Wilson * Given a physical path (minus the "/devices" prefix), find the 2567573ca77eSGeorge Wilson * associated vdev. 2568573ca77eSGeorge Wilson */ 2569573ca77eSGeorge Wilson nvlist_t * 2570573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath, 2571573ca77eSGeorge Wilson boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log) 2572573ca77eSGeorge Wilson { 2573573ca77eSGeorge Wilson nvlist_t *search, *nvroot, *ret; 2574573ca77eSGeorge Wilson 2575573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2576573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0); 2577573ca77eSGeorge Wilson 2578573ca77eSGeorge Wilson verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 2579573ca77eSGeorge Wilson &nvroot) == 0); 2580573ca77eSGeorge Wilson 2581573ca77eSGeorge Wilson *avail_spare = B_FALSE; 2582cb04b873SMark J Musante *l2cache = B_FALSE; 2583daeb70e5SMark J Musante if (log != NULL) 2584daeb70e5SMark J Musante *log = B_FALSE; 2585573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 2586573ca77eSGeorge Wilson nvlist_free(search); 2587573ca77eSGeorge Wilson 2588573ca77eSGeorge Wilson return (ret); 2589573ca77eSGeorge Wilson } 2590573ca77eSGeorge Wilson 259188ecc943SGeorge Wilson /* 259288ecc943SGeorge Wilson * Determine if we have an "interior" top-level vdev (i.e mirror/raidz). 259388ecc943SGeorge Wilson */ 25942ba5f978SAlan Somers static boolean_t 259588ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name) 259688ecc943SGeorge Wilson { 259788ecc943SGeorge Wilson if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 || 25982ba5f978SAlan Somers strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 || 25992ba5f978SAlan Somers strncmp(name, 26002ba5f978SAlan Somers VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 || 260188ecc943SGeorge Wilson strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0) 260288ecc943SGeorge Wilson return (B_TRUE); 260388ecc943SGeorge Wilson return (B_FALSE); 260488ecc943SGeorge Wilson } 260588ecc943SGeorge Wilson 260699653d4eSeschrock nvlist_t * 2607fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, 2608ee0eb9f2SEric Schrock boolean_t *l2cache, boolean_t *log) 2609ea8dc4b6Seschrock { 2610ea8dc4b6Seschrock char buf[MAXPATHLEN]; 2611ea8dc4b6Seschrock char *end; 2612573ca77eSGeorge Wilson nvlist_t *nvroot, *search, *ret; 2613ea8dc4b6Seschrock uint64_t guid; 2614ea8dc4b6Seschrock 2615573ca77eSGeorge Wilson verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2616573ca77eSGeorge Wilson 26170917b783Seschrock guid = strtoull(path, &end, 10); 2618ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 2619573ca77eSGeorge Wilson verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0); 262088ecc943SGeorge Wilson } else if (zpool_vdev_is_interior(path)) { 262188ecc943SGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0); 2622ea8dc4b6Seschrock } else if (path[0] != '/') { 26236401734dSWill Andrews (void) snprintf(buf, sizeof (buf), "%s/%s", ZFS_DISK_ROOT, 26246401734dSWill Andrews path); 2625573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0); 2626ea8dc4b6Seschrock } else { 2627573ca77eSGeorge Wilson verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0); 2628ea8dc4b6Seschrock } 2629ea8dc4b6Seschrock 2630ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 2631ea8dc4b6Seschrock &nvroot) == 0); 2632ea8dc4b6Seschrock 2633a43d325bSek *avail_spare = B_FALSE; 2634fa94a07fSbrendan *l2cache = B_FALSE; 2635ee0eb9f2SEric Schrock if (log != NULL) 2636ee0eb9f2SEric Schrock *log = B_FALSE; 2637573ca77eSGeorge Wilson ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log); 2638573ca77eSGeorge Wilson nvlist_free(search); 2639573ca77eSGeorge Wilson 2640573ca77eSGeorge Wilson return (ret); 2641a43d325bSek } 2642a43d325bSek 264319397407SSherry Moore static int 2644e0f1c0afSOlaf Faaland vdev_is_online(nvlist_t *nv) 264519397407SSherry Moore { 264619397407SSherry Moore uint64_t ival; 264719397407SSherry Moore 264819397407SSherry Moore if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 || 264919397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 || 265019397407SSherry Moore nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0) 265119397407SSherry Moore return (0); 265219397407SSherry Moore 265319397407SSherry Moore return (1); 265419397407SSherry Moore } 265519397407SSherry Moore 265619397407SSherry Moore /* 265721ecdf64SLin Ling * Helper function for zpool_get_physpaths(). 265819397407SSherry Moore */ 2659753a6d45SSherry Moore static int 266021ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size, 2661753a6d45SSherry Moore size_t *bytes_written) 266219397407SSherry Moore { 2663753a6d45SSherry Moore size_t bytes_left, pos, rsz; 2664753a6d45SSherry Moore char *tmppath; 2665753a6d45SSherry Moore const char *format; 2666753a6d45SSherry Moore 2667753a6d45SSherry Moore if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH, 2668753a6d45SSherry Moore &tmppath) != 0) 2669753a6d45SSherry Moore return (EZFS_NODEVICE); 2670753a6d45SSherry Moore 2671753a6d45SSherry Moore pos = *bytes_written; 2672753a6d45SSherry Moore bytes_left = physpath_size - pos; 2673753a6d45SSherry Moore format = (pos == 0) ? "%s" : " %s"; 2674753a6d45SSherry Moore 2675753a6d45SSherry Moore rsz = snprintf(physpath + pos, bytes_left, format, tmppath); 2676753a6d45SSherry Moore *bytes_written += rsz; 2677753a6d45SSherry Moore 2678753a6d45SSherry Moore if (rsz >= bytes_left) { 2679753a6d45SSherry Moore /* if physpath was not copied properly, clear it */ 2680753a6d45SSherry Moore if (bytes_left != 0) { 2681753a6d45SSherry Moore physpath[pos] = 0; 2682753a6d45SSherry Moore } 2683753a6d45SSherry Moore return (EZFS_NOSPC); 2684753a6d45SSherry Moore } 2685753a6d45SSherry Moore return (0); 2686753a6d45SSherry Moore } 2687753a6d45SSherry Moore 268821ecdf64SLin Ling static int 268921ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size, 269021ecdf64SLin Ling size_t *rsz, boolean_t is_spare) 269121ecdf64SLin Ling { 269221ecdf64SLin Ling char *type; 269321ecdf64SLin Ling int ret; 269421ecdf64SLin Ling 269521ecdf64SLin Ling if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0) 269621ecdf64SLin Ling return (EZFS_INVALCONFIG); 269721ecdf64SLin Ling 269821ecdf64SLin Ling if (strcmp(type, VDEV_TYPE_DISK) == 0) { 269921ecdf64SLin Ling /* 270021ecdf64SLin Ling * An active spare device has ZPOOL_CONFIG_IS_SPARE set. 270121ecdf64SLin Ling * For a spare vdev, we only want to boot from the active 270221ecdf64SLin Ling * spare device. 270321ecdf64SLin Ling */ 270421ecdf64SLin Ling if (is_spare) { 270521ecdf64SLin Ling uint64_t spare = 0; 270621ecdf64SLin Ling (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE, 270721ecdf64SLin Ling &spare); 270821ecdf64SLin Ling if (!spare) 270921ecdf64SLin Ling return (EZFS_INVALCONFIG); 271021ecdf64SLin Ling } 271121ecdf64SLin Ling 2712e0f1c0afSOlaf Faaland if (vdev_is_online(nv)) { 271321ecdf64SLin Ling if ((ret = vdev_get_one_physpath(nv, physpath, 271421ecdf64SLin Ling phypath_size, rsz)) != 0) 271521ecdf64SLin Ling return (ret); 271621ecdf64SLin Ling } 271721ecdf64SLin Ling } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 || 2718d5f26ad8SToomas Soome strcmp(type, VDEV_TYPE_RAIDZ) == 0 || 271921ecdf64SLin Ling strcmp(type, VDEV_TYPE_REPLACING) == 0 || 272021ecdf64SLin Ling (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) { 272121ecdf64SLin Ling nvlist_t **child; 272221ecdf64SLin Ling uint_t count; 272321ecdf64SLin Ling int i, ret; 272421ecdf64SLin Ling 272521ecdf64SLin Ling if (nvlist_lookup_nvlist_array(nv, 272621ecdf64SLin Ling ZPOOL_CONFIG_CHILDREN, &child, &count) != 0) 272721ecdf64SLin Ling return (EZFS_INVALCONFIG); 272821ecdf64SLin Ling 272921ecdf64SLin Ling for (i = 0; i < count; i++) { 273021ecdf64SLin Ling ret = vdev_get_physpaths(child[i], physpath, 273121ecdf64SLin Ling phypath_size, rsz, is_spare); 273221ecdf64SLin Ling if (ret == EZFS_NOSPC) 273321ecdf64SLin Ling return (ret); 273421ecdf64SLin Ling } 273521ecdf64SLin Ling } 273621ecdf64SLin Ling 273721ecdf64SLin Ling return (EZFS_POOL_INVALARG); 273821ecdf64SLin Ling } 273921ecdf64SLin Ling 2740753a6d45SSherry Moore /* 2741753a6d45SSherry Moore * Get phys_path for a root pool config. 2742753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 2743753a6d45SSherry Moore */ 2744753a6d45SSherry Moore static int 2745753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) 2746753a6d45SSherry Moore { 2747753a6d45SSherry Moore size_t rsz; 274819397407SSherry Moore nvlist_t *vdev_root; 274919397407SSherry Moore nvlist_t **child; 275019397407SSherry Moore uint_t count; 2751753a6d45SSherry Moore char *type; 2752753a6d45SSherry Moore 2753753a6d45SSherry Moore rsz = 0; 2754753a6d45SSherry Moore 2755753a6d45SSherry Moore if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2756753a6d45SSherry Moore &vdev_root) != 0) 2757753a6d45SSherry Moore return (EZFS_INVALCONFIG); 2758753a6d45SSherry Moore 2759753a6d45SSherry Moore if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 || 2760753a6d45SSherry Moore nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN, 2761753a6d45SSherry Moore &child, &count) != 0) 2762753a6d45SSherry Moore return (EZFS_INVALCONFIG); 276319397407SSherry Moore 276419397407SSherry Moore /* 27651a902ef8SHans Rosenfeld * root pool can only have a single top-level vdev. 276619397407SSherry Moore */ 27671a902ef8SHans Rosenfeld if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1) 2768753a6d45SSherry Moore return (EZFS_POOL_INVALARG); 276919397407SSherry Moore 277021ecdf64SLin Ling (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, 277121ecdf64SLin Ling B_FALSE); 277219397407SSherry Moore 2773753a6d45SSherry Moore /* No online devices */ 2774753a6d45SSherry Moore if (rsz == 0) 2775753a6d45SSherry Moore return (EZFS_NODEVICE); 2776753a6d45SSherry Moore 277719397407SSherry Moore return (0); 277819397407SSherry Moore } 277919397407SSherry Moore 2780753a6d45SSherry Moore /* 2781753a6d45SSherry Moore * Get phys_path for a root pool 2782753a6d45SSherry Moore * Return 0 on success; non-zero on failure. 2783753a6d45SSherry Moore */ 2784753a6d45SSherry Moore int 2785753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size) 2786753a6d45SSherry Moore { 2787753a6d45SSherry Moore return (zpool_get_config_physpath(zhp->zpool_config, physpath, 2788753a6d45SSherry Moore phypath_size)); 2789753a6d45SSherry Moore } 2790753a6d45SSherry Moore 2791573ca77eSGeorge Wilson /* 2792573ca77eSGeorge Wilson * If the device has being dynamically expanded then we need to relabel 2793573ca77eSGeorge Wilson * the disk to use the new unallocated space. 2794573ca77eSGeorge Wilson */ 2795573ca77eSGeorge Wilson static int 2796573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name) 2797573ca77eSGeorge Wilson { 2798573ca77eSGeorge Wilson char path[MAXPATHLEN]; 2799573ca77eSGeorge Wilson char errbuf[1024]; 2800573ca77eSGeorge Wilson int fd, error; 2801573ca77eSGeorge Wilson int (*_efi_use_whole_disk)(int); 2802573ca77eSGeorge Wilson 2803573ca77eSGeorge Wilson if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT, 2804573ca77eSGeorge Wilson "efi_use_whole_disk")) == NULL) 2805573ca77eSGeorge Wilson return (-1); 2806573ca77eSGeorge Wilson 28076401734dSWill Andrews (void) snprintf(path, sizeof (path), "%s/%s", ZFS_RDISK_ROOT, name); 2808573ca77eSGeorge Wilson 2809573ca77eSGeorge Wilson if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 2810573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 2811573ca77eSGeorge Wilson "relabel '%s': unable to open device"), name); 2812573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 2813573ca77eSGeorge Wilson } 2814573ca77eSGeorge Wilson 2815573ca77eSGeorge Wilson /* 2816573ca77eSGeorge Wilson * It's possible that we might encounter an error if the device 2817573ca77eSGeorge Wilson * does not have any unallocated space left. If so, we simply 2818573ca77eSGeorge Wilson * ignore that error and continue on. 2819573ca77eSGeorge Wilson */ 2820573ca77eSGeorge Wilson error = _efi_use_whole_disk(fd); 2821573ca77eSGeorge Wilson (void) close(fd); 2822573ca77eSGeorge Wilson if (error && error != VT_ENOSPC) { 2823573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 2824573ca77eSGeorge Wilson "relabel '%s': unable to read disk capacity"), name); 2825573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 2826573ca77eSGeorge Wilson } 2827573ca77eSGeorge Wilson return (0); 2828573ca77eSGeorge Wilson } 2829573ca77eSGeorge Wilson 2830fa9e4066Sahrens /* 28313d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 28323d7072f8Seschrock * ZFS_ONLINE_* flags. 2833fa9e4066Sahrens */ 2834fa9e4066Sahrens int 28353d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 28363d7072f8Seschrock vdev_state_t *newstate) 2837fa9e4066Sahrens { 2838fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2839fa9e4066Sahrens char msg[1024]; 28409a551dd6SYuri Pankov char *pathname; 284199653d4eSeschrock nvlist_t *tgt; 2842573ca77eSGeorge Wilson boolean_t avail_spare, l2cache, islog; 284399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2844fa9e4066Sahrens 2845573ca77eSGeorge Wilson if (flags & ZFS_ONLINE_EXPAND) { 2846573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2847573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot expand %s"), path); 2848573ca77eSGeorge Wilson } else { 2849573ca77eSGeorge Wilson (void) snprintf(msg, sizeof (msg), 2850573ca77eSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot online %s"), path); 2851573ca77eSGeorge Wilson } 2852ea8dc4b6Seschrock 2853fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2854ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2855573ca77eSGeorge Wilson &islog)) == NULL) 285699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 2857fa9e4066Sahrens 285899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2859fa9e4066Sahrens 2860069f55e2SEric Schrock if (avail_spare) 2861a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2862a43d325bSek 28639a551dd6SYuri Pankov if ((flags & ZFS_ONLINE_EXPAND || 28649a551dd6SYuri Pankov zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) && 28659a551dd6SYuri Pankov nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) { 2866573ca77eSGeorge Wilson uint64_t wholedisk = 0; 2867573ca77eSGeorge Wilson 2868573ca77eSGeorge Wilson (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, 2869573ca77eSGeorge Wilson &wholedisk); 2870573ca77eSGeorge Wilson 2871573ca77eSGeorge Wilson /* 2872573ca77eSGeorge Wilson * XXX - L2ARC 1.0 devices can't support expansion. 2873573ca77eSGeorge Wilson */ 2874573ca77eSGeorge Wilson if (l2cache) { 2875573ca77eSGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2876573ca77eSGeorge Wilson "cannot expand cache devices")); 2877573ca77eSGeorge Wilson return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg)); 2878573ca77eSGeorge Wilson } 2879573ca77eSGeorge Wilson 2880573ca77eSGeorge Wilson if (wholedisk) { 28816401734dSWill Andrews pathname += strlen(ZFS_DISK_ROOT) + 1; 2882cb04b873SMark J Musante (void) zpool_relabel_disk(hdl, pathname); 2883573ca77eSGeorge Wilson } 2884573ca77eSGeorge Wilson } 2885573ca77eSGeorge Wilson 28863d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 28873d7072f8Seschrock zc.zc_obj = flags; 2888fa9e4066Sahrens 2889cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) { 28901195e687SMark J Musante if (errno == EINVAL) { 28911195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split " 28921195e687SMark J Musante "from this pool into a new one. Use '%s' " 28931195e687SMark J Musante "instead"), "zpool detach"); 28941195e687SMark J Musante return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg)); 28951195e687SMark J Musante } 28963d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 28971195e687SMark J Musante } 28983d7072f8Seschrock 28993d7072f8Seschrock *newstate = zc.zc_cookie; 29003d7072f8Seschrock return (0); 2901fa9e4066Sahrens } 2902fa9e4066Sahrens 2903fa9e4066Sahrens /* 2904fa9e4066Sahrens * Take the specified vdev offline 2905fa9e4066Sahrens */ 2906fa9e4066Sahrens int 29073d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 2908fa9e4066Sahrens { 2909fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 2910fa9e4066Sahrens char msg[1024]; 291199653d4eSeschrock nvlist_t *tgt; 2912fa94a07fSbrendan boolean_t avail_spare, l2cache; 291399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 2914fa9e4066Sahrens 2915ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 2916ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 2917ea8dc4b6Seschrock 2918fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2919ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 2920ee0eb9f2SEric Schrock NULL)) == NULL) 292199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 292299653d4eSeschrock 292399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 2924fa9e4066Sahrens 2925069f55e2SEric Schrock if (avail_spare) 2926a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 2927a43d325bSek 29283d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 29293d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 29303d7072f8Seschrock 2931cb04b873SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 29323d7072f8Seschrock return (0); 29333d7072f8Seschrock 29343d7072f8Seschrock switch (errno) { 29353d7072f8Seschrock case EBUSY: 29363d7072f8Seschrock 29373d7072f8Seschrock /* 29383d7072f8Seschrock * There are no other replicas of this device. 29393d7072f8Seschrock */ 29403d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 29413d7072f8Seschrock 2942e6ca193dSGeorge Wilson case EEXIST: 2943e6ca193dSGeorge Wilson /* 2944e6ca193dSGeorge Wilson * The log device has unplayed logs 2945e6ca193dSGeorge Wilson */ 2946e6ca193dSGeorge Wilson return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg)); 2947e6ca193dSGeorge Wilson 29483d7072f8Seschrock default: 29493d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 29503d7072f8Seschrock } 29513d7072f8Seschrock } 29523d7072f8Seschrock 29533d7072f8Seschrock /* 29543d7072f8Seschrock * Mark the given vdev faulted. 29553d7072f8Seschrock */ 29563d7072f8Seschrock int 2957069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 29583d7072f8Seschrock { 29593d7072f8Seschrock zfs_cmd_t zc = { 0 }; 29603d7072f8Seschrock char msg[1024]; 29613d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 29623d7072f8Seschrock 29633d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 29643d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 2965441d80aaSlling 29663d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 29673d7072f8Seschrock zc.zc_guid = guid; 29683d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 2969069f55e2SEric Schrock zc.zc_obj = aux; 29703d7072f8Seschrock 2971cb04b873SMark J Musante if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 2972fa9e4066Sahrens return (0); 2973fa9e4066Sahrens 2974fa9e4066Sahrens switch (errno) { 297599653d4eSeschrock case EBUSY: 2976fa9e4066Sahrens 2977fa9e4066Sahrens /* 2978fa9e4066Sahrens * There are no other replicas of this device. 2979fa9e4066Sahrens */ 298099653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 2981fa9e4066Sahrens 298299653d4eSeschrock default: 298399653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 2984fa9e4066Sahrens } 29853d7072f8Seschrock 29863d7072f8Seschrock } 29873d7072f8Seschrock 29883d7072f8Seschrock /* 29893d7072f8Seschrock * Mark the given vdev degraded. 29903d7072f8Seschrock */ 29913d7072f8Seschrock int 2992069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux) 29933d7072f8Seschrock { 29943d7072f8Seschrock zfs_cmd_t zc = { 0 }; 29953d7072f8Seschrock char msg[1024]; 29963d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 29973d7072f8Seschrock 29983d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 29993d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 30003d7072f8Seschrock 30013d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 30023d7072f8Seschrock zc.zc_guid = guid; 30033d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 3004069f55e2SEric Schrock zc.zc_obj = aux; 30053d7072f8Seschrock 3006cb04b873SMark J Musante if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 30073d7072f8Seschrock return (0); 30083d7072f8Seschrock 30093d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 301099653d4eSeschrock } 301199653d4eSeschrock 301299653d4eSeschrock /* 301399653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 301499653d4eSeschrock * a hot spare. 301599653d4eSeschrock */ 301699653d4eSeschrock static boolean_t 301799653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 301899653d4eSeschrock { 301999653d4eSeschrock nvlist_t **child; 302099653d4eSeschrock uint_t c, children; 302199653d4eSeschrock char *type; 302299653d4eSeschrock 302399653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 302499653d4eSeschrock &children) == 0) { 302599653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 302699653d4eSeschrock &type) == 0); 302799653d4eSeschrock 302899653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 302999653d4eSeschrock children == 2 && child[which] == tgt) 303099653d4eSeschrock return (B_TRUE); 303199653d4eSeschrock 303299653d4eSeschrock for (c = 0; c < children; c++) 303399653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 303499653d4eSeschrock return (B_TRUE); 303599653d4eSeschrock } 303699653d4eSeschrock 303799653d4eSeschrock return (B_FALSE); 3038fa9e4066Sahrens } 3039fa9e4066Sahrens 3040fa9e4066Sahrens /* 3041fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 30428654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 3043fa9e4066Sahrens */ 3044fa9e4066Sahrens int 3045fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 3046fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 3047fa9e4066Sahrens { 3048fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3049fa9e4066Sahrens char msg[1024]; 3050fa9e4066Sahrens int ret; 3051e830fb12SKody A Kantor nvlist_t *tgt, *newvd; 3052ee0eb9f2SEric Schrock boolean_t avail_spare, l2cache, islog; 3053ee0eb9f2SEric Schrock uint64_t val; 3054cb04b873SMark J Musante char *newname; 305599653d4eSeschrock nvlist_t **child; 305699653d4eSeschrock uint_t children; 305799653d4eSeschrock nvlist_t *config_root; 305899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 30594263d13fSGeorge Wilson boolean_t rootpool = zpool_is_bootable(zhp); 3060fa9e4066Sahrens 3061ea8dc4b6Seschrock if (replacing) 3062ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 3063ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 3064ea8dc4b6Seschrock else 3065ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 3066ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 3067ea8dc4b6Seschrock 3068fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3069ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, 30705cabbc6bSPrashanth Sreenivasa &islog)) == NULL) 307199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 307299653d4eSeschrock 3073a43d325bSek if (avail_spare) 307499653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 307599653d4eSeschrock 3076fa94a07fSbrendan if (l2cache) 3077fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 3078fa94a07fSbrendan 307999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 3080fa9e4066Sahrens zc.zc_cookie = replacing; 3081fa9e4066Sahrens 308299653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 308399653d4eSeschrock &child, &children) != 0 || children != 1) { 308499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 308599653d4eSeschrock "new device must be a single disk")); 308699653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 308799653d4eSeschrock } 308899653d4eSeschrock 308999653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 309099653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 309199653d4eSeschrock 3092663207adSDon Brady if ((newname = zpool_vdev_name(NULL, NULL, child[0], 0)) == NULL) 30930430f8daSeschrock return (-1); 30940430f8daSeschrock 3095e830fb12SKody A Kantor newvd = zpool_find_vdev(zhp, newname, &avail_spare, &l2cache, NULL); 309699653d4eSeschrock /* 309799653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 309899653d4eSeschrock * replace it with another hot spare. 309999653d4eSeschrock */ 310099653d4eSeschrock if (replacing && 310199653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 3102e830fb12SKody A Kantor (newvd == NULL || !avail_spare) && 3103ee0eb9f2SEric Schrock is_replacing_spare(config_root, tgt, 1)) { 310499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 310599653d4eSeschrock "can only be replaced by another hot spare")); 31060430f8daSeschrock free(newname); 310799653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 310899653d4eSeschrock } 310999653d4eSeschrock 31100430f8daSeschrock free(newname); 31110430f8daSeschrock 3112e830fb12SKody A Kantor if (replacing && avail_spare && !vdev_is_online(newvd)) { 3113e830fb12SKody A Kantor (void) zpool_standard_error(hdl, ENXIO, msg); 3114e830fb12SKody A Kantor return (-1); 3115e830fb12SKody A Kantor } 3116e830fb12SKody A Kantor 3117990b4856Slling if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0) 311899653d4eSeschrock return (-1); 3119fa9e4066Sahrens 3120cb04b873SMark J Musante ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc); 3121fa9e4066Sahrens 3122e9dbad6fSeschrock zcmd_free_nvlists(&zc); 3123fa9e4066Sahrens 3124b5b76fecSGeorge Wilson if (ret == 0) { 3125b5b76fecSGeorge Wilson if (rootpool) { 312621ecdf64SLin Ling /* 312721ecdf64SLin Ling * XXX need a better way to prevent user from 312821ecdf64SLin Ling * booting up a half-baked vdev. 312921ecdf64SLin Ling */ 313021ecdf64SLin Ling (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make " 313121ecdf64SLin Ling "sure to wait until resilver is done " 313221ecdf64SLin Ling "before rebooting.\n")); 3133b5b76fecSGeorge Wilson } 3134fa9e4066Sahrens return (0); 3135b5b76fecSGeorge Wilson } 3136fa9e4066Sahrens 3137fa9e4066Sahrens switch (errno) { 3138ea8dc4b6Seschrock case ENOTSUP: 3139fa9e4066Sahrens /* 3140fa9e4066Sahrens * Can't attach to or replace this type of vdev. 3141fa9e4066Sahrens */ 31428654d025Sperrin if (replacing) { 3143cb04b873SMark J Musante uint64_t version = zpool_get_prop_int(zhp, 3144cb04b873SMark J Musante ZPOOL_PROP_VERSION, NULL); 3145cb04b873SMark J Musante 3146ee0eb9f2SEric Schrock if (islog) 31478654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31488654d025Sperrin "cannot replace a log with a spare")); 3149cb04b873SMark J Musante else if (version >= SPA_VERSION_MULTI_REPLACE) 3150cb04b873SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3151cb04b873SMark J Musante "already in replacing/spare config; wait " 3152cb04b873SMark J Musante "for completion or use 'zpool detach'")); 31538654d025Sperrin else 31548654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31558654d025Sperrin "cannot replace a replacing device")); 31568654d025Sperrin } else { 315799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 315899653d4eSeschrock "can only attach to mirrors and top-level " 315999653d4eSeschrock "disks")); 31608654d025Sperrin } 316199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 3162fa9e4066Sahrens break; 3163fa9e4066Sahrens 3164ea8dc4b6Seschrock case EINVAL: 3165fa9e4066Sahrens /* 3166fa9e4066Sahrens * The new device must be a single disk. 3167fa9e4066Sahrens */ 316899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 316999653d4eSeschrock "new device must be a single disk")); 317099653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 3171fa9e4066Sahrens break; 3172fa9e4066Sahrens 3173ea8dc4b6Seschrock case EBUSY: 31745cabbc6bSPrashanth Sreenivasa zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy, " 31753a4b1be9SMatthew Ahrens "or device removal is in progress"), 317699653d4eSeschrock new_disk); 317799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 3178fa9e4066Sahrens break; 3179fa9e4066Sahrens 3180ea8dc4b6Seschrock case EOVERFLOW: 3181fa9e4066Sahrens /* 3182fa9e4066Sahrens * The new device is too small. 3183fa9e4066Sahrens */ 318499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 318599653d4eSeschrock "device is too small")); 318699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 3187fa9e4066Sahrens break; 3188fa9e4066Sahrens 3189ea8dc4b6Seschrock case EDOM: 3190fa9e4066Sahrens /* 31915711d393Sloli * The new device has a different optimal sector size. 3192fa9e4066Sahrens */ 319399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31945711d393Sloli "new device has a different optimal sector size; use the " 31955711d393Sloli "option '-o ashift=N' to override the optimal size")); 319699653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 3197fa9e4066Sahrens break; 3198fa9e4066Sahrens 3199ea8dc4b6Seschrock case ENAMETOOLONG: 3200fa9e4066Sahrens /* 3201fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 3202fa9e4066Sahrens */ 320399653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 3204fa9e4066Sahrens break; 3205fa9e4066Sahrens 3206ea8dc4b6Seschrock default: 320799653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 3208fa9e4066Sahrens } 3209fa9e4066Sahrens 321099653d4eSeschrock return (-1); 3211fa9e4066Sahrens } 3212fa9e4066Sahrens 3213fa9e4066Sahrens /* 3214fa9e4066Sahrens * Detach the specified device. 3215fa9e4066Sahrens */ 3216fa9e4066Sahrens int 3217fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 3218fa9e4066Sahrens { 3219fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 3220fa9e4066Sahrens char msg[1024]; 322199653d4eSeschrock nvlist_t *tgt; 3222fa94a07fSbrendan boolean_t avail_spare, l2cache; 322399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 3224fa9e4066Sahrens 3225ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 3226ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 3227ea8dc4b6Seschrock 3228fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3229ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 32305cabbc6bSPrashanth Sreenivasa NULL)) == NULL) 323199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 3232fa9e4066Sahrens 3233a43d325bSek if (avail_spare) 323499653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 323599653d4eSeschrock 3236fa94a07fSbrendan if (l2cache) 3237fa94a07fSbrendan return (zfs_error(hdl, EZFS_ISL2CACHE, msg)); 3238fa94a07fSbrendan 323999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 324099653d4eSeschrock 3241ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 3242fa9e4066Sahrens return (0); 3243fa9e4066Sahrens 3244fa9e4066Sahrens switch (errno) { 3245fa9e4066Sahrens 3246ea8dc4b6Seschrock case ENOTSUP: 3247fa9e4066Sahrens /* 3248fa9e4066Sahrens * Can't detach from this type of vdev. 3249fa9e4066Sahrens */ 325099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 325199653d4eSeschrock "applicable to mirror and replacing vdevs")); 3252cb04b873SMark J Musante (void) zfs_error(hdl, EZFS_BADTARGET, msg); 3253fa9e4066Sahrens break; 3254fa9e4066Sahrens 3255ea8dc4b6Seschrock case EBUSY: 3256fa9e4066Sahrens /* 3257fa9e4066Sahrens * There are no other replicas of this device. 3258fa9e4066Sahrens */ 325999653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 3260fa9e4066Sahrens break; 3261fa9e4066Sahrens 3262ea8dc4b6Seschrock default: 326399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 3264ea8dc4b6Seschrock } 3265ea8dc4b6Seschrock 326699653d4eSeschrock return (-1); 326799653d4eSeschrock } 326899653d4eSeschrock 32691195e687SMark J Musante /* 32701195e687SMark J Musante * Find a mirror vdev in the source nvlist. 32711195e687SMark J Musante * 32721195e687SMark J Musante * The mchild array contains a list of disks in one of the top-level mirrors 32731195e687SMark J Musante * of the source pool. The schild array contains a list of disks that the 32741195e687SMark J Musante * user specified on the command line. We loop over the mchild array to 32751195e687SMark J Musante * see if any entry in the schild array matches. 32761195e687SMark J Musante * 32771195e687SMark J Musante * If a disk in the mchild array is found in the schild array, we return 32781195e687SMark J Musante * the index of that entry. Otherwise we return -1. 32791195e687SMark J Musante */ 32801195e687SMark J Musante static int 32811195e687SMark J Musante find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren, 32821195e687SMark J Musante nvlist_t **schild, uint_t schildren) 32831195e687SMark J Musante { 32841195e687SMark J Musante uint_t mc; 32851195e687SMark J Musante 32861195e687SMark J Musante for (mc = 0; mc < mchildren; mc++) { 32871195e687SMark J Musante uint_t sc; 32881195e687SMark J Musante char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp, 3289663207adSDon Brady mchild[mc], 0); 32901195e687SMark J Musante 32911195e687SMark J Musante for (sc = 0; sc < schildren; sc++) { 32921195e687SMark J Musante char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp, 3293663207adSDon Brady schild[sc], 0); 32941195e687SMark J Musante boolean_t result = (strcmp(mpath, spath) == 0); 32951195e687SMark J Musante 32961195e687SMark J Musante free(spath); 32971195e687SMark J Musante if (result) { 32981195e687SMark J Musante free(mpath); 32991195e687SMark J Musante return (mc); 33001195e687SMark J Musante } 33011195e687SMark J Musante } 33021195e687SMark J Musante 33031195e687SMark J Musante free(mpath); 33041195e687SMark J Musante } 33051195e687SMark J Musante 33061195e687SMark J Musante return (-1); 33071195e687SMark J Musante } 33081195e687SMark J Musante 33091195e687SMark J Musante /* 33101195e687SMark J Musante * Split a mirror pool. If newroot points to null, then a new nvlist 33111195e687SMark J Musante * is generated and it is the responsibility of the caller to free it. 33121195e687SMark J Musante */ 33131195e687SMark J Musante int 33141195e687SMark J Musante zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot, 33151195e687SMark J Musante nvlist_t *props, splitflags_t flags) 33161195e687SMark J Musante { 33171195e687SMark J Musante zfs_cmd_t zc = { 0 }; 33181195e687SMark J Musante char msg[1024]; 33191195e687SMark J Musante nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL; 33201195e687SMark J Musante nvlist_t **varray = NULL, *zc_props = NULL; 33211195e687SMark J Musante uint_t c, children, newchildren, lastlog = 0, vcount, found = 0; 33221195e687SMark J Musante libzfs_handle_t *hdl = zhp->zpool_hdl; 33231195e687SMark J Musante uint64_t vers; 33241195e687SMark J Musante boolean_t freelist = B_FALSE, memory_err = B_TRUE; 33251195e687SMark J Musante int retval = 0; 33261195e687SMark J Musante 33271195e687SMark J Musante (void) snprintf(msg, sizeof (msg), 33281195e687SMark J Musante dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name); 33291195e687SMark J Musante 33301195e687SMark J Musante if (!zpool_name_valid(hdl, B_FALSE, newname)) 33311195e687SMark J Musante return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 33321195e687SMark J Musante 33331195e687SMark J Musante if ((config = zpool_get_config(zhp, NULL)) == NULL) { 33341195e687SMark J Musante (void) fprintf(stderr, gettext("Internal error: unable to " 33351195e687SMark J Musante "retrieve pool configuration\n")); 33361195e687SMark J Musante return (-1); 33371195e687SMark J Musante } 33381195e687SMark J Musante 33391195e687SMark J Musante verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) 33401195e687SMark J Musante == 0); 33411195e687SMark J Musante verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0); 33421195e687SMark J Musante 33431195e687SMark J Musante if (props) { 3344f9af39baSGeorge Wilson prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE }; 33451195e687SMark J Musante if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name, 3346f9af39baSGeorge Wilson props, vers, flags, msg)) == NULL) 33471195e687SMark J Musante return (-1); 33481195e687SMark J Musante } 33491195e687SMark J Musante 33501195e687SMark J Musante if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, 33511195e687SMark J Musante &children) != 0) { 33521195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 33531195e687SMark J Musante "Source pool is missing vdev tree")); 3354aab83bb8SJosef 'Jeff' Sipek nvlist_free(zc_props); 33551195e687SMark J Musante return (-1); 33561195e687SMark J Musante } 33571195e687SMark J Musante 33581195e687SMark J Musante varray = zfs_alloc(hdl, children * sizeof (nvlist_t *)); 33591195e687SMark J Musante vcount = 0; 33601195e687SMark J Musante 33611195e687SMark J Musante if (*newroot == NULL || 33621195e687SMark J Musante nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, 33631195e687SMark J Musante &newchild, &newchildren) != 0) 33641195e687SMark J Musante newchildren = 0; 33651195e687SMark J Musante 33661195e687SMark J Musante for (c = 0; c < children; c++) { 33671195e687SMark J Musante uint64_t is_log = B_FALSE, is_hole = B_FALSE; 33681195e687SMark J Musante char *type; 33691195e687SMark J Musante nvlist_t **mchild, *vdev; 33701195e687SMark J Musante uint_t mchildren; 33711195e687SMark J Musante int entry; 33721195e687SMark J Musante 33731195e687SMark J Musante /* 33741195e687SMark J Musante * Unlike cache & spares, slogs are stored in the 33751195e687SMark J Musante * ZPOOL_CONFIG_CHILDREN array. We filter them out here. 33761195e687SMark J Musante */ 33771195e687SMark J Musante (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 33781195e687SMark J Musante &is_log); 33791195e687SMark J Musante (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 33801195e687SMark J Musante &is_hole); 33811195e687SMark J Musante if (is_log || is_hole) { 33821195e687SMark J Musante /* 33831195e687SMark J Musante * Create a hole vdev and put it in the config. 33841195e687SMark J Musante */ 33851195e687SMark J Musante if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0) 33861195e687SMark J Musante goto out; 33871195e687SMark J Musante if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, 33881195e687SMark J Musante VDEV_TYPE_HOLE) != 0) 33891195e687SMark J Musante goto out; 33901195e687SMark J Musante if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE, 33911195e687SMark J Musante 1) != 0) 33921195e687SMark J Musante goto out; 33931195e687SMark J Musante if (lastlog == 0) 33941195e687SMark J Musante lastlog = vcount; 33951195e687SMark J Musante varray[vcount++] = vdev; 33961195e687SMark J Musante continue; 33971195e687SMark J Musante } 33981195e687SMark J Musante lastlog = 0; 33991195e687SMark J Musante verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type) 34001195e687SMark J Musante == 0); 34011195e687SMark J Musante if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 34021195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34031195e687SMark J Musante "Source pool must be composed only of mirrors\n")); 34041195e687SMark J Musante retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 34051195e687SMark J Musante goto out; 34061195e687SMark J Musante } 34071195e687SMark J Musante 34081195e687SMark J Musante verify(nvlist_lookup_nvlist_array(child[c], 34091195e687SMark J Musante ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0); 34101195e687SMark J Musante 34111195e687SMark J Musante /* find or add an entry for this top-level vdev */ 34121195e687SMark J Musante if (newchildren > 0 && 34131195e687SMark J Musante (entry = find_vdev_entry(zhp, mchild, mchildren, 34141195e687SMark J Musante newchild, newchildren)) >= 0) { 34151195e687SMark J Musante /* We found a disk that the user specified. */ 34161195e687SMark J Musante vdev = mchild[entry]; 34171195e687SMark J Musante ++found; 34181195e687SMark J Musante } else { 34191195e687SMark J Musante /* User didn't specify a disk for this vdev. */ 34201195e687SMark J Musante vdev = mchild[mchildren - 1]; 34211195e687SMark J Musante } 34221195e687SMark J Musante 34231195e687SMark J Musante if (nvlist_dup(vdev, &varray[vcount++], 0) != 0) 34241195e687SMark J Musante goto out; 34251195e687SMark J Musante } 34261195e687SMark J Musante 34271195e687SMark J Musante /* did we find every disk the user specified? */ 34281195e687SMark J Musante if (found != newchildren) { 34291195e687SMark J Musante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must " 34301195e687SMark J Musante "include at most one disk from each mirror")); 34311195e687SMark J Musante retval = zfs_error(hdl, EZFS_INVALCONFIG, msg); 34321195e687SMark J Musante goto out; 34331195e687SMark J Musante } 34341195e687SMark J Musante 34351195e687SMark J Musante /* Prepare the nvlist for populating. */ 34361195e687SMark J Musante if (*newroot == NULL) { 34371195e687SMark J Musante if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0) 34381195e687SMark J Musante goto out; 34391195e687SMark J Musante freelist = B_TRUE; 34401195e687SMark J Musante if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE, 34411195e687SMark J Musante VDEV_TYPE_ROOT) != 0) 34421195e687SMark J Musante goto out; 34431195e687SMark J Musante } else { 34441195e687SMark J Musante verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0); 34451195e687SMark J Musante } 34461195e687SMark J Musante 34471195e687SMark J Musante /* Add all the children we found */ 34481195e687SMark J Musante if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray, 34491195e687SMark J Musante lastlog == 0 ? vcount : lastlog) != 0) 34501195e687SMark J Musante goto out; 34511195e687SMark J Musante 34521195e687SMark J Musante /* 34531195e687SMark J Musante * If we're just doing a dry run, exit now with success. 34541195e687SMark J Musante */ 34551195e687SMark J Musante if (flags.dryrun) { 34561195e687SMark J Musante memory_err = B_FALSE; 34571195e687SMark J Musante freelist = B_FALSE; 34581195e687SMark J Musante goto out; 34591195e687SMark J Musante } 34601195e687SMark J Musante 34611195e687SMark J Musante /* now build up the config list & call the ioctl */ 34621195e687SMark J Musante if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0) 34631195e687SMark J Musante goto out; 34641195e687SMark J Musante 34651195e687SMark J Musante if (nvlist_add_nvlist(newconfig, 34661195e687SMark J Musante ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 || 34671195e687SMark J Musante nvlist_add_string(newconfig, 34681195e687SMark J Musante ZPOOL_CONFIG_POOL_NAME, newname) != 0 || 34691195e687SMark J Musante nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0) 34701195e687SMark J Musante goto out; 34711195e687SMark J Musante 34721195e687SMark J Musante /* 34731195e687SMark J Musante * The new pool is automatically part of the namespace unless we 34741195e687SMark J Musante * explicitly export it. 34751195e687SMark J Musante */ 34761195e687SMark J Musante if (!flags.import) 34771195e687SMark J Musante zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT; 34781195e687SMark J Musante (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 34791195e687SMark J Musante (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string)); 34801195e687SMark J Musante if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0) 34811195e687SMark J Musante goto out; 34821195e687SMark J Musante if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0) 34831195e687SMark J Musante goto out; 34841195e687SMark J Musante 34851195e687SMark J Musante if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) { 34861195e687SMark J Musante retval = zpool_standard_error(hdl, errno, msg); 34871195e687SMark J Musante goto out; 34881195e687SMark J Musante } 34891195e687SMark J Musante 34901195e687SMark J Musante freelist = B_FALSE; 34911195e687SMark J Musante memory_err = B_FALSE; 34921195e687SMark J Musante 34931195e687SMark J Musante out: 34941195e687SMark J Musante if (varray != NULL) { 34951195e687SMark J Musante int v; 34961195e687SMark J Musante 34971195e687SMark J Musante for (v = 0; v < vcount; v++) 34981195e687SMark J Musante nvlist_free(varray[v]); 34991195e687SMark J Musante free(varray); 35001195e687SMark J Musante } 35011195e687SMark J Musante zcmd_free_nvlists(&zc); 3502aab83bb8SJosef 'Jeff' Sipek nvlist_free(zc_props); 3503aab83bb8SJosef 'Jeff' Sipek nvlist_free(newconfig); 35041195e687SMark J Musante if (freelist) { 35051195e687SMark J Musante nvlist_free(*newroot); 35061195e687SMark J Musante *newroot = NULL; 35071195e687SMark J Musante } 35081195e687SMark J Musante 35091195e687SMark J Musante if (retval != 0) 35101195e687SMark J Musante return (retval); 35111195e687SMark J Musante 35121195e687SMark J Musante if (memory_err) 35131195e687SMark J Musante return (no_memory(hdl)); 35141195e687SMark J Musante 35151195e687SMark J Musante return (0); 35161195e687SMark J Musante } 35171195e687SMark J Musante 351899653d4eSeschrock /* 35195cabbc6bSPrashanth Sreenivasa * Remove the given device. 352099653d4eSeschrock */ 352199653d4eSeschrock int 352299653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 352399653d4eSeschrock { 352499653d4eSeschrock zfs_cmd_t zc = { 0 }; 352599653d4eSeschrock char msg[1024]; 352699653d4eSeschrock nvlist_t *tgt; 352788ecc943SGeorge Wilson boolean_t avail_spare, l2cache, islog; 352899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 352988ecc943SGeorge Wilson uint64_t version; 353099653d4eSeschrock 353199653d4eSeschrock (void) snprintf(msg, sizeof (msg), 353299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 353399653d4eSeschrock 353499653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3535ee0eb9f2SEric Schrock if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 35365cabbc6bSPrashanth Sreenivasa &islog)) == NULL) 353799653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 353899653d4eSeschrock 353988ecc943SGeorge Wilson version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 354088ecc943SGeorge Wilson if (islog && version < SPA_VERSION_HOLES) { 354188ecc943SGeorge Wilson zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35425cabbc6bSPrashanth Sreenivasa "pool must be upgraded to support log removal")); 354388ecc943SGeorge Wilson return (zfs_error(hdl, EZFS_BADVERSION, msg)); 354488ecc943SGeorge Wilson } 354588ecc943SGeorge Wilson 35465cabbc6bSPrashanth Sreenivasa zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID); 35475cabbc6bSPrashanth Sreenivasa 35485cabbc6bSPrashanth Sreenivasa if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 35495cabbc6bSPrashanth Sreenivasa return (0); 35505cabbc6bSPrashanth Sreenivasa 35515cabbc6bSPrashanth Sreenivasa switch (errno) { 35525cabbc6bSPrashanth Sreenivasa 35535cabbc6bSPrashanth Sreenivasa case EINVAL: 35545cabbc6bSPrashanth Sreenivasa zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35555cabbc6bSPrashanth Sreenivasa "invalid config; all top-level vdevs must " 35565cabbc6bSPrashanth Sreenivasa "have the same sector size and not be raidz.")); 35575cabbc6bSPrashanth Sreenivasa (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 35585cabbc6bSPrashanth Sreenivasa break; 35595cabbc6bSPrashanth Sreenivasa 35605cabbc6bSPrashanth Sreenivasa case EBUSY: 35615cabbc6bSPrashanth Sreenivasa zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 35625cabbc6bSPrashanth Sreenivasa "Pool busy; removal may already be in progress")); 35635cabbc6bSPrashanth Sreenivasa (void) zfs_error(hdl, EZFS_BUSY, msg); 35645cabbc6bSPrashanth Sreenivasa break; 35655cabbc6bSPrashanth Sreenivasa 35665cabbc6bSPrashanth Sreenivasa default: 35675cabbc6bSPrashanth Sreenivasa (void) zpool_standard_error(hdl, errno, msg); 35685cabbc6bSPrashanth Sreenivasa } 35695cabbc6bSPrashanth Sreenivasa return (-1); 35705cabbc6bSPrashanth Sreenivasa } 35715cabbc6bSPrashanth Sreenivasa 35725cabbc6bSPrashanth Sreenivasa int 35735cabbc6bSPrashanth Sreenivasa zpool_vdev_remove_cancel(zpool_handle_t *zhp) 35745cabbc6bSPrashanth Sreenivasa { 35755cabbc6bSPrashanth Sreenivasa zfs_cmd_t zc = { 0 }; 35765cabbc6bSPrashanth Sreenivasa char msg[1024]; 35775cabbc6bSPrashanth Sreenivasa libzfs_handle_t *hdl = zhp->zpool_hdl; 35785cabbc6bSPrashanth Sreenivasa 35795cabbc6bSPrashanth Sreenivasa (void) snprintf(msg, sizeof (msg), 35805cabbc6bSPrashanth Sreenivasa dgettext(TEXT_DOMAIN, "cannot cancel removal")); 35815cabbc6bSPrashanth Sreenivasa 35825cabbc6bSPrashanth Sreenivasa (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 35835cabbc6bSPrashanth Sreenivasa zc.zc_cookie = 1; 358499653d4eSeschrock 3585ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 358699653d4eSeschrock return (0); 358799653d4eSeschrock 358899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 3589ea8dc4b6Seschrock } 3590ea8dc4b6Seschrock 35915cabbc6bSPrashanth Sreenivasa int 35925cabbc6bSPrashanth Sreenivasa zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path, 35935cabbc6bSPrashanth Sreenivasa uint64_t *sizep) 35945cabbc6bSPrashanth Sreenivasa { 35955cabbc6bSPrashanth Sreenivasa char msg[1024]; 35965cabbc6bSPrashanth Sreenivasa nvlist_t *tgt; 35975cabbc6bSPrashanth Sreenivasa boolean_t avail_spare, l2cache, islog; 35985cabbc6bSPrashanth Sreenivasa libzfs_handle_t *hdl = zhp->zpool_hdl; 35995cabbc6bSPrashanth Sreenivasa 36005cabbc6bSPrashanth Sreenivasa (void) snprintf(msg, sizeof (msg), 36015cabbc6bSPrashanth Sreenivasa dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"), 36025cabbc6bSPrashanth Sreenivasa path); 36035cabbc6bSPrashanth Sreenivasa 36045cabbc6bSPrashanth Sreenivasa if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache, 36055cabbc6bSPrashanth Sreenivasa &islog)) == NULL) 36065cabbc6bSPrashanth Sreenivasa return (zfs_error(hdl, EZFS_NODEVICE, msg)); 36075cabbc6bSPrashanth Sreenivasa 36085cabbc6bSPrashanth Sreenivasa if (avail_spare || l2cache || islog) { 36095cabbc6bSPrashanth Sreenivasa *sizep = 0; 36105cabbc6bSPrashanth Sreenivasa return (0); 36115cabbc6bSPrashanth Sreenivasa } 36125cabbc6bSPrashanth Sreenivasa 36135cabbc6bSPrashanth Sreenivasa if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) { 36145cabbc6bSPrashanth Sreenivasa zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 36155cabbc6bSPrashanth Sreenivasa "indirect size not available")); 36165cabbc6bSPrashanth Sreenivasa return (zfs_error(hdl, EINVAL, msg)); 36175cabbc6bSPrashanth Sreenivasa } 36185cabbc6bSPrashanth Sreenivasa return (0); 36195cabbc6bSPrashanth Sreenivasa } 36205cabbc6bSPrashanth Sreenivasa 3621ea8dc4b6Seschrock /* 3622ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 3623ea8dc4b6Seschrock */ 3624ea8dc4b6Seschrock int 3625468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl) 3626ea8dc4b6Seschrock { 3627ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 3628ea8dc4b6Seschrock char msg[1024]; 362999653d4eSeschrock nvlist_t *tgt; 36305dafeea3SPavel Zakharov zpool_load_policy_t policy; 3631fa94a07fSbrendan boolean_t avail_spare, l2cache; 363299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 3633468c413aSTim Haley nvlist_t *nvi = NULL; 36344b964adaSGeorge Wilson int error; 3635ea8dc4b6Seschrock 3636ea8dc4b6Seschrock if (path) 3637ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 3638ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 3639e9dbad6fSeschrock path); 3640ea8dc4b6Seschrock else 3641ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 3642ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 3643ea8dc4b6Seschrock zhp->zpool_name); 3644ea8dc4b6Seschrock 3645ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 364699653d4eSeschrock if (path) { 3647fa94a07fSbrendan if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, 36485cabbc6bSPrashanth Sreenivasa &l2cache, NULL)) == NULL) 364999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 3650ea8dc4b6Seschrock 3651fa94a07fSbrendan /* 3652fa94a07fSbrendan * Don't allow error clearing for hot spares. Do allow 3653fa94a07fSbrendan * error clearing for l2cache devices. 3654fa94a07fSbrendan */ 3655a43d325bSek if (avail_spare) 365699653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 3657ea8dc4b6Seschrock 365899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 365999653d4eSeschrock &zc.zc_guid) == 0); 3660fa9e4066Sahrens } 3661fa9e4066Sahrens 36625dafeea3SPavel Zakharov zpool_get_load_policy(rewindnvl, &policy); 36635dafeea3SPavel Zakharov zc.zc_cookie = policy.zlp_rewind; 3664468c413aSTim Haley 366557f304caSGeorge Wilson if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0) 3666468c413aSTim Haley return (-1); 3667468c413aSTim Haley 3668cb04b873SMark J Musante if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0) 3669468c413aSTim Haley return (-1); 3670468c413aSTim Haley 36714b964adaSGeorge Wilson while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 && 36724b964adaSGeorge Wilson errno == ENOMEM) { 36734b964adaSGeorge Wilson if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 36744b964adaSGeorge Wilson zcmd_free_nvlists(&zc); 36754b964adaSGeorge Wilson return (-1); 36764b964adaSGeorge Wilson } 36774b964adaSGeorge Wilson } 36784b964adaSGeorge Wilson 36795dafeea3SPavel Zakharov if (!error || ((policy.zlp_rewind & ZPOOL_TRY_REWIND) && 3680468c413aSTim Haley errno != EPERM && errno != EACCES)) { 36815dafeea3SPavel Zakharov if (policy.zlp_rewind & 3682468c413aSTim Haley (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) { 3683468c413aSTim Haley (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi); 3684468c413aSTim Haley zpool_rewind_exclaim(hdl, zc.zc_name, 36855dafeea3SPavel Zakharov ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0), 3686468c413aSTim Haley nvi); 3687468c413aSTim Haley nvlist_free(nvi); 3688468c413aSTim Haley } 3689468c413aSTim Haley zcmd_free_nvlists(&zc); 369099653d4eSeschrock return (0); 3691468c413aSTim Haley } 369299653d4eSeschrock 3693468c413aSTim Haley zcmd_free_nvlists(&zc); 369499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 3695fa9e4066Sahrens } 3696fa9e4066Sahrens 36973d7072f8Seschrock /* 36983d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 36993d7072f8Seschrock */ 37003d7072f8Seschrock int 37013d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 37023d7072f8Seschrock { 37033d7072f8Seschrock zfs_cmd_t zc = { 0 }; 37043d7072f8Seschrock char msg[1024]; 37053d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 37063d7072f8Seschrock 37073d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 37083d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 37093d7072f8Seschrock guid); 37103d7072f8Seschrock 37113d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 37123d7072f8Seschrock zc.zc_guid = guid; 371314f8ce41SVictor Latushkin zc.zc_cookie = ZPOOL_NO_REWIND; 37143d7072f8Seschrock 37153d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 37163d7072f8Seschrock return (0); 37173d7072f8Seschrock 37183d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 37193d7072f8Seschrock } 37203d7072f8Seschrock 3721e9103aaeSGarrett D'Amore /* 3722e9103aaeSGarrett D'Amore * Change the GUID for a pool. 3723e9103aaeSGarrett D'Amore */ 3724e9103aaeSGarrett D'Amore int 3725e9103aaeSGarrett D'Amore zpool_reguid(zpool_handle_t *zhp) 3726e9103aaeSGarrett D'Amore { 3727e9103aaeSGarrett D'Amore char msg[1024]; 3728e9103aaeSGarrett D'Amore libzfs_handle_t *hdl = zhp->zpool_hdl; 3729e9103aaeSGarrett D'Amore zfs_cmd_t zc = { 0 }; 3730e9103aaeSGarrett D'Amore 3731e9103aaeSGarrett D'Amore (void) snprintf(msg, sizeof (msg), 3732e9103aaeSGarrett D'Amore dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name); 3733e9103aaeSGarrett D'Amore 3734e9103aaeSGarrett D'Amore (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3735e9103aaeSGarrett D'Amore if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0) 3736e9103aaeSGarrett D'Amore return (0); 3737e9103aaeSGarrett D'Amore 3738e9103aaeSGarrett D'Amore return (zpool_standard_error(hdl, errno, msg)); 3739e9103aaeSGarrett D'Amore } 3740e9103aaeSGarrett D'Amore 37414263d13fSGeorge Wilson /* 37424263d13fSGeorge Wilson * Reopen the pool. 37434263d13fSGeorge Wilson */ 37444263d13fSGeorge Wilson int 37454263d13fSGeorge Wilson zpool_reopen(zpool_handle_t *zhp) 37464263d13fSGeorge Wilson { 37474263d13fSGeorge Wilson zfs_cmd_t zc = { 0 }; 37484263d13fSGeorge Wilson char msg[1024]; 37494263d13fSGeorge Wilson libzfs_handle_t *hdl = zhp->zpool_hdl; 37504263d13fSGeorge Wilson 37514263d13fSGeorge Wilson (void) snprintf(msg, sizeof (msg), 37524263d13fSGeorge Wilson dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), 37534263d13fSGeorge Wilson zhp->zpool_name); 37544263d13fSGeorge Wilson 37554263d13fSGeorge Wilson (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 37564263d13fSGeorge Wilson if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0) 37574263d13fSGeorge Wilson return (0); 37584263d13fSGeorge Wilson return (zpool_standard_error(hdl, errno, msg)); 37594263d13fSGeorge Wilson } 37604263d13fSGeorge Wilson 37619c2acf00SAlek Pinchuk /* call into libzfs_core to execute the sync IOCTL per pool */ 37629c2acf00SAlek Pinchuk int 37639c2acf00SAlek Pinchuk zpool_sync_one(zpool_handle_t *zhp, void *data) 37649c2acf00SAlek Pinchuk { 37659c2acf00SAlek Pinchuk int ret; 37669c2acf00SAlek Pinchuk libzfs_handle_t *hdl = zpool_get_handle(zhp); 37679c2acf00SAlek Pinchuk const char *pool_name = zpool_get_name(zhp); 37689c2acf00SAlek Pinchuk boolean_t *force = data; 37699c2acf00SAlek Pinchuk nvlist_t *innvl = fnvlist_alloc(); 37709c2acf00SAlek Pinchuk 37719c2acf00SAlek Pinchuk fnvlist_add_boolean_value(innvl, "force", *force); 37729c2acf00SAlek Pinchuk if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) { 37739c2acf00SAlek Pinchuk nvlist_free(innvl); 37749c2acf00SAlek Pinchuk return (zpool_standard_error_fmt(hdl, ret, 37759c2acf00SAlek Pinchuk dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name)); 37769c2acf00SAlek Pinchuk } 37779c2acf00SAlek Pinchuk nvlist_free(innvl); 37789c2acf00SAlek Pinchuk 37799c2acf00SAlek Pinchuk return (0); 37809c2acf00SAlek Pinchuk } 37819c2acf00SAlek Pinchuk 3782c67d9675Seschrock /* 3783c67d9675Seschrock * Convert from a devid string to a path. 3784c67d9675Seschrock */ 3785c67d9675Seschrock static char * 3786c67d9675Seschrock devid_to_path(char *devid_str) 3787c67d9675Seschrock { 3788c67d9675Seschrock ddi_devid_t devid; 3789c67d9675Seschrock char *minor; 3790c67d9675Seschrock char *path; 3791c67d9675Seschrock devid_nmlist_t *list = NULL; 3792c67d9675Seschrock int ret; 3793c67d9675Seschrock 3794c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 3795c67d9675Seschrock return (NULL); 3796c67d9675Seschrock 3797c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 3798c67d9675Seschrock 3799c67d9675Seschrock devid_str_free(minor); 3800c67d9675Seschrock devid_free(devid); 3801c67d9675Seschrock 3802c67d9675Seschrock if (ret != 0) 3803c67d9675Seschrock return (NULL); 3804c67d9675Seschrock 3805078266a5SMarcel Telka /* 3806078266a5SMarcel Telka * In a case the strdup() fails, we will just return NULL below. 3807078266a5SMarcel Telka */ 3808078266a5SMarcel Telka path = strdup(list[0].devname); 380999653d4eSeschrock 3810c67d9675Seschrock devid_free_nmlist(list); 3811c67d9675Seschrock 3812c67d9675Seschrock return (path); 3813c67d9675Seschrock } 3814c67d9675Seschrock 3815c67d9675Seschrock /* 3816c67d9675Seschrock * Convert from a path to a devid string. 3817c67d9675Seschrock */ 3818c67d9675Seschrock static char * 3819c67d9675Seschrock path_to_devid(const char *path) 3820c67d9675Seschrock { 3821c67d9675Seschrock int fd; 3822c67d9675Seschrock ddi_devid_t devid; 3823c67d9675Seschrock char *minor, *ret; 3824c67d9675Seschrock 3825c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 3826c67d9675Seschrock return (NULL); 3827c67d9675Seschrock 3828c67d9675Seschrock minor = NULL; 3829c67d9675Seschrock ret = NULL; 3830c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 3831c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 3832c67d9675Seschrock ret = devid_str_encode(devid, minor); 3833c67d9675Seschrock if (minor != NULL) 3834c67d9675Seschrock devid_str_free(minor); 3835c67d9675Seschrock devid_free(devid); 3836c67d9675Seschrock } 3837c67d9675Seschrock (void) close(fd); 3838c67d9675Seschrock 3839c67d9675Seschrock return (ret); 3840c67d9675Seschrock } 3841c67d9675Seschrock 3842727feae5SJoshua M. Clulow struct path_from_physpath_walker_args { 3843727feae5SJoshua M. Clulow char *pfpwa_path; 3844727feae5SJoshua M. Clulow }; 3845727feae5SJoshua M. Clulow 3846727feae5SJoshua M. Clulow /* 3847727feae5SJoshua M. Clulow * Walker for use with di_devlink_walk(). Stores the "/dev" path of the first 3848727feae5SJoshua M. Clulow * primary devlink (i.e., the first devlink which refers to our "/devices" 3849727feae5SJoshua M. Clulow * node) and stops walking. 3850727feae5SJoshua M. Clulow */ 3851727feae5SJoshua M. Clulow static int 3852727feae5SJoshua M. Clulow path_from_physpath_walker(di_devlink_t devlink, void *arg) 3853727feae5SJoshua M. Clulow { 3854727feae5SJoshua M. Clulow struct path_from_physpath_walker_args *pfpwa = arg; 3855727feae5SJoshua M. Clulow 3856727feae5SJoshua M. Clulow if (di_devlink_type(devlink) != DI_PRIMARY_LINK) { 3857727feae5SJoshua M. Clulow return (DI_WALK_CONTINUE); 3858727feae5SJoshua M. Clulow } 3859727feae5SJoshua M. Clulow 3860727feae5SJoshua M. Clulow verify(pfpwa->pfpwa_path == NULL); 3861727feae5SJoshua M. Clulow if ((pfpwa->pfpwa_path = strdup(di_devlink_path(devlink))) != NULL) { 3862727feae5SJoshua M. Clulow return (DI_WALK_TERMINATE); 3863727feae5SJoshua M. Clulow } 3864727feae5SJoshua M. Clulow 3865727feae5SJoshua M. Clulow return (DI_WALK_CONTINUE); 3866727feae5SJoshua M. Clulow } 3867727feae5SJoshua M. Clulow 3868727feae5SJoshua M. Clulow /* 3869727feae5SJoshua M. Clulow * Search for a "/dev" path that refers to our physical path. Returns the new 3870727feae5SJoshua M. Clulow * path if one is found and it does not match the existing "path" value. If 3871727feae5SJoshua M. Clulow * the value is unchanged, or one could not be found, returns NULL. 3872727feae5SJoshua M. Clulow */ 3873727feae5SJoshua M. Clulow static char * 3874727feae5SJoshua M. Clulow path_from_physpath(libzfs_handle_t *hdl, const char *path, 3875727feae5SJoshua M. Clulow const char *physpath) 3876727feae5SJoshua M. Clulow { 3877727feae5SJoshua M. Clulow struct path_from_physpath_walker_args pfpwa; 3878727feae5SJoshua M. Clulow 3879727feae5SJoshua M. Clulow if (physpath == NULL) { 3880727feae5SJoshua M. Clulow return (NULL); 3881727feae5SJoshua M. Clulow } 3882727feae5SJoshua M. Clulow 3883727feae5SJoshua M. Clulow if (hdl->libzfs_devlink == NULL) { 3884727feae5SJoshua M. Clulow if ((hdl->libzfs_devlink = di_devlink_init(NULL, 0)) == 3885727feae5SJoshua M. Clulow DI_LINK_NIL) { 3886727feae5SJoshua M. Clulow /* 3887727feae5SJoshua M. Clulow * We may not be able to open a handle if this process 3888727feae5SJoshua M. Clulow * is insufficiently privileged, or we are too early in 3889727feae5SJoshua M. Clulow * boot for devfsadm to be ready. Ignore this error 3890727feae5SJoshua M. Clulow * and defer the path check to a subsequent run. 3891727feae5SJoshua M. Clulow */ 3892727feae5SJoshua M. Clulow return (NULL); 3893727feae5SJoshua M. Clulow } 3894727feae5SJoshua M. Clulow } 3895727feae5SJoshua M. Clulow 3896727feae5SJoshua M. Clulow pfpwa.pfpwa_path = NULL; 3897727feae5SJoshua M. Clulow (void) di_devlink_walk(hdl->libzfs_devlink, NULL, physpath, 3898727feae5SJoshua M. Clulow DI_PRIMARY_LINK, &pfpwa, path_from_physpath_walker); 3899727feae5SJoshua M. Clulow 3900727feae5SJoshua M. Clulow if (path != NULL && pfpwa.pfpwa_path != NULL && 3901727feae5SJoshua M. Clulow strcmp(path, pfpwa.pfpwa_path) == 0) { 3902727feae5SJoshua M. Clulow /* 3903727feae5SJoshua M. Clulow * If the path is already correct, no change is required. 3904727feae5SJoshua M. Clulow */ 3905727feae5SJoshua M. Clulow free(pfpwa.pfpwa_path); 3906727feae5SJoshua M. Clulow return (NULL); 3907727feae5SJoshua M. Clulow } 3908727feae5SJoshua M. Clulow 3909727feae5SJoshua M. Clulow return (pfpwa.pfpwa_path); 3910727feae5SJoshua M. Clulow } 3911727feae5SJoshua M. Clulow 3912c67d9675Seschrock /* 3913c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 3914c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 3915c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 3916c67d9675Seschrock */ 3917c67d9675Seschrock static void 3918c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 3919c67d9675Seschrock { 3920c67d9675Seschrock zfs_cmd_t zc = { 0 }; 3921c67d9675Seschrock 3922c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 3923e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 3924c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 3925ea8dc4b6Seschrock &zc.zc_guid) == 0); 3926c67d9675Seschrock 392799653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 3928c67d9675Seschrock } 3929c67d9675Seschrock 3930c67d9675Seschrock /* 3931c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 3932c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 3933c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 3934c67d9675Seschrock * trailing 's0' slice name. 3935c67d9675Seschrock * 3936c67d9675Seschrock * This routine is also responsible for identifying when disks have been 3937c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 3938c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 3939c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 3940c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 3941c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 3942c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 3943c67d9675Seschrock * of these checks. 3944c67d9675Seschrock */ 3945c67d9675Seschrock char * 394688ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, 3947663207adSDon Brady int name_flags) 3948c67d9675Seschrock { 3949dd50e0ccSTony Hutter char *path, *type, *env; 3950ea8dc4b6Seschrock uint64_t value; 3951ea8dc4b6Seschrock char buf[64]; 3952c67d9675Seschrock 3953dd50e0ccSTony Hutter /* 3954dd50e0ccSTony Hutter * vdev_name will be "root"/"root-0" for the root vdev, but it is the 3955dd50e0ccSTony Hutter * zpool name that will be displayed to the user. 3956dd50e0ccSTony Hutter */ 3957dd50e0ccSTony Hutter verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 3958dd50e0ccSTony Hutter if (zhp != NULL && strcmp(type, "root") == 0) 3959dd50e0ccSTony Hutter return (zfs_strdup(hdl, zpool_get_name(zhp))); 3960dd50e0ccSTony Hutter 3961663207adSDon Brady env = getenv("ZPOOL_VDEV_NAME_PATH"); 3962663207adSDon Brady if (env && (strtoul(env, NULL, 0) > 0 || 3963663207adSDon Brady !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2))) 3964663207adSDon Brady name_flags |= VDEV_NAME_PATH; 3965663207adSDon Brady 3966663207adSDon Brady env = getenv("ZPOOL_VDEV_NAME_GUID"); 3967663207adSDon Brady if (env && (strtoul(env, NULL, 0) > 0 || 3968663207adSDon Brady !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2))) 3969663207adSDon Brady name_flags |= VDEV_NAME_GUID; 3970663207adSDon Brady 3971663207adSDon Brady env = getenv("ZPOOL_VDEV_NAME_FOLLOW_LINKS"); 3972663207adSDon Brady if (env && (strtoul(env, NULL, 0) > 0 || 3973663207adSDon Brady !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2))) 3974663207adSDon Brady name_flags |= VDEV_NAME_FOLLOW_LINKS; 3975663207adSDon Brady 3976663207adSDon Brady if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &value) == 0 || 3977663207adSDon Brady name_flags & VDEV_NAME_GUID) { 3978663207adSDon Brady nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value); 3979663207adSDon Brady (void) snprintf(buf, sizeof (buf), "%llu", (u_longlong_t)value); 3980ea8dc4b6Seschrock path = buf; 3981ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 3982727feae5SJoshua M. Clulow vdev_stat_t *vs; 3983727feae5SJoshua M. Clulow uint_t vsc; 3984727feae5SJoshua M. Clulow char *newpath = NULL; 3985727feae5SJoshua M. Clulow char *physpath = NULL; 3986727feae5SJoshua M. Clulow char *devid = NULL; 3987c67d9675Seschrock 39883d7072f8Seschrock /* 39893d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 39903d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 39913d7072f8Seschrock * open a misbehaving device, which can have undesirable 39923d7072f8Seschrock * effects. 39933d7072f8Seschrock */ 3994727feae5SJoshua M. Clulow if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 39953d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 3996727feae5SJoshua M. Clulow vs->vs_state < VDEV_STATE_DEGRADED || 3997727feae5SJoshua M. Clulow zhp == NULL) { 3998727feae5SJoshua M. Clulow goto after_open; 3999727feae5SJoshua M. Clulow } 4000727feae5SJoshua M. Clulow 4001727feae5SJoshua M. Clulow if (nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 4002c67d9675Seschrock /* 4003727feae5SJoshua M. Clulow * This vdev has a devid. We can use it to check the 4004727feae5SJoshua M. Clulow * current path. 4005c67d9675Seschrock */ 4006c67d9675Seschrock char *newdevid = path_to_devid(path); 4007c67d9675Seschrock 4008727feae5SJoshua M. Clulow if (newdevid == NULL || strcmp(devid, newdevid) != 0) { 4009727feae5SJoshua M. Clulow newpath = devid_to_path(devid); 4010c67d9675Seschrock } 4011c67d9675Seschrock 4012727feae5SJoshua M. Clulow if (newdevid != NULL) 401399653d4eSeschrock devid_str_free(newdevid); 4014727feae5SJoshua M. Clulow 4015727feae5SJoshua M. Clulow } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PHYS_PATH, 4016727feae5SJoshua M. Clulow &physpath) == 0) { 4017727feae5SJoshua M. Clulow /* 4018727feae5SJoshua M. Clulow * This vdev does not have a devid, but it does have a 4019727feae5SJoshua M. Clulow * physical path. Attempt to translate this to a /dev 4020727feae5SJoshua M. Clulow * path. 4021727feae5SJoshua M. Clulow */ 4022727feae5SJoshua M. Clulow newpath = path_from_physpath(hdl, path, physpath); 4023727feae5SJoshua M. Clulow } 4024727feae5SJoshua M. Clulow 4025727feae5SJoshua M. Clulow if (newpath != NULL) { 4026727feae5SJoshua M. Clulow /* 4027727feae5SJoshua M. Clulow * Update the path appropriately. 4028727feae5SJoshua M. Clulow */ 4029727feae5SJoshua M. Clulow set_path(zhp, nv, newpath); 4030727feae5SJoshua M. Clulow if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, 4031727feae5SJoshua M. Clulow newpath) == 0) { 4032727feae5SJoshua M. Clulow verify(nvlist_lookup_string(nv, 4033727feae5SJoshua M. Clulow ZPOOL_CONFIG_PATH, &path) == 0); 4034727feae5SJoshua M. Clulow } 4035727feae5SJoshua M. Clulow free(newpath); 4036c67d9675Seschrock } 4037c67d9675Seschrock 4038663207adSDon Brady if (name_flags & VDEV_NAME_FOLLOW_LINKS) { 4039663207adSDon Brady char *rp = realpath(path, NULL); 4040663207adSDon Brady if (rp) { 4041663207adSDon Brady strlcpy(buf, rp, sizeof (buf)); 4042663207adSDon Brady path = buf; 4043663207adSDon Brady free(rp); 4044663207adSDon Brady } 4045663207adSDon Brady } 4046663207adSDon Brady 4047727feae5SJoshua M. Clulow after_open: 40486401734dSWill Andrews if (strncmp(path, ZFS_DISK_ROOTD, strlen(ZFS_DISK_ROOTD)) == 0) 40496401734dSWill Andrews path += strlen(ZFS_DISK_ROOTD); 4050c67d9675Seschrock 4051663207adSDon Brady /* 4052663207adSDon Brady * Remove the partition from the path it this is a whole disk. 4053663207adSDon Brady */ 4054663207adSDon Brady if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &value) 4055663207adSDon Brady == 0 && value && !(name_flags & VDEV_NAME_PATH)) { 40563fdda499SJohn Harres int pathlen = strlen(path); 405799653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 40583fdda499SJohn Harres 40593fdda499SJohn Harres /* 40607855d95bSToomas Soome * If it starts with c#, and ends with "s0" or "s1", 40617855d95bSToomas Soome * chop the slice off, or if it ends with "s0/old" or 40627855d95bSToomas Soome * "s1/old", remove the slice from the middle. 40633fdda499SJohn Harres */ 40643fdda499SJohn Harres if (CTD_CHECK(tmp)) { 40657855d95bSToomas Soome if (strcmp(&tmp[pathlen - 2], "s0") == 0 || 40667855d95bSToomas Soome strcmp(&tmp[pathlen - 2], "s1") == 0) { 40673fdda499SJohn Harres tmp[pathlen - 2] = '\0'; 40683fdda499SJohn Harres } else if (pathlen > 6 && 40697855d95bSToomas Soome (strcmp(&tmp[pathlen - 6], "s0/old") == 0 || 40707855d95bSToomas Soome strcmp(&tmp[pathlen - 6], "s1/old") == 0)) { 40713fdda499SJohn Harres (void) strcpy(&tmp[pathlen - 6], 40723fdda499SJohn Harres "/old"); 40733fdda499SJohn Harres } 40743fdda499SJohn Harres } 4075c67d9675Seschrock return (tmp); 4076c67d9675Seschrock } 4077c67d9675Seschrock } else { 4078dd50e0ccSTony Hutter path = type; 407999653d4eSeschrock 408099653d4eSeschrock /* 408199653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 408299653d4eSeschrock */ 408399653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 408499653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 408599653d4eSeschrock &value) == 0); 408699653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 40875ad82045Snd (u_longlong_t)value); 408899653d4eSeschrock path = buf; 408999653d4eSeschrock } 409088ecc943SGeorge Wilson 409188ecc943SGeorge Wilson /* 409288ecc943SGeorge Wilson * We identify each top-level vdev by using a <type-id> 409388ecc943SGeorge Wilson * naming convention. 409488ecc943SGeorge Wilson */ 4095663207adSDon Brady if (name_flags & VDEV_NAME_TYPE_ID) { 409688ecc943SGeorge Wilson uint64_t id; 409788ecc943SGeorge Wilson 409888ecc943SGeorge Wilson verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID, 409988ecc943SGeorge Wilson &id) == 0); 410088ecc943SGeorge Wilson (void) snprintf(buf, sizeof (buf), "%s-%llu", path, 410188ecc943SGeorge Wilson (u_longlong_t)id); 410288ecc943SGeorge Wilson path = buf; 410388ecc943SGeorge Wilson } 4104c67d9675Seschrock } 4105c67d9675Seschrock 410699653d4eSeschrock return (zfs_strdup(hdl, path)); 4107c67d9675Seschrock } 4108ea8dc4b6Seschrock 4109ea8dc4b6Seschrock static int 4110a2cdcdd2SPaul Dagnelie zbookmark_mem_compare(const void *a, const void *b) 4111ea8dc4b6Seschrock { 41127802d7bfSMatthew Ahrens return (memcmp(a, b, sizeof (zbookmark_phys_t))); 4113ea8dc4b6Seschrock } 4114ea8dc4b6Seschrock 4115ea8dc4b6Seschrock /* 4116ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 4117ea8dc4b6Seschrock * caller. 4118ea8dc4b6Seschrock */ 4119ea8dc4b6Seschrock int 412055434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 4121ea8dc4b6Seschrock { 4122ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 4123ea8dc4b6Seschrock uint64_t count; 41247802d7bfSMatthew Ahrens zbookmark_phys_t *zb = NULL; 412555434c77Sek int i; 4126ea8dc4b6Seschrock 4127ea8dc4b6Seschrock /* 4128ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 4129ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 4130ea8dc4b6Seschrock * entire list. 4131ea8dc4b6Seschrock */ 4132ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 4133ea8dc4b6Seschrock &count) == 0); 413475519f38Sek if (count == 0) 413575519f38Sek return (0); 4136e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 41377802d7bfSMatthew Ahrens count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL) 413899653d4eSeschrock return (-1); 4139e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 4140ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 4141ea8dc4b6Seschrock for (;;) { 414299653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 414399653d4eSeschrock &zc) != 0) { 4144e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 4145ea8dc4b6Seschrock if (errno == ENOMEM) { 41467802d7bfSMatthew Ahrens void *dst; 41477802d7bfSMatthew Ahrens 4148bf561db0Svb count = zc.zc_nvlist_dst_size; 41497802d7bfSMatthew Ahrens dst = zfs_alloc(zhp->zpool_hdl, count * 41507802d7bfSMatthew Ahrens sizeof (zbookmark_phys_t)); 41517802d7bfSMatthew Ahrens if (dst == NULL) 415299653d4eSeschrock return (-1); 41537802d7bfSMatthew Ahrens zc.zc_nvlist_dst = (uintptr_t)dst; 4154ea8dc4b6Seschrock } else { 4155ea8dc4b6Seschrock return (-1); 4156ea8dc4b6Seschrock } 4157ea8dc4b6Seschrock } else { 4158ea8dc4b6Seschrock break; 4159ea8dc4b6Seschrock } 4160ea8dc4b6Seschrock } 4161ea8dc4b6Seschrock 4162ea8dc4b6Seschrock /* 4163ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 4164ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 4165e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 4166ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 4167ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 4168ea8dc4b6Seschrock */ 41697802d7bfSMatthew Ahrens zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) + 4170e9dbad6fSeschrock zc.zc_nvlist_dst_size; 4171e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 4172ea8dc4b6Seschrock 4173a2cdcdd2SPaul Dagnelie qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_mem_compare); 4174ea8dc4b6Seschrock 417555434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 4176ea8dc4b6Seschrock 4177ea8dc4b6Seschrock /* 417855434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 4179ea8dc4b6Seschrock */ 4180ea8dc4b6Seschrock for (i = 0; i < count; i++) { 4181ea8dc4b6Seschrock nvlist_t *nv; 4182ea8dc4b6Seschrock 4183c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 4184c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 4185c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 4186ea8dc4b6Seschrock continue; 4187ea8dc4b6Seschrock 418855434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 418955434c77Sek goto nomem; 419055434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 419155434c77Sek zb[i].zb_objset) != 0) { 419255434c77Sek nvlist_free(nv); 419399653d4eSeschrock goto nomem; 4194ea8dc4b6Seschrock } 419555434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 419655434c77Sek zb[i].zb_object) != 0) { 419755434c77Sek nvlist_free(nv); 419855434c77Sek goto nomem; 419955434c77Sek } 420055434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 420155434c77Sek nvlist_free(nv); 420255434c77Sek goto nomem; 420355434c77Sek } 420455434c77Sek nvlist_free(nv); 4205ea8dc4b6Seschrock } 4206ea8dc4b6Seschrock 42073ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 4208ea8dc4b6Seschrock return (0); 420999653d4eSeschrock 421099653d4eSeschrock nomem: 4211e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 421299653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 4213ea8dc4b6Seschrock } 4214eaca9bbdSeschrock 4215eaca9bbdSeschrock /* 4216eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 4217eaca9bbdSeschrock */ 4218eaca9bbdSeschrock int 4219990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) 4220eaca9bbdSeschrock { 4221eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 422299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 4223eaca9bbdSeschrock 4224eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 4225990b4856Slling zc.zc_cookie = new_version; 4226990b4856Slling 4227ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 4228ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 422999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 423099653d4eSeschrock zhp->zpool_name)); 4231eaca9bbdSeschrock return (0); 4232eaca9bbdSeschrock } 423306eeb2adSek 423406eeb2adSek void 42354445fffbSMatthew Ahrens zfs_save_arguments(int argc, char **argv, char *string, int len) 423606eeb2adSek { 42374445fffbSMatthew Ahrens (void) strlcpy(string, basename(argv[0]), len); 42384445fffbSMatthew Ahrens for (int i = 1; i < argc; i++) { 42394445fffbSMatthew Ahrens (void) strlcat(string, " ", len); 42404445fffbSMatthew Ahrens (void) strlcat(string, argv[i], len); 42412a6b87f0Sek } 42422a6b87f0Sek } 42432a6b87f0Sek 42442a6b87f0Sek int 42454445fffbSMatthew Ahrens zpool_log_history(libzfs_handle_t *hdl, const char *message) 42462a6b87f0Sek { 42474445fffbSMatthew Ahrens zfs_cmd_t zc = { 0 }; 42484445fffbSMatthew Ahrens nvlist_t *args; 42494445fffbSMatthew Ahrens int err; 42504445fffbSMatthew Ahrens 42514445fffbSMatthew Ahrens args = fnvlist_alloc(); 42524445fffbSMatthew Ahrens fnvlist_add_string(args, "message", message); 42534445fffbSMatthew Ahrens err = zcmd_write_src_nvlist(hdl, &zc, args); 42544445fffbSMatthew Ahrens if (err == 0) 42554445fffbSMatthew Ahrens err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc); 42564445fffbSMatthew Ahrens nvlist_free(args); 42574445fffbSMatthew Ahrens zcmd_free_nvlists(&zc); 42584445fffbSMatthew Ahrens return (err); 425906eeb2adSek } 426006eeb2adSek 426106eeb2adSek /* 426206eeb2adSek * Perform ioctl to get some command history of a pool. 426306eeb2adSek * 426406eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 426506eeb2adSek * logical offset of the history buffer to start reading from. 426606eeb2adSek * 426706eeb2adSek * Upon return, 'off' is the next logical offset to read from and 426806eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 426906eeb2adSek */ 427006eeb2adSek static int 427106eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 427206eeb2adSek { 427306eeb2adSek zfs_cmd_t zc = { 0 }; 427406eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 427506eeb2adSek 427606eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 427706eeb2adSek 427806eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 427906eeb2adSek zc.zc_history_len = *len; 428006eeb2adSek zc.zc_history_offset = *off; 428106eeb2adSek 428206eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 428306eeb2adSek switch (errno) { 428406eeb2adSek case EPERM: 4285ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 4286ece3d9b3Slling dgettext(TEXT_DOMAIN, 428706eeb2adSek "cannot show history for pool '%s'"), 428806eeb2adSek zhp->zpool_name)); 428906eeb2adSek case ENOENT: 4290ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 429106eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 429206eeb2adSek "'%s'"), zhp->zpool_name)); 4293d7306b64Sek case ENOTSUP: 4294d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 4295d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 4296d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 429706eeb2adSek default: 4298ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 429906eeb2adSek dgettext(TEXT_DOMAIN, 430006eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 430106eeb2adSek } 430206eeb2adSek } 430306eeb2adSek 430406eeb2adSek *len = zc.zc_history_len; 430506eeb2adSek *off = zc.zc_history_offset; 430606eeb2adSek 430706eeb2adSek return (0); 430806eeb2adSek } 430906eeb2adSek 431006eeb2adSek /* 431106eeb2adSek * Retrieve the command history of a pool. 431206eeb2adSek */ 431306eeb2adSek int 4314a52121eaSChunwei Chen zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp, uint64_t *off, 4315a52121eaSChunwei Chen boolean_t *eof) 431606eeb2adSek { 43173339867aSMatthew Ahrens char *buf; 43183339867aSMatthew Ahrens int buflen = 128 * 1024; 431906eeb2adSek nvlist_t **records = NULL; 432006eeb2adSek uint_t numrecords = 0; 4321a52121eaSChunwei Chen int err = 0, i; 4322a52121eaSChunwei Chen uint64_t start = *off; 432306eeb2adSek 43243339867aSMatthew Ahrens buf = malloc(buflen); 43253339867aSMatthew Ahrens if (buf == NULL) 43263339867aSMatthew Ahrens return (ENOMEM); 4327a52121eaSChunwei Chen /* process about 1MB a time */ 4328a52121eaSChunwei Chen while (*off - start < 1024 * 1024) { 43293339867aSMatthew Ahrens uint64_t bytes_read = buflen; 433006eeb2adSek uint64_t leftover; 433106eeb2adSek 4332a52121eaSChunwei Chen if ((err = get_history(zhp, buf, off, &bytes_read)) != 0) 433306eeb2adSek break; 433406eeb2adSek 433506eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 4336a52121eaSChunwei Chen if (!bytes_read) { 4337a52121eaSChunwei Chen *eof = B_TRUE; 433806eeb2adSek break; 4339a52121eaSChunwei Chen } 434006eeb2adSek 434106eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 434206eeb2adSek &leftover, &records, &numrecords)) != 0) 434306eeb2adSek break; 4344a52121eaSChunwei Chen *off -= leftover; 43453339867aSMatthew Ahrens if (leftover == bytes_read) { 43463339867aSMatthew Ahrens /* 43473339867aSMatthew Ahrens * no progress made, because buffer is not big enough 43483339867aSMatthew Ahrens * to hold this record; resize and retry. 43493339867aSMatthew Ahrens */ 43503339867aSMatthew Ahrens buflen *= 2; 43513339867aSMatthew Ahrens free(buf); 43523339867aSMatthew Ahrens buf = malloc(buflen); 43533339867aSMatthew Ahrens if (buf == NULL) 43543339867aSMatthew Ahrens return (ENOMEM); 43553339867aSMatthew Ahrens } 4356a52121eaSChunwei Chen } 435706eeb2adSek 43583339867aSMatthew Ahrens free(buf); 43593339867aSMatthew Ahrens 436006eeb2adSek if (!err) { 436106eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 436206eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 436306eeb2adSek records, numrecords) == 0); 436406eeb2adSek } 436506eeb2adSek for (i = 0; i < numrecords; i++) 436606eeb2adSek nvlist_free(records[i]); 436706eeb2adSek free(records); 436806eeb2adSek 436906eeb2adSek return (err); 437006eeb2adSek } 437155434c77Sek 437255434c77Sek void 437355434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 437455434c77Sek char *pathname, size_t len) 437555434c77Sek { 437655434c77Sek zfs_cmd_t zc = { 0 }; 437755434c77Sek boolean_t mounted = B_FALSE; 437855434c77Sek char *mntpnt = NULL; 43799adfa60dSMatthew Ahrens char dsname[ZFS_MAX_DATASET_NAME_LEN]; 438055434c77Sek 438155434c77Sek if (dsobj == 0) { 438255434c77Sek /* special case for the MOS */ 438355434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 438455434c77Sek return; 438555434c77Sek } 438655434c77Sek 438755434c77Sek /* get the dataset's name */ 438855434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 438955434c77Sek zc.zc_obj = dsobj; 439055434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 439155434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 439255434c77Sek /* just write out a path of two object numbers */ 439355434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 439455434c77Sek dsobj, obj); 439555434c77Sek return; 439655434c77Sek } 439755434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 439855434c77Sek 439955434c77Sek /* find out if the dataset is mounted */ 440055434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 440155434c77Sek 440255434c77Sek /* get the corrupted object's path */ 440355434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 440455434c77Sek zc.zc_obj = obj; 440555434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 440655434c77Sek &zc) == 0) { 440755434c77Sek if (mounted) { 440855434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 440955434c77Sek zc.zc_value); 441055434c77Sek } else { 441155434c77Sek (void) snprintf(pathname, len, "%s:%s", 441255434c77Sek dsname, zc.zc_value); 441355434c77Sek } 441455434c77Sek } else { 441555434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 441655434c77Sek } 441755434c77Sek free(mntpnt); 441855434c77Sek } 4419b1b8ab34Slling 442015e6edf1Sgw /* 442115e6edf1Sgw * Read the EFI label from the config, if a label does not exist then 442215e6edf1Sgw * pass back the error to the caller. If the caller has passed a non-NULL 442315e6edf1Sgw * diskaddr argument then we set it to the starting address of the EFI 44247855d95bSToomas Soome * partition. If the caller has passed a non-NULL boolean argument, then 44257855d95bSToomas Soome * we set it to indicate if the disk does have efi system partition. 442615e6edf1Sgw */ 442715e6edf1Sgw static int 44287855d95bSToomas Soome read_efi_label(nvlist_t *config, diskaddr_t *sb, boolean_t *system) 442915e6edf1Sgw { 443015e6edf1Sgw char *path; 443115e6edf1Sgw int fd; 443215e6edf1Sgw char diskname[MAXPATHLEN]; 44337855d95bSToomas Soome boolean_t boot = B_FALSE; 443415e6edf1Sgw int err = -1; 44357855d95bSToomas Soome int slice; 443615e6edf1Sgw 443715e6edf1Sgw if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) 443815e6edf1Sgw return (err); 443915e6edf1Sgw 44406401734dSWill Andrews (void) snprintf(diskname, sizeof (diskname), "%s%s", ZFS_RDISK_ROOT, 444115e6edf1Sgw strrchr(path, '/')); 444215e6edf1Sgw if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 444315e6edf1Sgw struct dk_gpt *vtoc; 444415e6edf1Sgw 444515e6edf1Sgw if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { 44467855d95bSToomas Soome for (slice = 0; slice < vtoc->efi_nparts; slice++) { 44477855d95bSToomas Soome if (vtoc->efi_parts[slice].p_tag == V_SYSTEM) 44487855d95bSToomas Soome boot = B_TRUE; 44497855d95bSToomas Soome if (vtoc->efi_parts[slice].p_tag == V_USR) 44507855d95bSToomas Soome break; 44517855d95bSToomas Soome } 44527855d95bSToomas Soome if (sb != NULL && vtoc->efi_parts[slice].p_tag == V_USR) 44537855d95bSToomas Soome *sb = vtoc->efi_parts[slice].p_start; 44547855d95bSToomas Soome if (system != NULL) 44557855d95bSToomas Soome *system = boot; 445615e6edf1Sgw efi_free(vtoc); 445715e6edf1Sgw } 445815e6edf1Sgw (void) close(fd); 445915e6edf1Sgw } 446015e6edf1Sgw return (err); 446115e6edf1Sgw } 446215e6edf1Sgw 44638488aeb5Staylor /* 44648488aeb5Staylor * determine where a partition starts on a disk in the current 44658488aeb5Staylor * configuration 44668488aeb5Staylor */ 44678488aeb5Staylor static diskaddr_t 44688488aeb5Staylor find_start_block(nvlist_t *config) 44698488aeb5Staylor { 44708488aeb5Staylor nvlist_t **child; 44718488aeb5Staylor uint_t c, children; 44728488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 44738488aeb5Staylor uint64_t wholedisk; 44748488aeb5Staylor 44758488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 44768488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 44778488aeb5Staylor if (nvlist_lookup_uint64(config, 44788488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 44798488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 44808488aeb5Staylor return (MAXOFFSET_T); 44818488aeb5Staylor } 44827855d95bSToomas Soome if (read_efi_label(config, &sb, NULL) < 0) 448315e6edf1Sgw sb = MAXOFFSET_T; 44848488aeb5Staylor return (sb); 44858488aeb5Staylor } 44868488aeb5Staylor 44878488aeb5Staylor for (c = 0; c < children; c++) { 44888488aeb5Staylor sb = find_start_block(child[c]); 44898488aeb5Staylor if (sb != MAXOFFSET_T) { 44908488aeb5Staylor return (sb); 44918488aeb5Staylor } 44928488aeb5Staylor } 44938488aeb5Staylor return (MAXOFFSET_T); 44948488aeb5Staylor } 44958488aeb5Staylor 44968488aeb5Staylor /* 44978488aeb5Staylor * Label an individual disk. The name provided is the short name, 44988488aeb5Staylor * stripped of any leading /dev path. 44998488aeb5Staylor */ 45008488aeb5Staylor int 45017855d95bSToomas Soome zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name, 45027855d95bSToomas Soome zpool_boot_label_t boot_type, uint64_t boot_size, int *slice) 45038488aeb5Staylor { 45048488aeb5Staylor char path[MAXPATHLEN]; 45058488aeb5Staylor struct dk_gpt *vtoc; 45068488aeb5Staylor int fd; 45072dd124cdSToomas Soome size_t resv; 45088488aeb5Staylor uint64_t slice_size; 45098488aeb5Staylor diskaddr_t start_block; 45108488aeb5Staylor char errbuf[1024]; 45118488aeb5Staylor 4512c6ef114fSmmusante /* prepare an error message just in case */ 4513c6ef114fSmmusante (void) snprintf(errbuf, sizeof (errbuf), 4514c6ef114fSmmusante dgettext(TEXT_DOMAIN, "cannot label '%s'"), name); 4515c6ef114fSmmusante 45168488aeb5Staylor if (zhp) { 45178488aeb5Staylor nvlist_t *nvroot; 45188488aeb5Staylor 45198488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 45208488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 45218488aeb5Staylor 45228488aeb5Staylor if (zhp->zpool_start_block == 0) 45238488aeb5Staylor start_block = find_start_block(nvroot); 45248488aeb5Staylor else 45258488aeb5Staylor start_block = zhp->zpool_start_block; 45268488aeb5Staylor zhp->zpool_start_block = start_block; 45278488aeb5Staylor } else { 45288488aeb5Staylor /* new pool */ 45298488aeb5Staylor start_block = NEW_START_BLOCK; 45308488aeb5Staylor } 45318488aeb5Staylor 45326401734dSWill Andrews (void) snprintf(path, sizeof (path), "%s/%s%s", ZFS_RDISK_ROOT, name, 45338488aeb5Staylor BACKUP_SLICE); 45348488aeb5Staylor 45358488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 45368488aeb5Staylor /* 45378488aeb5Staylor * This shouldn't happen. We've long since verified that this 45388488aeb5Staylor * is a valid device. 45398488aeb5Staylor */ 4540c6ef114fSmmusante zfs_error_aux(hdl, 4541c6ef114fSmmusante dgettext(TEXT_DOMAIN, "unable to open device")); 45428488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 45438488aeb5Staylor } 45448488aeb5Staylor 45458488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 45468488aeb5Staylor /* 45478488aeb5Staylor * The only way this can fail is if we run out of memory, or we 45488488aeb5Staylor * were unable to read the disk's capacity 45498488aeb5Staylor */ 45508488aeb5Staylor if (errno == ENOMEM) 45518488aeb5Staylor (void) no_memory(hdl); 45528488aeb5Staylor 45538488aeb5Staylor (void) close(fd); 4554c6ef114fSmmusante zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4555c6ef114fSmmusante "unable to read disk capacity"), name); 45568488aeb5Staylor 45578488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 45588488aeb5Staylor } 45592dd124cdSToomas Soome resv = efi_reserved_sectors(vtoc); 45608488aeb5Staylor 45618488aeb5Staylor /* 45628488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 45638488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 45648488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 45658488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 45668488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 45678488aeb5Staylor * can get, in the absence of V_OTHER. 45688488aeb5Staylor */ 45697855d95bSToomas Soome /* first fix the partition start block */ 45707855d95bSToomas Soome if (start_block == MAXOFFSET_T) 45717855d95bSToomas Soome start_block = NEW_START_BLOCK; 45728488aeb5Staylor 45737855d95bSToomas Soome /* 45747855d95bSToomas Soome * EFI System partition is using slice 0. 45757855d95bSToomas Soome * ZFS is on slice 1 and slice 8 is reserved. 45767855d95bSToomas Soome * We assume the GPT partition table without system 45777855d95bSToomas Soome * partition has zfs p_start == NEW_START_BLOCK. 45787855d95bSToomas Soome * If start_block != NEW_START_BLOCK, it means we have 45797855d95bSToomas Soome * system partition. Correct solution would be to query/cache vtoc 45807855d95bSToomas Soome * from existing vdev member. 45817855d95bSToomas Soome */ 45827855d95bSToomas Soome if (boot_type == ZPOOL_CREATE_BOOT_LABEL) { 45837855d95bSToomas Soome if (boot_size % vtoc->efi_lbasize != 0) { 45847855d95bSToomas Soome zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 45857855d95bSToomas Soome "boot partition size must be a multiple of %d"), 45867855d95bSToomas Soome vtoc->efi_lbasize); 45877855d95bSToomas Soome (void) close(fd); 45887855d95bSToomas Soome efi_free(vtoc); 45897855d95bSToomas Soome return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 45907855d95bSToomas Soome } 45917855d95bSToomas Soome /* 45927855d95bSToomas Soome * System partition size checks. 45937855d95bSToomas Soome * Note the 1MB is quite arbitrary value, since we 45947855d95bSToomas Soome * are creating dedicated pool, it should be enough 45957855d95bSToomas Soome * to hold fat + efi bootloader. May need to be 45967855d95bSToomas Soome * adjusted if the bootloader size will grow. 45977855d95bSToomas Soome */ 45987855d95bSToomas Soome if (boot_size < 1024 * 1024) { 45997855d95bSToomas Soome char buf[64]; 46007855d95bSToomas Soome zfs_nicenum(boot_size, buf, sizeof (buf)); 46017855d95bSToomas Soome zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 46027855d95bSToomas Soome "Specified size %s for EFI System partition is too " 46037855d95bSToomas Soome "small, the minimum size is 1MB."), buf); 46047855d95bSToomas Soome (void) close(fd); 46057855d95bSToomas Soome efi_free(vtoc); 46067855d95bSToomas Soome return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 46077855d95bSToomas Soome } 46087855d95bSToomas Soome /* 33MB is tested with mkfs -F pcfs */ 46097855d95bSToomas Soome if (hdl->libzfs_printerr && 46107855d95bSToomas Soome ((vtoc->efi_lbasize == 512 && 46117855d95bSToomas Soome boot_size < 33 * 1024 * 1024) || 46127855d95bSToomas Soome (vtoc->efi_lbasize == 4096 && 46137855d95bSToomas Soome boot_size < 256 * 1024 * 1024))) { 46147855d95bSToomas Soome char buf[64]; 46157855d95bSToomas Soome zfs_nicenum(boot_size, buf, sizeof (buf)); 46167855d95bSToomas Soome (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 46177855d95bSToomas Soome "Warning: EFI System partition size %s is " 46187855d95bSToomas Soome "not allowing to create FAT32 file\nsystem, which " 46197855d95bSToomas Soome "may result in unbootable system.\n"), buf); 46207855d95bSToomas Soome } 46217855d95bSToomas Soome /* Adjust zfs partition start by size of system partition. */ 46227855d95bSToomas Soome start_block += boot_size / vtoc->efi_lbasize; 46237855d95bSToomas Soome } 46247855d95bSToomas Soome 46257855d95bSToomas Soome if (start_block == NEW_START_BLOCK) { 46267855d95bSToomas Soome /* 46277855d95bSToomas Soome * Use default layout. 46287855d95bSToomas Soome * ZFS is on slice 0 and slice 8 is reserved. 46297855d95bSToomas Soome */ 46307855d95bSToomas Soome slice_size = vtoc->efi_last_u_lba + 1; 46312dd124cdSToomas Soome slice_size -= resv; 46327855d95bSToomas Soome slice_size -= start_block; 46337855d95bSToomas Soome if (slice != NULL) 46347855d95bSToomas Soome *slice = 0; 46357855d95bSToomas Soome 46367855d95bSToomas Soome vtoc->efi_parts[0].p_start = start_block; 46377855d95bSToomas Soome vtoc->efi_parts[0].p_size = slice_size; 46387855d95bSToomas Soome 46397855d95bSToomas Soome vtoc->efi_parts[0].p_tag = V_USR; 46407855d95bSToomas Soome (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 46417855d95bSToomas Soome 46427855d95bSToomas Soome vtoc->efi_parts[8].p_start = slice_size + start_block; 46437855d95bSToomas Soome vtoc->efi_parts[8].p_size = resv; 46447855d95bSToomas Soome vtoc->efi_parts[8].p_tag = V_RESERVED; 46457855d95bSToomas Soome } else { 46467855d95bSToomas Soome slice_size = start_block - NEW_START_BLOCK; 46477855d95bSToomas Soome vtoc->efi_parts[0].p_start = NEW_START_BLOCK; 46487855d95bSToomas Soome vtoc->efi_parts[0].p_size = slice_size; 46497855d95bSToomas Soome vtoc->efi_parts[0].p_tag = V_SYSTEM; 46507855d95bSToomas Soome (void) strcpy(vtoc->efi_parts[0].p_name, "loader"); 46517855d95bSToomas Soome if (slice != NULL) 46527855d95bSToomas Soome *slice = 1; 46537855d95bSToomas Soome /* prepare slice 1 */ 46547855d95bSToomas Soome slice_size = vtoc->efi_last_u_lba + 1 - slice_size; 46557855d95bSToomas Soome slice_size -= resv; 46567855d95bSToomas Soome slice_size -= NEW_START_BLOCK; 46577855d95bSToomas Soome vtoc->efi_parts[1].p_start = start_block; 46587855d95bSToomas Soome vtoc->efi_parts[1].p_size = slice_size; 46597855d95bSToomas Soome vtoc->efi_parts[1].p_tag = V_USR; 46607855d95bSToomas Soome (void) strcpy(vtoc->efi_parts[1].p_name, "zfs"); 46617855d95bSToomas Soome 46627855d95bSToomas Soome vtoc->efi_parts[8].p_start = slice_size + start_block; 46637855d95bSToomas Soome vtoc->efi_parts[8].p_size = resv; 46647855d95bSToomas Soome vtoc->efi_parts[8].p_tag = V_RESERVED; 46657855d95bSToomas Soome } 46668488aeb5Staylor 46678488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 46688488aeb5Staylor /* 46698488aeb5Staylor * Some block drivers (like pcata) may not support EFI 46708488aeb5Staylor * GPT labels. Print out a helpful error message dir- 46718488aeb5Staylor * ecting the user to manually label the disk and give 46728488aeb5Staylor * a specific slice. 46738488aeb5Staylor */ 46748488aeb5Staylor (void) close(fd); 46758488aeb5Staylor efi_free(vtoc); 46768488aeb5Staylor 46778488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4678c6ef114fSmmusante "try using fdisk(1M) and then provide a specific slice")); 46798488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 46808488aeb5Staylor } 46818488aeb5Staylor 46828488aeb5Staylor (void) close(fd); 46838488aeb5Staylor efi_free(vtoc); 46848488aeb5Staylor return (0); 46858488aeb5Staylor } 4686e7cbe64fSgw 4687e7cbe64fSgw static boolean_t 4688e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf) 4689e7cbe64fSgw { 4690e7cbe64fSgw char *type; 4691e7cbe64fSgw nvlist_t **child; 4692e7cbe64fSgw uint_t children, c; 4693e7cbe64fSgw 4694e7cbe64fSgw verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0); 4695810e43b2SBill Pijewski if (strcmp(type, VDEV_TYPE_FILE) == 0 || 469688ecc943SGeorge Wilson strcmp(type, VDEV_TYPE_HOLE) == 0 || 4697e7cbe64fSgw strcmp(type, VDEV_TYPE_MISSING) == 0) { 4698e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4699e7cbe64fSgw "vdev type '%s' is not supported"), type); 4700e7cbe64fSgw (void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf); 4701e7cbe64fSgw return (B_FALSE); 4702e7cbe64fSgw } 4703e7cbe64fSgw if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, 4704e7cbe64fSgw &child, &children) == 0) { 4705e7cbe64fSgw for (c = 0; c < children; c++) { 4706e7cbe64fSgw if (!supported_dump_vdev_type(hdl, child[c], errbuf)) 4707e7cbe64fSgw return (B_FALSE); 4708e7cbe64fSgw } 4709e7cbe64fSgw } 4710e7cbe64fSgw return (B_TRUE); 4711e7cbe64fSgw } 4712e7cbe64fSgw 4713e7cbe64fSgw /* 4714810e43b2SBill Pijewski * Check if this zvol is allowable for use as a dump device; zero if 4715810e43b2SBill Pijewski * it is, > 0 if it isn't, < 0 if it isn't a zvol. 4716810e43b2SBill Pijewski * 4717810e43b2SBill Pijewski * Allowable storage configurations include mirrors, all raidz variants, and 4718810e43b2SBill Pijewski * pools with log, cache, and spare devices. Pools which are backed by files or 4719810e43b2SBill Pijewski * have missing/hole vdevs are not suitable. 4720e7cbe64fSgw */ 4721e7cbe64fSgw int 4722e7cbe64fSgw zvol_check_dump_config(char *arg) 4723e7cbe64fSgw { 4724e7cbe64fSgw zpool_handle_t *zhp = NULL; 4725e7cbe64fSgw nvlist_t *config, *nvroot; 4726e7cbe64fSgw char *p, *volname; 4727e7cbe64fSgw nvlist_t **top; 4728e7cbe64fSgw uint_t toplevels; 4729e7cbe64fSgw libzfs_handle_t *hdl; 4730e7cbe64fSgw char errbuf[1024]; 47319adfa60dSMatthew Ahrens char poolname[ZFS_MAX_DATASET_NAME_LEN]; 4732e7cbe64fSgw int pathlen = strlen(ZVOL_FULL_DEV_DIR); 4733e7cbe64fSgw int ret = 1; 4734e7cbe64fSgw 4735e7cbe64fSgw if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) { 4736e7cbe64fSgw return (-1); 4737e7cbe64fSgw } 4738e7cbe64fSgw 4739e7cbe64fSgw (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 4740e7cbe64fSgw "dump is not supported on device '%s'"), arg); 4741e7cbe64fSgw 4742e7cbe64fSgw if ((hdl = libzfs_init()) == NULL) 4743e7cbe64fSgw return (1); 4744e7cbe64fSgw libzfs_print_on_error(hdl, B_TRUE); 4745e7cbe64fSgw 4746e7cbe64fSgw volname = arg + pathlen; 4747e7cbe64fSgw 4748e7cbe64fSgw /* check the configuration of the pool */ 4749e7cbe64fSgw if ((p = strchr(volname, '/')) == NULL) { 4750e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4751e7cbe64fSgw "malformed dataset name")); 4752e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 4753e7cbe64fSgw return (1); 47549adfa60dSMatthew Ahrens } else if (p - volname >= ZFS_MAX_DATASET_NAME_LEN) { 4755e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4756e7cbe64fSgw "dataset name is too long")); 4757e7cbe64fSgw (void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf); 4758e7cbe64fSgw return (1); 4759e7cbe64fSgw } else { 4760e7cbe64fSgw (void) strncpy(poolname, volname, p - volname); 4761e7cbe64fSgw poolname[p - volname] = '\0'; 4762e7cbe64fSgw } 4763e7cbe64fSgw 4764e7cbe64fSgw if ((zhp = zpool_open(hdl, poolname)) == NULL) { 4765e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4766e7cbe64fSgw "could not open pool '%s'"), poolname); 4767e7cbe64fSgw (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); 4768e7cbe64fSgw goto out; 4769e7cbe64fSgw } 4770e7cbe64fSgw config = zpool_get_config(zhp, NULL); 4771e7cbe64fSgw if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4772e7cbe64fSgw &nvroot) != 0) { 4773e7cbe64fSgw zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 4774e7cbe64fSgw "could not obtain vdev configuration for '%s'"), poolname); 4775e7cbe64fSgw (void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf); 4776e7cbe64fSgw goto out; 4777e7cbe64fSgw } 4778e7cbe64fSgw 4779e7cbe64fSgw verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4780e7cbe64fSgw &top, &toplevels) == 0); 4781e7cbe64fSgw 4782e7cbe64fSgw if (!supported_dump_vdev_type(hdl, top[0], errbuf)) { 4783e7cbe64fSgw goto out; 4784e7cbe64fSgw } 4785e7cbe64fSgw ret = 0; 4786e7cbe64fSgw 4787e7cbe64fSgw out: 4788e7cbe64fSgw if (zhp) 4789e7cbe64fSgw zpool_close(zhp); 4790e7cbe64fSgw libzfs_fini(hdl); 4791e7cbe64fSgw return (ret); 4792e7cbe64fSgw } 4793