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 /* 2339c23413Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29f3861e1aSahl #include <alloca.h> 30fa9e4066Sahrens #include <assert.h> 31fa9e4066Sahrens #include <ctype.h> 32fa9e4066Sahrens #include <errno.h> 33fa9e4066Sahrens #include <devid.h> 34f3861e1aSahl #include <dirent.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> 418488aeb5Staylor #include <sys/efi_partition.h> 428488aeb5Staylor #include <sys/vtoc.h> 43fa9e4066Sahrens #include <sys/zfs_ioctl.h> 44ea8dc4b6Seschrock #include <sys/zio.h> 4506eeb2adSek110237 #include <strings.h> 46fa9e4066Sahrens 47fa9e4066Sahrens #include "zfs_namecheck.h" 48b1b8ab34Slling #include "zfs_prop.h" 49fa9e4066Sahrens #include "libzfs_impl.h" 50fa9e4066Sahrens 51fa9e4066Sahrens /* 52fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 53fa9e4066Sahrens * 'buf'. 54fa9e4066Sahrens */ 5599653d4eSeschrock static boolean_t 5699653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 57fa9e4066Sahrens { 58fa9e4066Sahrens namecheck_err_t why; 59fa9e4066Sahrens char what; 60b468a217Seschrock int ret; 61fa9e4066Sahrens 62b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 63b468a217Seschrock 64b468a217Seschrock /* 65b468a217Seschrock * The rules for reserved pool names were extended at a later point. 66b468a217Seschrock * But we need to support users with existing pools that may now be 67b468a217Seschrock * invalid. So we only check for this expanded set of names during a 68b468a217Seschrock * create (or import), and only in userland. 69b468a217Seschrock */ 70b468a217Seschrock if (ret == 0 && !isopen && 71b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 72b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 738654d025Sperrin strncmp(pool, "spare", 5) == 0 || 748654d025Sperrin strcmp(pool, "log") == 0)) { 7599653d4eSeschrock zfs_error_aux(hdl, 7699653d4eSeschrock dgettext(TEXT_DOMAIN, "name is reserved")); 7799653d4eSeschrock return (B_FALSE); 78b468a217Seschrock } 79b468a217Seschrock 80b468a217Seschrock 81b468a217Seschrock if (ret != 0) { 8299653d4eSeschrock if (hdl != NULL) { 83fa9e4066Sahrens switch (why) { 84b81d61a6Slling case NAME_ERR_TOOLONG: 8599653d4eSeschrock zfs_error_aux(hdl, 86b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 87b81d61a6Slling break; 88b81d61a6Slling 89fa9e4066Sahrens case NAME_ERR_INVALCHAR: 9099653d4eSeschrock zfs_error_aux(hdl, 91fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 92fa9e4066Sahrens "'%c' in pool name"), what); 93fa9e4066Sahrens break; 94fa9e4066Sahrens 95fa9e4066Sahrens case NAME_ERR_NOLETTER: 9699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9799653d4eSeschrock "name must begin with a letter")); 98fa9e4066Sahrens break; 99fa9e4066Sahrens 100fa9e4066Sahrens case NAME_ERR_RESERVED: 10199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10299653d4eSeschrock "name is reserved")); 103fa9e4066Sahrens break; 104fa9e4066Sahrens 105fa9e4066Sahrens case NAME_ERR_DISKLIKE: 10699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10799653d4eSeschrock "pool name is reserved")); 108fa9e4066Sahrens break; 1095ad82045Snd150628 1105ad82045Snd150628 case NAME_ERR_LEADING_SLASH: 1115ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1125ad82045Snd150628 "leading slash in name")); 1135ad82045Snd150628 break; 1145ad82045Snd150628 1155ad82045Snd150628 case NAME_ERR_EMPTY_COMPONENT: 1165ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1175ad82045Snd150628 "empty component in name")); 1185ad82045Snd150628 break; 1195ad82045Snd150628 1205ad82045Snd150628 case NAME_ERR_TRAILING_SLASH: 1215ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1225ad82045Snd150628 "trailing slash in name")); 1235ad82045Snd150628 break; 1245ad82045Snd150628 1255ad82045Snd150628 case NAME_ERR_MULTIPLE_AT: 1265ad82045Snd150628 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1275ad82045Snd150628 "multiple '@' delimiters in name")); 1285ad82045Snd150628 break; 1295ad82045Snd150628 130fa9e4066Sahrens } 131fa9e4066Sahrens } 13299653d4eSeschrock return (B_FALSE); 133fa9e4066Sahrens } 134fa9e4066Sahrens 13599653d4eSeschrock return (B_TRUE); 136fa9e4066Sahrens } 137fa9e4066Sahrens 138b1b8ab34Slling static int 139b1b8ab34Slling zpool_get_all_props(zpool_handle_t *zhp) 140b1b8ab34Slling { 141b1b8ab34Slling zfs_cmd_t zc = { 0 }; 142b1b8ab34Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 143b1b8ab34Slling 144b1b8ab34Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 145b1b8ab34Slling 146b1b8ab34Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 147b1b8ab34Slling return (-1); 148b1b8ab34Slling 149b1b8ab34Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 150b1b8ab34Slling if (errno == ENOMEM) { 151b1b8ab34Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 152b1b8ab34Slling zcmd_free_nvlists(&zc); 153b1b8ab34Slling return (-1); 154b1b8ab34Slling } 155b1b8ab34Slling } else { 156b1b8ab34Slling zcmd_free_nvlists(&zc); 157b1b8ab34Slling return (-1); 158b1b8ab34Slling } 159b1b8ab34Slling } 160b1b8ab34Slling 161b1b8ab34Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 162b1b8ab34Slling zcmd_free_nvlists(&zc); 163b1b8ab34Slling return (-1); 164b1b8ab34Slling } 165b1b8ab34Slling 166b1b8ab34Slling zcmd_free_nvlists(&zc); 167b1b8ab34Slling 168b1b8ab34Slling return (0); 169b1b8ab34Slling } 170b1b8ab34Slling 171fa9e4066Sahrens /* 172fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 173fa9e4066Sahrens * state. 174fa9e4066Sahrens */ 175fa9e4066Sahrens zpool_handle_t * 17699653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 177fa9e4066Sahrens { 178fa9e4066Sahrens zpool_handle_t *zhp; 17994de1d4cSeschrock boolean_t missing; 180fa9e4066Sahrens 181fa9e4066Sahrens /* 182fa9e4066Sahrens * Make sure the pool name is valid. 183fa9e4066Sahrens */ 18499653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 185ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 18699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 18799653d4eSeschrock pool); 188fa9e4066Sahrens return (NULL); 189fa9e4066Sahrens } 190fa9e4066Sahrens 19199653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 19299653d4eSeschrock return (NULL); 193fa9e4066Sahrens 19499653d4eSeschrock zhp->zpool_hdl = hdl; 195fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 196fa9e4066Sahrens 19794de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 19894de1d4cSeschrock zpool_close(zhp); 19994de1d4cSeschrock return (NULL); 20094de1d4cSeschrock } 20194de1d4cSeschrock 20294de1d4cSeschrock if (missing) { 20399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20499653d4eSeschrock "no such pool")); 205ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 20699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 20799653d4eSeschrock pool); 20894de1d4cSeschrock zpool_close(zhp); 209fa9e4066Sahrens return (NULL); 210fa9e4066Sahrens } 211fa9e4066Sahrens 212fa9e4066Sahrens return (zhp); 213fa9e4066Sahrens } 214fa9e4066Sahrens 215fa9e4066Sahrens /* 216fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 217fa9e4066Sahrens * the configuration cache may be out of date). 218fa9e4066Sahrens */ 21994de1d4cSeschrock int 22094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 221fa9e4066Sahrens { 222fa9e4066Sahrens zpool_handle_t *zhp; 22394de1d4cSeschrock boolean_t missing; 224fa9e4066Sahrens 22594de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 22694de1d4cSeschrock return (-1); 227fa9e4066Sahrens 22899653d4eSeschrock zhp->zpool_hdl = hdl; 229fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 230fa9e4066Sahrens 23194de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 23294de1d4cSeschrock zpool_close(zhp); 23394de1d4cSeschrock return (-1); 234fa9e4066Sahrens } 235fa9e4066Sahrens 23694de1d4cSeschrock if (missing) { 23794de1d4cSeschrock zpool_close(zhp); 23894de1d4cSeschrock *ret = NULL; 23994de1d4cSeschrock return (0); 24094de1d4cSeschrock } 24194de1d4cSeschrock 24294de1d4cSeschrock *ret = zhp; 24394de1d4cSeschrock return (0); 244fa9e4066Sahrens } 245fa9e4066Sahrens 246fa9e4066Sahrens /* 247fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 248fa9e4066Sahrens * state. 249fa9e4066Sahrens */ 250fa9e4066Sahrens zpool_handle_t * 25199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 252fa9e4066Sahrens { 253fa9e4066Sahrens zpool_handle_t *zhp; 254fa9e4066Sahrens 25599653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 256fa9e4066Sahrens return (NULL); 257fa9e4066Sahrens 258fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 259ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 26099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 261fa9e4066Sahrens zpool_close(zhp); 262fa9e4066Sahrens return (NULL); 263fa9e4066Sahrens } 264fa9e4066Sahrens 265fa9e4066Sahrens return (zhp); 266fa9e4066Sahrens } 267fa9e4066Sahrens 268fa9e4066Sahrens /* 269fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 270fa9e4066Sahrens */ 271fa9e4066Sahrens void 272fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 273fa9e4066Sahrens { 274fa9e4066Sahrens if (zhp->zpool_config) 275fa9e4066Sahrens nvlist_free(zhp->zpool_config); 276088e9d47Seschrock if (zhp->zpool_old_config) 277088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 278b1b8ab34Slling if (zhp->zpool_props) 279b1b8ab34Slling nvlist_free(zhp->zpool_props); 280fa9e4066Sahrens free(zhp); 281fa9e4066Sahrens } 282fa9e4066Sahrens 283fa9e4066Sahrens /* 284fa9e4066Sahrens * Return the name of the pool. 285fa9e4066Sahrens */ 286fa9e4066Sahrens const char * 287fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 288fa9e4066Sahrens { 289fa9e4066Sahrens return (zhp->zpool_name); 290fa9e4066Sahrens } 291fa9e4066Sahrens 292fa9e4066Sahrens /* 293fa9e4066Sahrens * Return the GUID of the pool. 294fa9e4066Sahrens */ 295fa9e4066Sahrens uint64_t 296fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp) 297fa9e4066Sahrens { 298fa9e4066Sahrens uint64_t guid; 299fa9e4066Sahrens 300fa9e4066Sahrens verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID, 301fa9e4066Sahrens &guid) == 0); 302fa9e4066Sahrens return (guid); 303fa9e4066Sahrens } 304fa9e4066Sahrens 305fa9e4066Sahrens /* 30699653d4eSeschrock * Return the version of the pool. 30799653d4eSeschrock */ 30899653d4eSeschrock uint64_t 30999653d4eSeschrock zpool_get_version(zpool_handle_t *zhp) 31099653d4eSeschrock { 31199653d4eSeschrock uint64_t version; 31299653d4eSeschrock 31399653d4eSeschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION, 31499653d4eSeschrock &version) == 0); 31599653d4eSeschrock 31699653d4eSeschrock return (version); 31799653d4eSeschrock } 31899653d4eSeschrock 31999653d4eSeschrock /* 320fa9e4066Sahrens * Return the amount of space currently consumed by the pool. 321fa9e4066Sahrens */ 322fa9e4066Sahrens uint64_t 323fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp) 324fa9e4066Sahrens { 325fa9e4066Sahrens nvlist_t *nvroot; 326fa9e4066Sahrens vdev_stat_t *vs; 327fa9e4066Sahrens uint_t vsc; 328fa9e4066Sahrens 329fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 330fa9e4066Sahrens &nvroot) == 0); 331fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 332fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 333fa9e4066Sahrens 334fa9e4066Sahrens return (vs->vs_alloc); 335fa9e4066Sahrens } 336fa9e4066Sahrens 337fa9e4066Sahrens /* 338fa9e4066Sahrens * Return the total space in the pool. 339fa9e4066Sahrens */ 340fa9e4066Sahrens uint64_t 341fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp) 342fa9e4066Sahrens { 343fa9e4066Sahrens nvlist_t *nvroot; 344fa9e4066Sahrens vdev_stat_t *vs; 345fa9e4066Sahrens uint_t vsc; 346fa9e4066Sahrens 347fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 348fa9e4066Sahrens &nvroot) == 0); 349fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 350fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 351fa9e4066Sahrens 352fa9e4066Sahrens return (vs->vs_space); 353fa9e4066Sahrens } 354fa9e4066Sahrens 355fa9e4066Sahrens /* 356fa9e4066Sahrens * Return the alternate root for this pool, if any. 357fa9e4066Sahrens */ 358fa9e4066Sahrens int 359fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen) 360fa9e4066Sahrens { 361fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 362fa9e4066Sahrens 363fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 36499653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 || 365e9dbad6fSeschrock zc.zc_value[0] == '\0') 366fa9e4066Sahrens return (-1); 367fa9e4066Sahrens 368e9dbad6fSeschrock (void) strlcpy(buf, zc.zc_value, buflen); 369fa9e4066Sahrens 370fa9e4066Sahrens return (0); 371fa9e4066Sahrens } 372fa9e4066Sahrens 373fa9e4066Sahrens /* 374fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 375fa9e4066Sahrens */ 376fa9e4066Sahrens int 377fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 378fa9e4066Sahrens { 379fa9e4066Sahrens return (zhp->zpool_state); 380fa9e4066Sahrens } 381fa9e4066Sahrens 382fa9e4066Sahrens /* 383fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 384fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 385fa9e4066Sahrens * don't have to worry about error semantics. 386fa9e4066Sahrens */ 387fa9e4066Sahrens int 38899653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 38999653d4eSeschrock const char *altroot) 390fa9e4066Sahrens { 391fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 39299653d4eSeschrock char msg[1024]; 393fa9e4066Sahrens 39499653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 39599653d4eSeschrock "cannot create '%s'"), pool); 39699653d4eSeschrock 39799653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 39899653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 39999653d4eSeschrock 40099653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 401ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 40299653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot)); 40399653d4eSeschrock 404e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 405fa9e4066Sahrens return (-1); 40699653d4eSeschrock 407fa9e4066Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 408fa9e4066Sahrens 409fa9e4066Sahrens if (altroot != NULL) 410e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 411fa9e4066Sahrens 412ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc) != 0) { 413e9dbad6fSeschrock zcmd_free_nvlists(&zc); 41499653d4eSeschrock 415fa9e4066Sahrens switch (errno) { 416fa9e4066Sahrens case EBUSY: 417fa9e4066Sahrens /* 418fa9e4066Sahrens * This can happen if the user has specified the same 419fa9e4066Sahrens * device multiple times. We can't reliably detect this 420fa9e4066Sahrens * until we try to add it and see we already have a 421fa9e4066Sahrens * label. 422fa9e4066Sahrens */ 42399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 42499653d4eSeschrock "one or more vdevs refer to the same device")); 42599653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 426fa9e4066Sahrens 427fa9e4066Sahrens case EOVERFLOW: 428fa9e4066Sahrens /* 42999653d4eSeschrock * This occurs when one of the devices is below 430fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 431fa9e4066Sahrens * device was the problem device since there's no 432fa9e4066Sahrens * reliable way to determine device size from userland. 433fa9e4066Sahrens */ 434fa9e4066Sahrens { 435fa9e4066Sahrens char buf[64]; 436fa9e4066Sahrens 437fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 438fa9e4066Sahrens 43999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 44099653d4eSeschrock "one or more devices is less than the " 44199653d4eSeschrock "minimum size (%s)"), buf); 442fa9e4066Sahrens } 44399653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 444fa9e4066Sahrens 445fa9e4066Sahrens case ENOSPC: 44699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 44799653d4eSeschrock "one or more devices is out of space")); 44899653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 449fa9e4066Sahrens 450fa9e4066Sahrens default: 45199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 452fa9e4066Sahrens } 453fa9e4066Sahrens } 454e9dbad6fSeschrock zcmd_free_nvlists(&zc); 455fa9e4066Sahrens 456fa9e4066Sahrens /* 457fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 458e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 459fa9e4066Sahrens */ 460fa9e4066Sahrens if (altroot != NULL) { 461fa9e4066Sahrens zfs_handle_t *zhp; 462fa9e4066Sahrens 46399653d4eSeschrock verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL); 464e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 465e9dbad6fSeschrock "/") == 0); 466fa9e4066Sahrens 467fa9e4066Sahrens zfs_close(zhp); 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens return (0); 471fa9e4066Sahrens } 472fa9e4066Sahrens 473fa9e4066Sahrens /* 474fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 475fa9e4066Sahrens * datasets left in the pool. 476fa9e4066Sahrens */ 477fa9e4066Sahrens int 478fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 479fa9e4066Sahrens { 480fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 481fa9e4066Sahrens zfs_handle_t *zfp = NULL; 48299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 48399653d4eSeschrock char msg[1024]; 484fa9e4066Sahrens 485fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 48699653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 48799653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 488fa9e4066Sahrens return (-1); 489fa9e4066Sahrens 4905ad82045Snd150628 if (zpool_remove_zvol_links(zhp) != 0) 491fa9e4066Sahrens return (-1); 492fa9e4066Sahrens 493fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 494fa9e4066Sahrens 495ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 49699653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 49799653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 498fa9e4066Sahrens 49999653d4eSeschrock if (errno == EROFS) { 50099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50199653d4eSeschrock "one or more devices is read only")); 50299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 50399653d4eSeschrock } else { 50499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 505fa9e4066Sahrens } 506fa9e4066Sahrens 507fa9e4066Sahrens if (zfp) 508fa9e4066Sahrens zfs_close(zfp); 509fa9e4066Sahrens return (-1); 510fa9e4066Sahrens } 511fa9e4066Sahrens 512fa9e4066Sahrens if (zfp) { 513fa9e4066Sahrens remove_mountpoint(zfp); 514fa9e4066Sahrens zfs_close(zfp); 515fa9e4066Sahrens } 516fa9e4066Sahrens 517fa9e4066Sahrens return (0); 518fa9e4066Sahrens } 519fa9e4066Sahrens 520fa9e4066Sahrens /* 521fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 522fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 523fa9e4066Sahrens */ 524fa9e4066Sahrens int 525fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 526fa9e4066Sahrens { 527e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 52899653d4eSeschrock int ret; 52999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 53099653d4eSeschrock char msg[1024]; 53199653d4eSeschrock nvlist_t **spares; 53299653d4eSeschrock uint_t nspares; 53399653d4eSeschrock 53499653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 53599653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 53699653d4eSeschrock 537e7437265Sahrens if (zpool_get_version(zhp) < SPA_VERSION_SPARES && 53899653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 53999653d4eSeschrock &spares, &nspares) == 0) { 54099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 54199653d4eSeschrock "upgraded to add hot spares")); 54299653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 54399653d4eSeschrock } 544fa9e4066Sahrens 545e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 54699653d4eSeschrock return (-1); 547fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 548fa9e4066Sahrens 549ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) { 550fa9e4066Sahrens switch (errno) { 551fa9e4066Sahrens case EBUSY: 552fa9e4066Sahrens /* 553fa9e4066Sahrens * This can happen if the user has specified the same 554fa9e4066Sahrens * device multiple times. We can't reliably detect this 555fa9e4066Sahrens * until we try to add it and see we already have a 556fa9e4066Sahrens * label. 557fa9e4066Sahrens */ 55899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 55999653d4eSeschrock "one or more vdevs refer to the same device")); 56099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 561fa9e4066Sahrens break; 562fa9e4066Sahrens 563fa9e4066Sahrens case EOVERFLOW: 564fa9e4066Sahrens /* 565fa9e4066Sahrens * This occurrs when one of the devices is below 566fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 567fa9e4066Sahrens * device was the problem device since there's no 568fa9e4066Sahrens * reliable way to determine device size from userland. 569fa9e4066Sahrens */ 570fa9e4066Sahrens { 571fa9e4066Sahrens char buf[64]; 572fa9e4066Sahrens 573fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 574fa9e4066Sahrens 57599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 57699653d4eSeschrock "device is less than the minimum " 57799653d4eSeschrock "size (%s)"), buf); 578fa9e4066Sahrens } 57999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 58099653d4eSeschrock break; 58199653d4eSeschrock 58299653d4eSeschrock case ENOTSUP: 58399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5848654d025Sperrin "pool must be upgraded to add these vdevs")); 58599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 586fa9e4066Sahrens break; 587fa9e4066Sahrens 588b1b8ab34Slling case EDOM: 589b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 5908654d025Sperrin "root pool can not have multiple vdevs" 5918654d025Sperrin " or separate logs")); 592b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 593b1b8ab34Slling break; 594b1b8ab34Slling 595fa9e4066Sahrens default: 59699653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 597fa9e4066Sahrens } 598fa9e4066Sahrens 59999653d4eSeschrock ret = -1; 60099653d4eSeschrock } else { 60199653d4eSeschrock ret = 0; 602fa9e4066Sahrens } 603fa9e4066Sahrens 604e9dbad6fSeschrock zcmd_free_nvlists(&zc); 605fa9e4066Sahrens 60699653d4eSeschrock return (ret); 607fa9e4066Sahrens } 608fa9e4066Sahrens 609fa9e4066Sahrens /* 610fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 611fa9e4066Sahrens * mounted datasets in the pool. 612fa9e4066Sahrens */ 613fa9e4066Sahrens int 614fa9e4066Sahrens zpool_export(zpool_handle_t *zhp) 615fa9e4066Sahrens { 616fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 617fa9e4066Sahrens 618fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 619fa9e4066Sahrens return (-1); 620fa9e4066Sahrens 621fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 622fa9e4066Sahrens 623ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) 624ece3d9b3Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 62599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot export '%s'"), 62699653d4eSeschrock zhp->zpool_name)); 627fa9e4066Sahrens return (0); 628fa9e4066Sahrens } 629fa9e4066Sahrens 630fa9e4066Sahrens /* 631fa9e4066Sahrens * Import the given pool using the known configuration. The configuration 632fa9e4066Sahrens * should have come from zpool_find_import(). The 'newname' and 'altroot' 633fa9e4066Sahrens * parameters control whether the pool is imported with a different name or with 634fa9e4066Sahrens * an alternate root, respectively. 635fa9e4066Sahrens */ 636fa9e4066Sahrens int 63799653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 63899653d4eSeschrock const char *altroot) 639fa9e4066Sahrens { 640e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 641fa9e4066Sahrens char *thename; 642fa9e4066Sahrens char *origname; 643fa9e4066Sahrens int ret; 644fa9e4066Sahrens 645fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 646fa9e4066Sahrens &origname) == 0); 647fa9e4066Sahrens 648fa9e4066Sahrens if (newname != NULL) { 64999653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 650ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 65199653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 65299653d4eSeschrock newname)); 653fa9e4066Sahrens thename = (char *)newname; 654fa9e4066Sahrens } else { 655fa9e4066Sahrens thename = origname; 656fa9e4066Sahrens } 657fa9e4066Sahrens 65899653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 659ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 66099653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), 66199653d4eSeschrock altroot)); 662fa9e4066Sahrens 663fa9e4066Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 664fa9e4066Sahrens 665fa9e4066Sahrens if (altroot != NULL) 666e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 667fa9e4066Sahrens else 668e9dbad6fSeschrock zc.zc_value[0] = '\0'; 669fa9e4066Sahrens 670fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 671ea8dc4b6Seschrock &zc.zc_guid) == 0); 672fa9e4066Sahrens 673e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0) 67499653d4eSeschrock return (-1); 675fa9e4066Sahrens 676fa9e4066Sahrens ret = 0; 677ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 678fa9e4066Sahrens char desc[1024]; 679fa9e4066Sahrens if (newname == NULL) 680fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 681fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 682fa9e4066Sahrens thename); 683fa9e4066Sahrens else 684fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 685fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 686fa9e4066Sahrens origname, thename); 687fa9e4066Sahrens 688fa9e4066Sahrens switch (errno) { 689ea8dc4b6Seschrock case ENOTSUP: 690ea8dc4b6Seschrock /* 691ea8dc4b6Seschrock * Unsupported version. 692ea8dc4b6Seschrock */ 69399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 694ea8dc4b6Seschrock break; 695ea8dc4b6Seschrock 696b5989ec7Seschrock case EINVAL: 697b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 698b5989ec7Seschrock break; 699b5989ec7Seschrock 700fa9e4066Sahrens default: 70199653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 702fa9e4066Sahrens } 703fa9e4066Sahrens 704fa9e4066Sahrens ret = -1; 705fa9e4066Sahrens } else { 706fa9e4066Sahrens zpool_handle_t *zhp; 707ecd6cf80Smarks 708fa9e4066Sahrens /* 709fa9e4066Sahrens * This should never fail, but play it safe anyway. 710fa9e4066Sahrens */ 71194de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 71294de1d4cSeschrock ret = -1; 71394de1d4cSeschrock } else if (zhp != NULL) { 714fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 715fa9e4066Sahrens zpool_close(zhp); 716fa9e4066Sahrens } 717ecd6cf80Smarks 718fa9e4066Sahrens } 719fa9e4066Sahrens 720ecd6cf80Smarks 721e9dbad6fSeschrock zcmd_free_nvlists(&zc); 722fa9e4066Sahrens return (ret); 723fa9e4066Sahrens } 724fa9e4066Sahrens 725fa9e4066Sahrens /* 726fa9e4066Sahrens * Scrub the pool. 727fa9e4066Sahrens */ 728fa9e4066Sahrens int 729fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 730fa9e4066Sahrens { 731fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 732fa9e4066Sahrens char msg[1024]; 73399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 734fa9e4066Sahrens 735fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 736fa9e4066Sahrens zc.zc_cookie = type; 737fa9e4066Sahrens 738ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0) 739fa9e4066Sahrens return (0); 740fa9e4066Sahrens 741fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 742fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 743fa9e4066Sahrens 74499653d4eSeschrock if (errno == EBUSY) 74599653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 74699653d4eSeschrock else 74799653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 748fa9e4066Sahrens } 749fa9e4066Sahrens 750a43d325bSek110237 /* 751a43d325bSek110237 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 752a43d325bSek110237 * spare; but FALSE if its an INUSE spare. 753a43d325bSek110237 */ 75499653d4eSeschrock static nvlist_t * 75599653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, 756a43d325bSek110237 boolean_t *avail_spare) 757ea8dc4b6Seschrock { 758ea8dc4b6Seschrock uint_t c, children; 759ea8dc4b6Seschrock nvlist_t **child; 76099653d4eSeschrock uint64_t theguid, present; 761ea8dc4b6Seschrock char *path; 762ea8dc4b6Seschrock uint64_t wholedisk = 0; 76399653d4eSeschrock nvlist_t *ret; 764ea8dc4b6Seschrock 76599653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0); 766ea8dc4b6Seschrock 767ea8dc4b6Seschrock if (search == NULL && 768ea8dc4b6Seschrock nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) { 769ea8dc4b6Seschrock /* 770ea8dc4b6Seschrock * If the device has never been present since import, the only 771ea8dc4b6Seschrock * reliable way to match the vdev is by GUID. 772ea8dc4b6Seschrock */ 77399653d4eSeschrock if (theguid == guid) 77499653d4eSeschrock return (nv); 775ea8dc4b6Seschrock } else if (search != NULL && 776ea8dc4b6Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 777ea8dc4b6Seschrock (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 778ea8dc4b6Seschrock &wholedisk); 779ea8dc4b6Seschrock if (wholedisk) { 780ea8dc4b6Seschrock /* 781ea8dc4b6Seschrock * For whole disks, the internal path has 's0', but the 782ea8dc4b6Seschrock * path passed in by the user doesn't. 783ea8dc4b6Seschrock */ 784ea8dc4b6Seschrock if (strlen(search) == strlen(path) - 2 && 785ea8dc4b6Seschrock strncmp(search, path, strlen(search)) == 0) 78699653d4eSeschrock return (nv); 787ea8dc4b6Seschrock } else if (strcmp(search, path) == 0) { 78899653d4eSeschrock return (nv); 789ea8dc4b6Seschrock } 790ea8dc4b6Seschrock } 791ea8dc4b6Seschrock 792ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 793ea8dc4b6Seschrock &child, &children) != 0) 79499653d4eSeschrock return (NULL); 795ea8dc4b6Seschrock 796ea8dc4b6Seschrock for (c = 0; c < children; c++) 79799653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 798a43d325bSek110237 avail_spare)) != NULL) 799ea8dc4b6Seschrock return (ret); 800ea8dc4b6Seschrock 80199653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 80299653d4eSeschrock &child, &children) == 0) { 80399653d4eSeschrock for (c = 0; c < children; c++) { 80499653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 805a43d325bSek110237 avail_spare)) != NULL) { 806a43d325bSek110237 *avail_spare = B_TRUE; 80799653d4eSeschrock return (ret); 80899653d4eSeschrock } 80999653d4eSeschrock } 810ea8dc4b6Seschrock } 811ea8dc4b6Seschrock 81299653d4eSeschrock return (NULL); 81399653d4eSeschrock } 81499653d4eSeschrock 81599653d4eSeschrock nvlist_t * 816a43d325bSek110237 zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) 817ea8dc4b6Seschrock { 818ea8dc4b6Seschrock char buf[MAXPATHLEN]; 819ea8dc4b6Seschrock const char *search; 820ea8dc4b6Seschrock char *end; 821ea8dc4b6Seschrock nvlist_t *nvroot; 822ea8dc4b6Seschrock uint64_t guid; 823ea8dc4b6Seschrock 8240917b783Seschrock guid = strtoull(path, &end, 10); 825ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 826ea8dc4b6Seschrock search = NULL; 827ea8dc4b6Seschrock } else if (path[0] != '/') { 828ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 829ea8dc4b6Seschrock search = buf; 830ea8dc4b6Seschrock } else { 831ea8dc4b6Seschrock search = path; 832ea8dc4b6Seschrock } 833ea8dc4b6Seschrock 834ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 835ea8dc4b6Seschrock &nvroot) == 0); 836ea8dc4b6Seschrock 837a43d325bSek110237 *avail_spare = B_FALSE; 838a43d325bSek110237 return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare)); 839a43d325bSek110237 } 840a43d325bSek110237 841a43d325bSek110237 /* 842a43d325bSek110237 * Returns TRUE if the given guid corresponds to a spare (INUSE or not). 843a43d325bSek110237 */ 844a43d325bSek110237 static boolean_t 845a43d325bSek110237 is_spare(zpool_handle_t *zhp, uint64_t guid) 846a43d325bSek110237 { 847a43d325bSek110237 uint64_t spare_guid; 848a43d325bSek110237 nvlist_t *nvroot; 849a43d325bSek110237 nvlist_t **spares; 850a43d325bSek110237 uint_t nspares; 851a43d325bSek110237 int i; 852a43d325bSek110237 853a43d325bSek110237 verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 854a43d325bSek110237 &nvroot) == 0); 855a43d325bSek110237 if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 856a43d325bSek110237 &spares, &nspares) == 0) { 857a43d325bSek110237 for (i = 0; i < nspares; i++) { 858a43d325bSek110237 verify(nvlist_lookup_uint64(spares[i], 859a43d325bSek110237 ZPOOL_CONFIG_GUID, &spare_guid) == 0); 860a43d325bSek110237 if (guid == spare_guid) 861a43d325bSek110237 return (B_TRUE); 862a43d325bSek110237 } 863a43d325bSek110237 } 864a43d325bSek110237 865a43d325bSek110237 return (B_FALSE); 866ea8dc4b6Seschrock } 867ea8dc4b6Seschrock 868fa9e4066Sahrens /* 8693d7072f8Seschrock * Bring the specified vdev online. The 'flags' parameter is a set of the 8703d7072f8Seschrock * ZFS_ONLINE_* flags. 871fa9e4066Sahrens */ 872fa9e4066Sahrens int 8733d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags, 8743d7072f8Seschrock vdev_state_t *newstate) 875fa9e4066Sahrens { 876fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 877fa9e4066Sahrens char msg[1024]; 87899653d4eSeschrock nvlist_t *tgt; 879a43d325bSek110237 boolean_t avail_spare; 88099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 881fa9e4066Sahrens 882fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 883ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot online %s"), path); 884ea8dc4b6Seschrock 885ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 886a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 88799653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 888ea8dc4b6Seschrock 88999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 89099653d4eSeschrock 891a43d325bSek110237 if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 892a43d325bSek110237 return (zfs_error(hdl, EZFS_ISSPARE, msg)); 893a43d325bSek110237 8943d7072f8Seschrock zc.zc_cookie = VDEV_STATE_ONLINE; 8953d7072f8Seschrock zc.zc_obj = flags; 896fa9e4066Sahrens 8973d7072f8Seschrock 898ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) 89999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 9003d7072f8Seschrock 9013d7072f8Seschrock *newstate = zc.zc_cookie; 9023d7072f8Seschrock return (0); 903fa9e4066Sahrens } 904fa9e4066Sahrens 905fa9e4066Sahrens /* 906fa9e4066Sahrens * Take the specified vdev offline 907fa9e4066Sahrens */ 908fa9e4066Sahrens int 9093d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp) 910fa9e4066Sahrens { 911fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 912fa9e4066Sahrens char msg[1024]; 91399653d4eSeschrock nvlist_t *tgt; 914a43d325bSek110237 boolean_t avail_spare; 91599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 916fa9e4066Sahrens 917ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 918ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 919ea8dc4b6Seschrock 920fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 921a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 92299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 92399653d4eSeschrock 92499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 925fa9e4066Sahrens 926a43d325bSek110237 if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 927a43d325bSek110237 return (zfs_error(hdl, EZFS_ISSPARE, msg)); 928a43d325bSek110237 9293d7072f8Seschrock zc.zc_cookie = VDEV_STATE_OFFLINE; 9303d7072f8Seschrock zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0; 931441d80aaSlling 932ecd6cf80Smarks if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 933fa9e4066Sahrens return (0); 934fa9e4066Sahrens 935fa9e4066Sahrens switch (errno) { 936fa9e4066Sahrens case EBUSY: 93799653d4eSeschrock 938fa9e4066Sahrens /* 939fa9e4066Sahrens * There are no other replicas of this device. 940fa9e4066Sahrens */ 94199653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 942fa9e4066Sahrens 943fa9e4066Sahrens default: 94499653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 945fa9e4066Sahrens } 94699653d4eSeschrock } 94799653d4eSeschrock 94899653d4eSeschrock /* 9493d7072f8Seschrock * Mark the given vdev faulted. 9503d7072f8Seschrock */ 9513d7072f8Seschrock int 9523d7072f8Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid) 9533d7072f8Seschrock { 9543d7072f8Seschrock zfs_cmd_t zc = { 0 }; 9553d7072f8Seschrock char msg[1024]; 9563d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 9573d7072f8Seschrock 9583d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 9593d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid); 9603d7072f8Seschrock 9613d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 9623d7072f8Seschrock zc.zc_guid = guid; 9633d7072f8Seschrock zc.zc_cookie = VDEV_STATE_FAULTED; 9643d7072f8Seschrock 9653d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 9663d7072f8Seschrock return (0); 9673d7072f8Seschrock 9683d7072f8Seschrock switch (errno) { 9693d7072f8Seschrock case EBUSY: 9703d7072f8Seschrock 9713d7072f8Seschrock /* 9723d7072f8Seschrock * There are no other replicas of this device. 9733d7072f8Seschrock */ 9743d7072f8Seschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 9753d7072f8Seschrock 9763d7072f8Seschrock default: 9773d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 9783d7072f8Seschrock } 9793d7072f8Seschrock 9803d7072f8Seschrock } 9813d7072f8Seschrock 9823d7072f8Seschrock /* 9833d7072f8Seschrock * Mark the given vdev degraded. 9843d7072f8Seschrock */ 9853d7072f8Seschrock int 9863d7072f8Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid) 9873d7072f8Seschrock { 9883d7072f8Seschrock zfs_cmd_t zc = { 0 }; 9893d7072f8Seschrock char msg[1024]; 9903d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 9913d7072f8Seschrock 9923d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 9933d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid); 9943d7072f8Seschrock 9953d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 9963d7072f8Seschrock zc.zc_guid = guid; 9973d7072f8Seschrock zc.zc_cookie = VDEV_STATE_DEGRADED; 9983d7072f8Seschrock 9993d7072f8Seschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 10003d7072f8Seschrock return (0); 10013d7072f8Seschrock 10023d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 10033d7072f8Seschrock } 10043d7072f8Seschrock 10053d7072f8Seschrock /* 100699653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 100799653d4eSeschrock * a hot spare. 100899653d4eSeschrock */ 100999653d4eSeschrock static boolean_t 101099653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 101199653d4eSeschrock { 101299653d4eSeschrock nvlist_t **child; 101399653d4eSeschrock uint_t c, children; 101499653d4eSeschrock char *type; 101599653d4eSeschrock 101699653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 101799653d4eSeschrock &children) == 0) { 101899653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 101999653d4eSeschrock &type) == 0); 102099653d4eSeschrock 102199653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 102299653d4eSeschrock children == 2 && child[which] == tgt) 102399653d4eSeschrock return (B_TRUE); 102499653d4eSeschrock 102599653d4eSeschrock for (c = 0; c < children; c++) 102699653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 102799653d4eSeschrock return (B_TRUE); 102899653d4eSeschrock } 102999653d4eSeschrock 103099653d4eSeschrock return (B_FALSE); 1031fa9e4066Sahrens } 1032fa9e4066Sahrens 1033fa9e4066Sahrens /* 1034fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 10358654d025Sperrin * If 'replacing' is specified, the new disk will replace the old one. 1036fa9e4066Sahrens */ 1037fa9e4066Sahrens int 1038fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 1039fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 1040fa9e4066Sahrens { 1041fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1042fa9e4066Sahrens char msg[1024]; 1043fa9e4066Sahrens int ret; 104499653d4eSeschrock nvlist_t *tgt; 1045a43d325bSek110237 boolean_t avail_spare; 10468654d025Sperrin uint64_t val, is_log; 104799653d4eSeschrock char *path; 104899653d4eSeschrock nvlist_t **child; 104999653d4eSeschrock uint_t children; 105099653d4eSeschrock nvlist_t *config_root; 105199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1052fa9e4066Sahrens 1053ea8dc4b6Seschrock if (replacing) 1054ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 1055ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 1056ea8dc4b6Seschrock else 1057ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 1058ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 1059ea8dc4b6Seschrock 1060fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1061a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0) 106299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 106399653d4eSeschrock 1064a43d325bSek110237 if (avail_spare) 106599653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 106699653d4eSeschrock 106799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 1068fa9e4066Sahrens zc.zc_cookie = replacing; 1069fa9e4066Sahrens 107099653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 107199653d4eSeschrock &child, &children) != 0 || children != 1) { 107299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 107399653d4eSeschrock "new device must be a single disk")); 107499653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 107599653d4eSeschrock } 107699653d4eSeschrock 107799653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 107899653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 107999653d4eSeschrock 108099653d4eSeschrock /* 108199653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 108299653d4eSeschrock * replace it with another hot spare. 108399653d4eSeschrock */ 108499653d4eSeschrock if (replacing && 108599653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 108699653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1087a43d325bSek110237 (zpool_find_vdev(zhp, path, &avail_spare) == NULL || 1088a43d325bSek110237 !avail_spare) && is_replacing_spare(config_root, tgt, 1)) { 108999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 109099653d4eSeschrock "can only be replaced by another hot spare")); 109199653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 109299653d4eSeschrock } 109399653d4eSeschrock 109499653d4eSeschrock /* 109599653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 109699653d4eSeschrock * already spared device. 109799653d4eSeschrock */ 109899653d4eSeschrock if (replacing && 109999653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1100a43d325bSek110237 zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare && 110199653d4eSeschrock is_replacing_spare(config_root, tgt, 0)) { 110299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 110399653d4eSeschrock "device has already been replaced with a spare")); 110499653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 110599653d4eSeschrock } 110699653d4eSeschrock 1107e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 110899653d4eSeschrock return (-1); 1109fa9e4066Sahrens 1110ecd6cf80Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc); 1111fa9e4066Sahrens 1112e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1113fa9e4066Sahrens 1114fa9e4066Sahrens if (ret == 0) 1115fa9e4066Sahrens return (0); 1116fa9e4066Sahrens 1117fa9e4066Sahrens switch (errno) { 1118fa9e4066Sahrens case ENOTSUP: 1119fa9e4066Sahrens /* 1120fa9e4066Sahrens * Can't attach to or replace this type of vdev. 1121fa9e4066Sahrens */ 11228654d025Sperrin if (replacing) { 11238654d025Sperrin is_log = B_FALSE; 11248654d025Sperrin (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_LOG, 11258654d025Sperrin &is_log); 11268654d025Sperrin if (is_log) 11278654d025Sperrin zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 11288654d025Sperrin "cannot replace a log with a spare")); 11298654d025Sperrin else 113099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 113199653d4eSeschrock "cannot replace a replacing device")); 11328654d025Sperrin } else { 113399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 113499653d4eSeschrock "can only attach to mirrors and top-level " 113599653d4eSeschrock "disks")); 11368654d025Sperrin } 113799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 1138fa9e4066Sahrens break; 1139fa9e4066Sahrens 1140fa9e4066Sahrens case EINVAL: 1141fa9e4066Sahrens /* 1142fa9e4066Sahrens * The new device must be a single disk. 1143fa9e4066Sahrens */ 114499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 114599653d4eSeschrock "new device must be a single disk")); 114699653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 1147fa9e4066Sahrens break; 1148fa9e4066Sahrens 1149fa9e4066Sahrens case EBUSY: 115099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 115199653d4eSeschrock new_disk); 115299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1153fa9e4066Sahrens break; 1154fa9e4066Sahrens 1155fa9e4066Sahrens case EOVERFLOW: 1156fa9e4066Sahrens /* 1157fa9e4066Sahrens * The new device is too small. 1158fa9e4066Sahrens */ 115999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116099653d4eSeschrock "device is too small")); 116199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1162fa9e4066Sahrens break; 1163fa9e4066Sahrens 1164fa9e4066Sahrens case EDOM: 1165fa9e4066Sahrens /* 1166fa9e4066Sahrens * The new device has a different alignment requirement. 1167fa9e4066Sahrens */ 116899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 116999653d4eSeschrock "devices have different sector alignment")); 117099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1171fa9e4066Sahrens break; 1172fa9e4066Sahrens 1173fa9e4066Sahrens case ENAMETOOLONG: 1174fa9e4066Sahrens /* 1175fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 1176fa9e4066Sahrens */ 117799653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 1178fa9e4066Sahrens break; 1179fa9e4066Sahrens 1180fa9e4066Sahrens default: 118199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1182fa9e4066Sahrens } 1183fa9e4066Sahrens 118499653d4eSeschrock return (-1); 1185fa9e4066Sahrens } 1186fa9e4066Sahrens 1187fa9e4066Sahrens /* 1188fa9e4066Sahrens * Detach the specified device. 1189fa9e4066Sahrens */ 1190fa9e4066Sahrens int 1191fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 1192fa9e4066Sahrens { 1193fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1194fa9e4066Sahrens char msg[1024]; 119599653d4eSeschrock nvlist_t *tgt; 1196a43d325bSek110237 boolean_t avail_spare; 119799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1198fa9e4066Sahrens 1199fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 1200ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 1201ea8dc4b6Seschrock 1202ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1203a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 120499653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1205ea8dc4b6Seschrock 1206a43d325bSek110237 if (avail_spare) 120799653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 120899653d4eSeschrock 120999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 121099653d4eSeschrock 1211ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0) 1212ea8dc4b6Seschrock return (0); 1213fa9e4066Sahrens 1214fa9e4066Sahrens switch (errno) { 1215fa9e4066Sahrens 1216fa9e4066Sahrens case ENOTSUP: 1217fa9e4066Sahrens /* 1218fa9e4066Sahrens * Can't detach from this type of vdev. 1219fa9e4066Sahrens */ 122099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 122199653d4eSeschrock "applicable to mirror and replacing vdevs")); 122299653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 1223fa9e4066Sahrens break; 1224fa9e4066Sahrens 1225fa9e4066Sahrens case EBUSY: 1226fa9e4066Sahrens /* 1227fa9e4066Sahrens * There are no other replicas of this device. 1228fa9e4066Sahrens */ 122999653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 1230fa9e4066Sahrens break; 1231fa9e4066Sahrens 1232fa9e4066Sahrens default: 123399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1234fa9e4066Sahrens } 1235fa9e4066Sahrens 123699653d4eSeschrock return (-1); 123799653d4eSeschrock } 123899653d4eSeschrock 123999653d4eSeschrock /* 124099653d4eSeschrock * Remove the given device. Currently, this is supported only for hot spares. 124199653d4eSeschrock */ 124299653d4eSeschrock int 124399653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 124499653d4eSeschrock { 124599653d4eSeschrock zfs_cmd_t zc = { 0 }; 124699653d4eSeschrock char msg[1024]; 124799653d4eSeschrock nvlist_t *tgt; 1248a43d325bSek110237 boolean_t avail_spare; 124999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 125099653d4eSeschrock 125199653d4eSeschrock (void) snprintf(msg, sizeof (msg), 125299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 125399653d4eSeschrock 125499653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1255a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 125699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 125799653d4eSeschrock 1258a43d325bSek110237 if (!avail_spare) { 125999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 126039c23413Seschrock "only inactive hot spares can be removed")); 126199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 126299653d4eSeschrock } 126399653d4eSeschrock 126499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 126599653d4eSeschrock 1266ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 126799653d4eSeschrock return (0); 126899653d4eSeschrock 126999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1270fa9e4066Sahrens } 1271fa9e4066Sahrens 1272ea8dc4b6Seschrock /* 1273ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 1274ea8dc4b6Seschrock */ 1275ea8dc4b6Seschrock int 1276ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 1277ea8dc4b6Seschrock { 1278ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1279ea8dc4b6Seschrock char msg[1024]; 128099653d4eSeschrock nvlist_t *tgt; 1281a43d325bSek110237 boolean_t avail_spare; 128299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1283ea8dc4b6Seschrock 1284ea8dc4b6Seschrock if (path) 1285ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1286ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1287e9dbad6fSeschrock path); 1288ea8dc4b6Seschrock else 1289ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1290ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1291ea8dc4b6Seschrock zhp->zpool_name); 1292ea8dc4b6Seschrock 1293ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 129499653d4eSeschrock if (path) { 1295a43d325bSek110237 if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 129699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 129799653d4eSeschrock 1298a43d325bSek110237 if (avail_spare) 129999653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 130099653d4eSeschrock 130199653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 130299653d4eSeschrock &zc.zc_guid) == 0); 1303ea8dc4b6Seschrock } 1304ea8dc4b6Seschrock 1305ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0) 1306ea8dc4b6Seschrock return (0); 1307ea8dc4b6Seschrock 130899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1309ea8dc4b6Seschrock } 1310ea8dc4b6Seschrock 1311fa9e4066Sahrens /* 13123d7072f8Seschrock * Similar to zpool_clear(), but takes a GUID (used by fmd). 13133d7072f8Seschrock */ 13143d7072f8Seschrock int 13153d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) 13163d7072f8Seschrock { 13173d7072f8Seschrock zfs_cmd_t zc = { 0 }; 13183d7072f8Seschrock char msg[1024]; 13193d7072f8Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 13203d7072f8Seschrock 13213d7072f8Seschrock (void) snprintf(msg, sizeof (msg), 13223d7072f8Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"), 13233d7072f8Seschrock guid); 13243d7072f8Seschrock 13253d7072f8Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 13263d7072f8Seschrock zc.zc_guid = guid; 13273d7072f8Seschrock 13283d7072f8Seschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 13293d7072f8Seschrock return (0); 13303d7072f8Seschrock 13313d7072f8Seschrock return (zpool_standard_error(hdl, errno, msg)); 13323d7072f8Seschrock } 13333d7072f8Seschrock 13343d7072f8Seschrock /* 1335f3861e1aSahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 1336f3861e1aSahl * hierarchy. 1337fa9e4066Sahrens */ 1338f3861e1aSahl int 1339f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 1340f3861e1aSahl void *data) 1341f3861e1aSahl { 1342f3861e1aSahl libzfs_handle_t *hdl = zhp->zpool_hdl; 1343f3861e1aSahl char (*paths)[MAXPATHLEN]; 1344f3861e1aSahl size_t size = 4; 1345f3861e1aSahl int curr, fd, base, ret = 0; 1346f3861e1aSahl DIR *dirp; 1347f3861e1aSahl struct dirent *dp; 1348f3861e1aSahl struct stat st; 1349f3861e1aSahl 1350f3861e1aSahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 1351f3861e1aSahl return (errno == ENOENT ? 0 : -1); 1352f3861e1aSahl 1353f3861e1aSahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 1354f3861e1aSahl int err = errno; 1355f3861e1aSahl (void) close(base); 1356f3861e1aSahl return (err == ENOENT ? 0 : -1); 1357fa9e4066Sahrens } 1358fa9e4066Sahrens 1359f3861e1aSahl /* 1360f3861e1aSahl * Oddly this wasn't a directory -- ignore that failure since we 1361f3861e1aSahl * know there are no links lower in the (non-existant) hierarchy. 1362f3861e1aSahl */ 1363f3861e1aSahl if (!S_ISDIR(st.st_mode)) { 1364f3861e1aSahl (void) close(base); 1365f3861e1aSahl return (0); 1366f3861e1aSahl } 1367f3861e1aSahl 1368f3861e1aSahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 1369f3861e1aSahl (void) close(base); 1370f3861e1aSahl return (-1); 1371f3861e1aSahl } 1372f3861e1aSahl 1373f3861e1aSahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 1374f3861e1aSahl curr = 0; 1375f3861e1aSahl 1376f3861e1aSahl while (curr >= 0) { 1377f3861e1aSahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 1378f3861e1aSahl goto err; 1379f3861e1aSahl 1380f3861e1aSahl if (S_ISDIR(st.st_mode)) { 1381f3861e1aSahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 1382f3861e1aSahl goto err; 1383f3861e1aSahl 1384f3861e1aSahl if ((dirp = fdopendir(fd)) == NULL) { 1385f3861e1aSahl (void) close(fd); 1386f3861e1aSahl goto err; 1387f3861e1aSahl } 1388f3861e1aSahl 1389f3861e1aSahl while ((dp = readdir(dirp)) != NULL) { 1390f3861e1aSahl if (dp->d_name[0] == '.') 1391f3861e1aSahl continue; 1392f3861e1aSahl 1393f3861e1aSahl if (curr + 1 == size) { 1394f3861e1aSahl paths = zfs_realloc(hdl, paths, 1395f3861e1aSahl size * sizeof (paths[0]), 1396f3861e1aSahl size * 2 * sizeof (paths[0])); 1397f3861e1aSahl if (paths == NULL) { 1398f3861e1aSahl (void) closedir(dirp); 1399f3861e1aSahl (void) close(fd); 1400f3861e1aSahl goto err; 1401f3861e1aSahl } 1402f3861e1aSahl 1403f3861e1aSahl size *= 2; 1404f3861e1aSahl } 1405f3861e1aSahl 1406f3861e1aSahl (void) strlcpy(paths[curr + 1], paths[curr], 1407f3861e1aSahl sizeof (paths[curr + 1])); 1408f3861e1aSahl (void) strlcat(paths[curr], "/", 1409f3861e1aSahl sizeof (paths[curr])); 1410f3861e1aSahl (void) strlcat(paths[curr], dp->d_name, 1411f3861e1aSahl sizeof (paths[curr])); 1412f3861e1aSahl curr++; 1413f3861e1aSahl } 1414f3861e1aSahl 1415f3861e1aSahl (void) closedir(dirp); 1416f3861e1aSahl 1417f3861e1aSahl } else { 1418f3861e1aSahl if ((ret = cb(paths[curr], data)) != 0) 1419f3861e1aSahl break; 1420f3861e1aSahl } 1421f3861e1aSahl 1422f3861e1aSahl curr--; 1423f3861e1aSahl } 1424f3861e1aSahl 1425f3861e1aSahl free(paths); 1426f3861e1aSahl (void) close(base); 1427f3861e1aSahl 1428f3861e1aSahl return (ret); 1429f3861e1aSahl 1430f3861e1aSahl err: 1431f3861e1aSahl free(paths); 1432f3861e1aSahl (void) close(base); 1433f3861e1aSahl return (-1); 1434f3861e1aSahl } 1435f3861e1aSahl 1436f3861e1aSahl typedef struct zvol_cb { 1437f3861e1aSahl zpool_handle_t *zcb_pool; 1438f3861e1aSahl boolean_t zcb_create; 1439f3861e1aSahl } zvol_cb_t; 1440f3861e1aSahl 1441f3861e1aSahl /*ARGSUSED*/ 1442f3861e1aSahl static int 1443f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data) 1444f3861e1aSahl { 14453aefe2c7Sahrens int ret = 0; 1446f3861e1aSahl 14473aefe2c7Sahrens if (ZFS_IS_VOLUME(zhp)) { 1448f3861e1aSahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 14493aefe2c7Sahrens ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL); 14503aefe2c7Sahrens } 1451f3861e1aSahl 14523aefe2c7Sahrens if (ret == 0) 14533aefe2c7Sahrens ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL); 1454fa9e4066Sahrens 1455fa9e4066Sahrens zfs_close(zhp); 1456f3861e1aSahl 1457fa9e4066Sahrens return (ret); 1458fa9e4066Sahrens } 1459fa9e4066Sahrens 1460fa9e4066Sahrens /* 1461fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 1462fa9e4066Sahrens */ 1463fa9e4066Sahrens int 1464fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 1465fa9e4066Sahrens { 1466fa9e4066Sahrens zfs_handle_t *zfp; 1467fa9e4066Sahrens int ret; 1468fa9e4066Sahrens 1469fa9e4066Sahrens /* 1470fa9e4066Sahrens * If the pool is unavailable, just return success. 1471fa9e4066Sahrens */ 147299653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 147399653d4eSeschrock zhp->zpool_name)) == NULL) 1474fa9e4066Sahrens return (0); 1475fa9e4066Sahrens 14763aefe2c7Sahrens ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL); 1477fa9e4066Sahrens 1478fa9e4066Sahrens zfs_close(zfp); 1479fa9e4066Sahrens return (ret); 1480fa9e4066Sahrens } 1481fa9e4066Sahrens 1482f3861e1aSahl static int 1483f3861e1aSahl do_zvol_remove(const char *dataset, void *data) 1484f3861e1aSahl { 1485f3861e1aSahl zpool_handle_t *zhp = data; 1486f3861e1aSahl 1487f3861e1aSahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 1488f3861e1aSahl } 1489f3861e1aSahl 1490fa9e4066Sahrens /* 1491f3861e1aSahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 1492f3861e1aSahl * by examining the /dev links so that a corrupted pool doesn't impede this 1493f3861e1aSahl * operation. 1494fa9e4066Sahrens */ 1495fa9e4066Sahrens int 1496fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 1497fa9e4066Sahrens { 1498f3861e1aSahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 1499fa9e4066Sahrens } 1500c67d9675Seschrock 1501c67d9675Seschrock /* 1502c67d9675Seschrock * Convert from a devid string to a path. 1503c67d9675Seschrock */ 1504c67d9675Seschrock static char * 1505c67d9675Seschrock devid_to_path(char *devid_str) 1506c67d9675Seschrock { 1507c67d9675Seschrock ddi_devid_t devid; 1508c67d9675Seschrock char *minor; 1509c67d9675Seschrock char *path; 1510c67d9675Seschrock devid_nmlist_t *list = NULL; 1511c67d9675Seschrock int ret; 1512c67d9675Seschrock 1513c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 1514c67d9675Seschrock return (NULL); 1515c67d9675Seschrock 1516c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 1517c67d9675Seschrock 1518c67d9675Seschrock devid_str_free(minor); 1519c67d9675Seschrock devid_free(devid); 1520c67d9675Seschrock 1521c67d9675Seschrock if (ret != 0) 1522c67d9675Seschrock return (NULL); 1523c67d9675Seschrock 152499653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 152599653d4eSeschrock return (NULL); 152699653d4eSeschrock 1527c67d9675Seschrock devid_free_nmlist(list); 1528c67d9675Seschrock 1529c67d9675Seschrock return (path); 1530c67d9675Seschrock } 1531c67d9675Seschrock 1532c67d9675Seschrock /* 1533c67d9675Seschrock * Convert from a path to a devid string. 1534c67d9675Seschrock */ 1535c67d9675Seschrock static char * 1536c67d9675Seschrock path_to_devid(const char *path) 1537c67d9675Seschrock { 1538c67d9675Seschrock int fd; 1539c67d9675Seschrock ddi_devid_t devid; 1540c67d9675Seschrock char *minor, *ret; 1541c67d9675Seschrock 1542c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 1543c67d9675Seschrock return (NULL); 1544c67d9675Seschrock 1545c67d9675Seschrock minor = NULL; 1546c67d9675Seschrock ret = NULL; 1547c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 1548c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 1549c67d9675Seschrock ret = devid_str_encode(devid, minor); 1550c67d9675Seschrock if (minor != NULL) 1551c67d9675Seschrock devid_str_free(minor); 1552c67d9675Seschrock devid_free(devid); 1553c67d9675Seschrock } 1554c67d9675Seschrock (void) close(fd); 1555c67d9675Seschrock 1556c67d9675Seschrock return (ret); 1557c67d9675Seschrock } 1558c67d9675Seschrock 1559c67d9675Seschrock /* 1560c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 1561c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 1562c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 1563c67d9675Seschrock */ 1564c67d9675Seschrock static void 1565c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 1566c67d9675Seschrock { 1567c67d9675Seschrock zfs_cmd_t zc = { 0 }; 1568c67d9675Seschrock 1569c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1570e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 1571c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1572ea8dc4b6Seschrock &zc.zc_guid) == 0); 1573c67d9675Seschrock 157499653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 1575c67d9675Seschrock } 1576c67d9675Seschrock 1577c67d9675Seschrock /* 1578c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 1579c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 1580c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 1581c67d9675Seschrock * trailing 's0' slice name. 1582c67d9675Seschrock * 1583c67d9675Seschrock * This routine is also responsible for identifying when disks have been 1584c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 1585c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 1586c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 1587c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 1588c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 1589c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 1590c67d9675Seschrock * of these checks. 1591c67d9675Seschrock */ 1592c67d9675Seschrock char * 159399653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 1594c67d9675Seschrock { 1595c67d9675Seschrock char *path, *devid; 1596ea8dc4b6Seschrock uint64_t value; 1597ea8dc4b6Seschrock char buf[64]; 15983d7072f8Seschrock vdev_stat_t *vs; 15993d7072f8Seschrock uint_t vsc; 1600c67d9675Seschrock 1601ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1602ea8dc4b6Seschrock &value) == 0) { 1603ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1604ea8dc4b6Seschrock &value) == 0); 16055ad82045Snd150628 (void) snprintf(buf, sizeof (buf), "%llu", 16065ad82045Snd150628 (u_longlong_t)value); 1607ea8dc4b6Seschrock path = buf; 1608ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 1609c67d9675Seschrock 16103d7072f8Seschrock /* 16113d7072f8Seschrock * If the device is dead (faulted, offline, etc) then don't 16123d7072f8Seschrock * bother opening it. Otherwise we may be forcing the user to 16133d7072f8Seschrock * open a misbehaving device, which can have undesirable 16143d7072f8Seschrock * effects. 16153d7072f8Seschrock */ 16163d7072f8Seschrock if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, 16173d7072f8Seschrock (uint64_t **)&vs, &vsc) != 0 || 16183d7072f8Seschrock vs->vs_state >= VDEV_STATE_DEGRADED) && 16193d7072f8Seschrock zhp != NULL && 1620c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 1621c67d9675Seschrock /* 1622c67d9675Seschrock * Determine if the current path is correct. 1623c67d9675Seschrock */ 1624c67d9675Seschrock char *newdevid = path_to_devid(path); 1625c67d9675Seschrock 1626c67d9675Seschrock if (newdevid == NULL || 1627c67d9675Seschrock strcmp(devid, newdevid) != 0) { 1628c67d9675Seschrock char *newpath; 1629c67d9675Seschrock 1630c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 1631c67d9675Seschrock /* 1632c67d9675Seschrock * Update the path appropriately. 1633c67d9675Seschrock */ 1634c67d9675Seschrock set_path(zhp, nv, newpath); 163599653d4eSeschrock if (nvlist_add_string(nv, 163699653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 1637c67d9675Seschrock verify(nvlist_lookup_string(nv, 163899653d4eSeschrock ZPOOL_CONFIG_PATH, 163999653d4eSeschrock &path) == 0); 164099653d4eSeschrock free(newpath); 164199653d4eSeschrock } 1642c67d9675Seschrock } 1643c67d9675Seschrock 1644c67d9675Seschrock if (newdevid) 1645c67d9675Seschrock devid_str_free(newdevid); 1646c67d9675Seschrock } 1647c67d9675Seschrock 1648c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 1649c67d9675Seschrock path += 9; 1650c67d9675Seschrock 1651c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1652ea8dc4b6Seschrock &value) == 0 && value) { 165399653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 165499653d4eSeschrock if (tmp == NULL) 165599653d4eSeschrock return (NULL); 1656c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 1657c67d9675Seschrock return (tmp); 1658c67d9675Seschrock } 1659c67d9675Seschrock } else { 1660c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 166199653d4eSeschrock 166299653d4eSeschrock /* 166399653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 166499653d4eSeschrock */ 166599653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 166699653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 166799653d4eSeschrock &value) == 0); 166899653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 16695ad82045Snd150628 (u_longlong_t)value); 167099653d4eSeschrock path = buf; 167199653d4eSeschrock } 1672c67d9675Seschrock } 1673c67d9675Seschrock 167499653d4eSeschrock return (zfs_strdup(hdl, path)); 1675c67d9675Seschrock } 1676ea8dc4b6Seschrock 1677ea8dc4b6Seschrock static int 1678ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 1679ea8dc4b6Seschrock { 1680ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 1681ea8dc4b6Seschrock } 1682ea8dc4b6Seschrock 1683ea8dc4b6Seschrock /* 1684ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 1685ea8dc4b6Seschrock * caller. 1686ea8dc4b6Seschrock */ 1687ea8dc4b6Seschrock int 168855434c77Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 1689ea8dc4b6Seschrock { 1690ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1691ea8dc4b6Seschrock uint64_t count; 1692e9dbad6fSeschrock zbookmark_t *zb = NULL; 169355434c77Sek110237 int i; 1694ea8dc4b6Seschrock 1695ea8dc4b6Seschrock /* 1696ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 1697ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 1698ea8dc4b6Seschrock * entire list. 1699ea8dc4b6Seschrock */ 1700ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 1701ea8dc4b6Seschrock &count) == 0); 170275519f38Sek110237 if (count == 0) 170375519f38Sek110237 return (0); 1704e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 17055ad82045Snd150628 count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 170699653d4eSeschrock return (-1); 1707e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 1708ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 1709ea8dc4b6Seschrock for (;;) { 171099653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 171199653d4eSeschrock &zc) != 0) { 1712e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 171399653d4eSeschrock if (errno == ENOMEM) { 1714bf561db0Svb160487 count = zc.zc_nvlist_dst_size; 1715e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 1716bf561db0Svb160487 zfs_alloc(zhp->zpool_hdl, count * 1717bf561db0Svb160487 sizeof (zbookmark_t))) == (uintptr_t)NULL) 171899653d4eSeschrock return (-1); 1719ea8dc4b6Seschrock } else { 1720ea8dc4b6Seschrock return (-1); 1721ea8dc4b6Seschrock } 1722ea8dc4b6Seschrock } else { 1723ea8dc4b6Seschrock break; 1724ea8dc4b6Seschrock } 1725ea8dc4b6Seschrock } 1726ea8dc4b6Seschrock 1727ea8dc4b6Seschrock /* 1728ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 1729ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 1730e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 1731ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 1732ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 1733ea8dc4b6Seschrock */ 1734e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 1735e9dbad6fSeschrock zc.zc_nvlist_dst_size; 1736e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 1737ea8dc4b6Seschrock 1738ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 1739ea8dc4b6Seschrock 174055434c77Sek110237 verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 174155434c77Sek110237 1742ea8dc4b6Seschrock /* 174355434c77Sek110237 * Fill in the nverrlistp with nvlist's of dataset and object numbers. 1744ea8dc4b6Seschrock */ 1745ea8dc4b6Seschrock for (i = 0; i < count; i++) { 1746ea8dc4b6Seschrock nvlist_t *nv; 1747ea8dc4b6Seschrock 1748c0a81264Sek110237 /* ignoring zb_blkid and zb_level for now */ 1749c0a81264Sek110237 if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 1750c0a81264Sek110237 zb[i-1].zb_object == zb[i].zb_object) 1751ea8dc4b6Seschrock continue; 1752ea8dc4b6Seschrock 175355434c77Sek110237 if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 1754e9dbad6fSeschrock goto nomem; 175555434c77Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 175655434c77Sek110237 zb[i].zb_objset) != 0) { 175755434c77Sek110237 nvlist_free(nv); 1758e9dbad6fSeschrock goto nomem; 1759e9dbad6fSeschrock } 176055434c77Sek110237 if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 176155434c77Sek110237 zb[i].zb_object) != 0) { 176255434c77Sek110237 nvlist_free(nv); 176399653d4eSeschrock goto nomem; 1764ea8dc4b6Seschrock } 176555434c77Sek110237 if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 176655434c77Sek110237 nvlist_free(nv); 1767e9dbad6fSeschrock goto nomem; 1768e9dbad6fSeschrock } 176955434c77Sek110237 nvlist_free(nv); 1770e9dbad6fSeschrock } 1771e9dbad6fSeschrock 17723ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 1773ea8dc4b6Seschrock return (0); 177499653d4eSeschrock 177599653d4eSeschrock nomem: 1776e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 177799653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 1778ea8dc4b6Seschrock } 1779eaca9bbdSeschrock 1780eaca9bbdSeschrock /* 1781eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 1782eaca9bbdSeschrock */ 1783eaca9bbdSeschrock int 1784eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp) 1785eaca9bbdSeschrock { 1786eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 178799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1788eaca9bbdSeschrock 1789eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 1790ecd6cf80Smarks if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 1791ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 179299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 179399653d4eSeschrock zhp->zpool_name)); 1794eaca9bbdSeschrock return (0); 1795eaca9bbdSeschrock } 179606eeb2adSek110237 179706eeb2adSek110237 void 1798*2a6b87f0Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv, 1799*2a6b87f0Sek110237 char *history_str) 180006eeb2adSek110237 { 180106eeb2adSek110237 int i; 180206eeb2adSek110237 1803*2a6b87f0Sek110237 (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); 1804*2a6b87f0Sek110237 for (i = 1; i < argc; i++) { 1805*2a6b87f0Sek110237 if (strlen(history_str) + 1 + strlen(argv[i]) > 1806*2a6b87f0Sek110237 HIS_MAX_RECORD_LEN) 1807*2a6b87f0Sek110237 break; 1808*2a6b87f0Sek110237 (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN); 1809*2a6b87f0Sek110237 (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN); 1810*2a6b87f0Sek110237 } 1811*2a6b87f0Sek110237 } 1812*2a6b87f0Sek110237 1813*2a6b87f0Sek110237 /* 1814*2a6b87f0Sek110237 * Stage command history for logging. 1815*2a6b87f0Sek110237 */ 1816*2a6b87f0Sek110237 int 1817*2a6b87f0Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) 1818*2a6b87f0Sek110237 { 1819*2a6b87f0Sek110237 if (history_str == NULL) 1820*2a6b87f0Sek110237 return (EINVAL); 1821*2a6b87f0Sek110237 1822*2a6b87f0Sek110237 if (strlen(history_str) > HIS_MAX_RECORD_LEN) 1823*2a6b87f0Sek110237 return (EINVAL); 1824*2a6b87f0Sek110237 1825228975ccSek110237 if (hdl->libzfs_log_str != NULL) 1826ecd6cf80Smarks free(hdl->libzfs_log_str); 1827ecd6cf80Smarks 1828*2a6b87f0Sek110237 if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) 1829*2a6b87f0Sek110237 return (no_memory(hdl)); 1830ecd6cf80Smarks 1831*2a6b87f0Sek110237 return (0); 183206eeb2adSek110237 } 183306eeb2adSek110237 183406eeb2adSek110237 /* 183506eeb2adSek110237 * Perform ioctl to get some command history of a pool. 183606eeb2adSek110237 * 183706eeb2adSek110237 * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 183806eeb2adSek110237 * logical offset of the history buffer to start reading from. 183906eeb2adSek110237 * 184006eeb2adSek110237 * Upon return, 'off' is the next logical offset to read from and 184106eeb2adSek110237 * 'len' is the actual amount of bytes read into 'buf'. 184206eeb2adSek110237 */ 184306eeb2adSek110237 static int 184406eeb2adSek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 184506eeb2adSek110237 { 184606eeb2adSek110237 zfs_cmd_t zc = { 0 }; 184706eeb2adSek110237 libzfs_handle_t *hdl = zhp->zpool_hdl; 184806eeb2adSek110237 184906eeb2adSek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 185006eeb2adSek110237 185106eeb2adSek110237 zc.zc_history = (uint64_t)(uintptr_t)buf; 185206eeb2adSek110237 zc.zc_history_len = *len; 185306eeb2adSek110237 zc.zc_history_offset = *off; 185406eeb2adSek110237 185506eeb2adSek110237 if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 185606eeb2adSek110237 switch (errno) { 185706eeb2adSek110237 case EPERM: 1858ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 1859ece3d9b3Slling dgettext(TEXT_DOMAIN, 186006eeb2adSek110237 "cannot show history for pool '%s'"), 186106eeb2adSek110237 zhp->zpool_name)); 186206eeb2adSek110237 case ENOENT: 1863ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 186406eeb2adSek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 186506eeb2adSek110237 "'%s'"), zhp->zpool_name)); 1866d7306b64Sek110237 case ENOTSUP: 1867d7306b64Sek110237 return (zfs_error_fmt(hdl, EZFS_BADVERSION, 1868d7306b64Sek110237 dgettext(TEXT_DOMAIN, "cannot get history for pool " 1869d7306b64Sek110237 "'%s', pool must be upgraded"), zhp->zpool_name)); 187006eeb2adSek110237 default: 1871ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 187206eeb2adSek110237 dgettext(TEXT_DOMAIN, 187306eeb2adSek110237 "cannot get history for '%s'"), zhp->zpool_name)); 187406eeb2adSek110237 } 187506eeb2adSek110237 } 187606eeb2adSek110237 187706eeb2adSek110237 *len = zc.zc_history_len; 187806eeb2adSek110237 *off = zc.zc_history_offset; 187906eeb2adSek110237 188006eeb2adSek110237 return (0); 188106eeb2adSek110237 } 188206eeb2adSek110237 188306eeb2adSek110237 /* 188406eeb2adSek110237 * Process the buffer of nvlists, unpacking and storing each nvlist record 188506eeb2adSek110237 * into 'records'. 'leftover' is set to the number of bytes that weren't 188606eeb2adSek110237 * processed as there wasn't a complete record. 188706eeb2adSek110237 */ 188806eeb2adSek110237 static int 188906eeb2adSek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 189006eeb2adSek110237 nvlist_t ***records, uint_t *numrecords) 189106eeb2adSek110237 { 189206eeb2adSek110237 uint64_t reclen; 189306eeb2adSek110237 nvlist_t *nv; 189406eeb2adSek110237 int i; 189506eeb2adSek110237 189606eeb2adSek110237 while (bytes_read > sizeof (reclen)) { 189706eeb2adSek110237 189806eeb2adSek110237 /* get length of packed record (stored as little endian) */ 189906eeb2adSek110237 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 190006eeb2adSek110237 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 190106eeb2adSek110237 190206eeb2adSek110237 if (bytes_read < sizeof (reclen) + reclen) 190306eeb2adSek110237 break; 190406eeb2adSek110237 190506eeb2adSek110237 /* unpack record */ 190606eeb2adSek110237 if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 190706eeb2adSek110237 return (ENOMEM); 190806eeb2adSek110237 bytes_read -= sizeof (reclen) + reclen; 190906eeb2adSek110237 buf += sizeof (reclen) + reclen; 191006eeb2adSek110237 191106eeb2adSek110237 /* add record to nvlist array */ 191206eeb2adSek110237 (*numrecords)++; 191306eeb2adSek110237 if (ISP2(*numrecords + 1)) { 191406eeb2adSek110237 *records = realloc(*records, 191506eeb2adSek110237 *numrecords * 2 * sizeof (nvlist_t *)); 191606eeb2adSek110237 } 191706eeb2adSek110237 (*records)[*numrecords - 1] = nv; 191806eeb2adSek110237 } 191906eeb2adSek110237 192006eeb2adSek110237 *leftover = bytes_read; 192106eeb2adSek110237 return (0); 192206eeb2adSek110237 } 192306eeb2adSek110237 192406eeb2adSek110237 #define HIS_BUF_LEN (128*1024) 192506eeb2adSek110237 192606eeb2adSek110237 /* 192706eeb2adSek110237 * Retrieve the command history of a pool. 192806eeb2adSek110237 */ 192906eeb2adSek110237 int 193006eeb2adSek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 193106eeb2adSek110237 { 193206eeb2adSek110237 char buf[HIS_BUF_LEN]; 193306eeb2adSek110237 uint64_t off = 0; 193406eeb2adSek110237 nvlist_t **records = NULL; 193506eeb2adSek110237 uint_t numrecords = 0; 193606eeb2adSek110237 int err, i; 193706eeb2adSek110237 193806eeb2adSek110237 do { 193906eeb2adSek110237 uint64_t bytes_read = sizeof (buf); 194006eeb2adSek110237 uint64_t leftover; 194106eeb2adSek110237 194206eeb2adSek110237 if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 194306eeb2adSek110237 break; 194406eeb2adSek110237 194506eeb2adSek110237 /* if nothing else was read in, we're at EOF, just return */ 194606eeb2adSek110237 if (!bytes_read) 194706eeb2adSek110237 break; 194806eeb2adSek110237 194906eeb2adSek110237 if ((err = zpool_history_unpack(buf, bytes_read, 195006eeb2adSek110237 &leftover, &records, &numrecords)) != 0) 195106eeb2adSek110237 break; 195206eeb2adSek110237 off -= leftover; 195306eeb2adSek110237 195406eeb2adSek110237 /* CONSTCOND */ 195506eeb2adSek110237 } while (1); 195606eeb2adSek110237 195706eeb2adSek110237 if (!err) { 195806eeb2adSek110237 verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 195906eeb2adSek110237 verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 196006eeb2adSek110237 records, numrecords) == 0); 196106eeb2adSek110237 } 196206eeb2adSek110237 for (i = 0; i < numrecords; i++) 196306eeb2adSek110237 nvlist_free(records[i]); 196406eeb2adSek110237 free(records); 196506eeb2adSek110237 196606eeb2adSek110237 return (err); 196706eeb2adSek110237 } 196855434c77Sek110237 196955434c77Sek110237 void 197055434c77Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 197155434c77Sek110237 char *pathname, size_t len) 197255434c77Sek110237 { 197355434c77Sek110237 zfs_cmd_t zc = { 0 }; 197455434c77Sek110237 boolean_t mounted = B_FALSE; 197555434c77Sek110237 char *mntpnt = NULL; 197655434c77Sek110237 char dsname[MAXNAMELEN]; 197755434c77Sek110237 197855434c77Sek110237 if (dsobj == 0) { 197955434c77Sek110237 /* special case for the MOS */ 198055434c77Sek110237 (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 198155434c77Sek110237 return; 198255434c77Sek110237 } 198355434c77Sek110237 198455434c77Sek110237 /* get the dataset's name */ 198555434c77Sek110237 (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 198655434c77Sek110237 zc.zc_obj = dsobj; 198755434c77Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, 198855434c77Sek110237 ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 198955434c77Sek110237 /* just write out a path of two object numbers */ 199055434c77Sek110237 (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 199155434c77Sek110237 dsobj, obj); 199255434c77Sek110237 return; 199355434c77Sek110237 } 199455434c77Sek110237 (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 199555434c77Sek110237 199655434c77Sek110237 /* find out if the dataset is mounted */ 199755434c77Sek110237 mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 199855434c77Sek110237 199955434c77Sek110237 /* get the corrupted object's path */ 200055434c77Sek110237 (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 200155434c77Sek110237 zc.zc_obj = obj; 200255434c77Sek110237 if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 200355434c77Sek110237 &zc) == 0) { 200455434c77Sek110237 if (mounted) { 200555434c77Sek110237 (void) snprintf(pathname, len, "%s%s", mntpnt, 200655434c77Sek110237 zc.zc_value); 200755434c77Sek110237 } else { 200855434c77Sek110237 (void) snprintf(pathname, len, "%s:%s", 200955434c77Sek110237 dsname, zc.zc_value); 201055434c77Sek110237 } 201155434c77Sek110237 } else { 201255434c77Sek110237 (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 201355434c77Sek110237 } 201455434c77Sek110237 free(mntpnt); 201555434c77Sek110237 } 2016b1b8ab34Slling 20178488aeb5Staylor #define RDISK_ROOT "/dev/rdsk" 20188488aeb5Staylor #define BACKUP_SLICE "s2" 20198488aeb5Staylor /* 20208488aeb5Staylor * Don't start the slice at the default block of 34; many storage 20218488aeb5Staylor * devices will use a stripe width of 128k, so start there instead. 20228488aeb5Staylor */ 20238488aeb5Staylor #define NEW_START_BLOCK 256 20248488aeb5Staylor 20258488aeb5Staylor /* 20268488aeb5Staylor * determine where a partition starts on a disk in the current 20278488aeb5Staylor * configuration 20288488aeb5Staylor */ 20298488aeb5Staylor static diskaddr_t 20308488aeb5Staylor find_start_block(nvlist_t *config) 20318488aeb5Staylor { 20328488aeb5Staylor nvlist_t **child; 20338488aeb5Staylor uint_t c, children; 20348488aeb5Staylor char *path; 20358488aeb5Staylor diskaddr_t sb = MAXOFFSET_T; 20368488aeb5Staylor int fd; 20378488aeb5Staylor char diskname[MAXPATHLEN]; 20388488aeb5Staylor uint64_t wholedisk; 20398488aeb5Staylor 20408488aeb5Staylor if (nvlist_lookup_nvlist_array(config, 20418488aeb5Staylor ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) { 20428488aeb5Staylor if (nvlist_lookup_uint64(config, 20438488aeb5Staylor ZPOOL_CONFIG_WHOLE_DISK, 20448488aeb5Staylor &wholedisk) != 0 || !wholedisk) { 20458488aeb5Staylor return (MAXOFFSET_T); 20468488aeb5Staylor } 20478488aeb5Staylor if (nvlist_lookup_string(config, 20488488aeb5Staylor ZPOOL_CONFIG_PATH, &path) != 0) { 20498488aeb5Staylor return (MAXOFFSET_T); 20508488aeb5Staylor } 20518488aeb5Staylor 20528488aeb5Staylor (void) snprintf(diskname, sizeof (diskname), "%s%s", 20538488aeb5Staylor RDISK_ROOT, strrchr(path, '/')); 20548488aeb5Staylor if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { 20558488aeb5Staylor struct dk_gpt *vtoc; 20568488aeb5Staylor if (efi_alloc_and_read(fd, &vtoc) >= 0) { 20578488aeb5Staylor sb = vtoc->efi_parts[0].p_start; 20588488aeb5Staylor efi_free(vtoc); 20598488aeb5Staylor } 20608488aeb5Staylor (void) close(fd); 20618488aeb5Staylor } 20628488aeb5Staylor return (sb); 20638488aeb5Staylor } 20648488aeb5Staylor 20658488aeb5Staylor for (c = 0; c < children; c++) { 20668488aeb5Staylor sb = find_start_block(child[c]); 20678488aeb5Staylor if (sb != MAXOFFSET_T) { 20688488aeb5Staylor return (sb); 20698488aeb5Staylor } 20708488aeb5Staylor } 20718488aeb5Staylor return (MAXOFFSET_T); 20728488aeb5Staylor } 20738488aeb5Staylor 20748488aeb5Staylor /* 20758488aeb5Staylor * Label an individual disk. The name provided is the short name, 20768488aeb5Staylor * stripped of any leading /dev path. 20778488aeb5Staylor */ 20788488aeb5Staylor int 20798488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) 20808488aeb5Staylor { 20818488aeb5Staylor char path[MAXPATHLEN]; 20828488aeb5Staylor struct dk_gpt *vtoc; 20838488aeb5Staylor int fd; 20848488aeb5Staylor size_t resv = EFI_MIN_RESV_SIZE; 20858488aeb5Staylor uint64_t slice_size; 20868488aeb5Staylor diskaddr_t start_block; 20878488aeb5Staylor char errbuf[1024]; 20888488aeb5Staylor 20898488aeb5Staylor if (zhp) { 20908488aeb5Staylor nvlist_t *nvroot; 20918488aeb5Staylor 20928488aeb5Staylor verify(nvlist_lookup_nvlist(zhp->zpool_config, 20938488aeb5Staylor ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); 20948488aeb5Staylor 20958488aeb5Staylor if (zhp->zpool_start_block == 0) 20968488aeb5Staylor start_block = find_start_block(nvroot); 20978488aeb5Staylor else 20988488aeb5Staylor start_block = zhp->zpool_start_block; 20998488aeb5Staylor zhp->zpool_start_block = start_block; 21008488aeb5Staylor } else { 21018488aeb5Staylor /* new pool */ 21028488aeb5Staylor start_block = NEW_START_BLOCK; 21038488aeb5Staylor } 21048488aeb5Staylor 21058488aeb5Staylor (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 21068488aeb5Staylor BACKUP_SLICE); 21078488aeb5Staylor 21088488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 21098488aeb5Staylor /* 21108488aeb5Staylor * This shouldn't happen. We've long since verified that this 21118488aeb5Staylor * is a valid device. 21128488aeb5Staylor */ 21138488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 21148488aeb5Staylor "label '%s': unable to open device"), name); 21158488aeb5Staylor return (zfs_error(hdl, EZFS_OPENFAILED, errbuf)); 21168488aeb5Staylor } 21178488aeb5Staylor 21188488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) { 21198488aeb5Staylor /* 21208488aeb5Staylor * The only way this can fail is if we run out of memory, or we 21218488aeb5Staylor * were unable to read the disk's capacity 21228488aeb5Staylor */ 21238488aeb5Staylor if (errno == ENOMEM) 21248488aeb5Staylor (void) no_memory(hdl); 21258488aeb5Staylor 21268488aeb5Staylor (void) close(fd); 21278488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot " 21288488aeb5Staylor "label '%s': unable to read disk capacity"), name); 21298488aeb5Staylor 21308488aeb5Staylor return (zfs_error(hdl, EZFS_NOCAP, errbuf)); 21318488aeb5Staylor } 21328488aeb5Staylor 21338488aeb5Staylor slice_size = vtoc->efi_last_u_lba + 1; 21348488aeb5Staylor slice_size -= EFI_MIN_RESV_SIZE; 21358488aeb5Staylor if (start_block == MAXOFFSET_T) 21368488aeb5Staylor start_block = NEW_START_BLOCK; 21378488aeb5Staylor slice_size -= start_block; 21388488aeb5Staylor 21398488aeb5Staylor vtoc->efi_parts[0].p_start = start_block; 21408488aeb5Staylor vtoc->efi_parts[0].p_size = slice_size; 21418488aeb5Staylor 21428488aeb5Staylor /* 21438488aeb5Staylor * Why we use V_USR: V_BACKUP confuses users, and is considered 21448488aeb5Staylor * disposable by some EFI utilities (since EFI doesn't have a backup 21458488aeb5Staylor * slice). V_UNASSIGNED is supposed to be used only for zero size 21468488aeb5Staylor * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 21478488aeb5Staylor * etc. were all pretty specific. V_USR is as close to reality as we 21488488aeb5Staylor * can get, in the absence of V_OTHER. 21498488aeb5Staylor */ 21508488aeb5Staylor vtoc->efi_parts[0].p_tag = V_USR; 21518488aeb5Staylor (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 21528488aeb5Staylor 21538488aeb5Staylor vtoc->efi_parts[8].p_start = slice_size + start_block; 21548488aeb5Staylor vtoc->efi_parts[8].p_size = resv; 21558488aeb5Staylor vtoc->efi_parts[8].p_tag = V_RESERVED; 21568488aeb5Staylor 21578488aeb5Staylor if (efi_write(fd, vtoc) != 0) { 21588488aeb5Staylor /* 21598488aeb5Staylor * Some block drivers (like pcata) may not support EFI 21608488aeb5Staylor * GPT labels. Print out a helpful error message dir- 21618488aeb5Staylor * ecting the user to manually label the disk and give 21628488aeb5Staylor * a specific slice. 21638488aeb5Staylor */ 21648488aeb5Staylor (void) close(fd); 21658488aeb5Staylor efi_free(vtoc); 21668488aeb5Staylor 21678488aeb5Staylor zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 21688488aeb5Staylor "cannot label '%s': try using fdisk(1M) and then " 21698488aeb5Staylor "provide a specific slice"), name); 21708488aeb5Staylor return (zfs_error(hdl, EZFS_LABELFAILED, errbuf)); 21718488aeb5Staylor } 21728488aeb5Staylor 21738488aeb5Staylor (void) close(fd); 21748488aeb5Staylor efi_free(vtoc); 21758488aeb5Staylor return (0); 21768488aeb5Staylor } 21778488aeb5Staylor 2178b1b8ab34Slling int 2179b1b8ab34Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 2180b1b8ab34Slling { 2181b1b8ab34Slling zfs_cmd_t zc = { 0 }; 2182b1b8ab34Slling int ret = -1; 2183b1b8ab34Slling char errbuf[1024]; 2184b1b8ab34Slling nvlist_t *nvl = NULL; 2185b1b8ab34Slling nvlist_t *realprops; 2186b1b8ab34Slling 2187b1b8ab34Slling (void) snprintf(errbuf, sizeof (errbuf), 2188b1b8ab34Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 2189b1b8ab34Slling zhp->zpool_name); 2190b1b8ab34Slling 2191e7437265Sahrens if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) { 2192b1b8ab34Slling zfs_error_aux(zhp->zpool_hdl, 2193b1b8ab34Slling dgettext(TEXT_DOMAIN, "pool must be " 2194b1b8ab34Slling "upgraded to support pool properties")); 2195b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, errbuf)); 2196b1b8ab34Slling } 2197b1b8ab34Slling 2198b1b8ab34Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) 2199b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, errbuf)); 2200b1b8ab34Slling 2201b1b8ab34Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 2202b1b8ab34Slling nvlist_add_string(nvl, propname, propval) != 0) { 2203b1b8ab34Slling return (no_memory(zhp->zpool_hdl)); 2204b1b8ab34Slling } 2205b1b8ab34Slling 2206b1b8ab34Slling if ((realprops = zfs_validate_properties(zhp->zpool_hdl, ZFS_TYPE_POOL, 2207b1b8ab34Slling zhp->zpool_name, nvl, 0, NULL, errbuf)) == NULL) { 2208b1b8ab34Slling nvlist_free(nvl); 2209b1b8ab34Slling return (-1); 2210b1b8ab34Slling } 2211b1b8ab34Slling 2212b1b8ab34Slling nvlist_free(nvl); 2213b1b8ab34Slling nvl = realprops; 2214b1b8ab34Slling 2215b1b8ab34Slling /* 2216b1b8ab34Slling * Execute the corresponding ioctl() to set this property. 2217b1b8ab34Slling */ 2218b1b8ab34Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 2219b1b8ab34Slling 2220b1b8ab34Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl, NULL) != 0) 2221b1b8ab34Slling return (-1); 2222b1b8ab34Slling 2223ecd6cf80Smarks ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc); 2224b1b8ab34Slling zcmd_free_nvlists(&zc); 2225b1b8ab34Slling 2226b1b8ab34Slling if (ret) 2227b1b8ab34Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 2228b1b8ab34Slling 2229b1b8ab34Slling return (ret); 2230b1b8ab34Slling } 2231b1b8ab34Slling 22323d7072f8Seschrock uint64_t 22333d7072f8Seschrock zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop) 22343d7072f8Seschrock { 22353d7072f8Seschrock uint64_t value; 22363d7072f8Seschrock nvlist_t *nvp; 22373d7072f8Seschrock 2238e7437265Sahrens if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) 22393d7072f8Seschrock return (0); 22403d7072f8Seschrock 22413d7072f8Seschrock if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) 22423d7072f8Seschrock return (zpool_prop_default_numeric(prop)); 22433d7072f8Seschrock 22443d7072f8Seschrock switch (prop) { 22453d7072f8Seschrock case ZPOOL_PROP_AUTOREPLACE: 22463d7072f8Seschrock if (nvlist_lookup_nvlist(zhp->zpool_props, 22473d7072f8Seschrock zpool_prop_to_name(prop), &nvp) != 0) { 22483d7072f8Seschrock value = zpool_prop_default_numeric(prop); 22493d7072f8Seschrock } else { 22503d7072f8Seschrock VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE, 22513d7072f8Seschrock &value) == 0); 22523d7072f8Seschrock } 22533d7072f8Seschrock return (value); 22543d7072f8Seschrock break; 22553d7072f8Seschrock 22563d7072f8Seschrock default: 22573d7072f8Seschrock assert(0); 22583d7072f8Seschrock } 22593d7072f8Seschrock 22603d7072f8Seschrock return (0); 22613d7072f8Seschrock } 22623d7072f8Seschrock 2263b1b8ab34Slling int 2264b1b8ab34Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf, 2265b1b8ab34Slling size_t proplen, zfs_source_t *srctype) 2266b1b8ab34Slling { 2267b1b8ab34Slling uint64_t value; 2268b1b8ab34Slling char msg[1024], *strvalue; 2269b1b8ab34Slling nvlist_t *nvp; 2270b1b8ab34Slling zfs_source_t src = ZFS_SRC_NONE; 2271b1b8ab34Slling 2272b1b8ab34Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 2273b1b8ab34Slling "cannot get property '%s'"), zpool_prop_to_name(prop)); 2274b1b8ab34Slling 2275e7437265Sahrens if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) { 2276b1b8ab34Slling zfs_error_aux(zhp->zpool_hdl, 2277b1b8ab34Slling dgettext(TEXT_DOMAIN, "pool must be " 2278b1b8ab34Slling "upgraded to support pool properties")); 2279b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, msg)); 2280b1b8ab34Slling } 2281b1b8ab34Slling 22823d7072f8Seschrock if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) && 22833d7072f8Seschrock prop != ZPOOL_PROP_NAME) 2284b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, msg)); 2285b1b8ab34Slling 2286b1b8ab34Slling switch (prop) { 22873d7072f8Seschrock case ZPOOL_PROP_NAME: 2288b1b8ab34Slling (void) strlcpy(propbuf, zhp->zpool_name, proplen); 2289b1b8ab34Slling break; 2290b1b8ab34Slling 22913d7072f8Seschrock case ZPOOL_PROP_BOOTFS: 2292b1b8ab34Slling if (nvlist_lookup_nvlist(zhp->zpool_props, 2293b1b8ab34Slling zpool_prop_to_name(prop), &nvp) != 0) { 2294b1b8ab34Slling strvalue = (char *)zfs_prop_default_string(prop); 2295b1b8ab34Slling if (strvalue == NULL) 2296b1b8ab34Slling strvalue = "-"; 2297b1b8ab34Slling src = ZFS_SRC_DEFAULT; 2298b1b8ab34Slling } else { 2299b1b8ab34Slling VERIFY(nvlist_lookup_uint64(nvp, 2300b1b8ab34Slling ZFS_PROP_SOURCE, &value) == 0); 2301b1b8ab34Slling src = value; 2302b1b8ab34Slling VERIFY(nvlist_lookup_string(nvp, ZFS_PROP_VALUE, 2303b1b8ab34Slling &strvalue) == 0); 2304b1b8ab34Slling if (strlen(strvalue) >= proplen) 2305b1b8ab34Slling return (-1); 2306b1b8ab34Slling } 23073d7072f8Seschrock (void) strlcpy(propbuf, strvalue, proplen); 23083d7072f8Seschrock break; 23093d7072f8Seschrock 2310ecd6cf80Smarks case ZPOOL_PROP_DELEGATION: 23113d7072f8Seschrock case ZPOOL_PROP_AUTOREPLACE: 23123d7072f8Seschrock if (nvlist_lookup_nvlist(zhp->zpool_props, 23133d7072f8Seschrock zpool_prop_to_name(prop), &nvp) != 0) { 23143d7072f8Seschrock value = zpool_prop_default_numeric(prop); 23153d7072f8Seschrock src = ZFS_SRC_DEFAULT; 23163d7072f8Seschrock } else { 23173d7072f8Seschrock VERIFY(nvlist_lookup_uint64(nvp, 23183d7072f8Seschrock ZFS_PROP_SOURCE, &value) == 0); 23193d7072f8Seschrock src = value; 23203d7072f8Seschrock VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE, 23213d7072f8Seschrock &value) == 0); 23223d7072f8Seschrock } 23233d7072f8Seschrock (void) strlcpy(propbuf, value ? "on" : "off", proplen); 2324b1b8ab34Slling break; 2325b1b8ab34Slling 2326b1b8ab34Slling default: 2327b1b8ab34Slling return (-1); 2328b1b8ab34Slling } 2329b1b8ab34Slling if (srctype) 2330b1b8ab34Slling *srctype = src; 2331b1b8ab34Slling return (0); 2332b1b8ab34Slling } 2333b1b8ab34Slling 2334b1b8ab34Slling int 2335b1b8ab34Slling zpool_get_proplist(libzfs_handle_t *hdl, char *fields, zpool_proplist_t **listp) 2336b1b8ab34Slling { 2337b1b8ab34Slling return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_POOL)); 2338b1b8ab34Slling } 2339b1b8ab34Slling 2340b1b8ab34Slling 2341b1b8ab34Slling int 2342b1b8ab34Slling zpool_expand_proplist(zpool_handle_t *zhp, zpool_proplist_t **plp) 2343b1b8ab34Slling { 2344b1b8ab34Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 2345b1b8ab34Slling zpool_proplist_t *entry; 2346b1b8ab34Slling char buf[ZFS_MAXPROPLEN]; 2347b1b8ab34Slling 2348b1b8ab34Slling if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_POOL) != 0) 2349b1b8ab34Slling return (-1); 2350b1b8ab34Slling 2351b1b8ab34Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 2352b1b8ab34Slling 2353b1b8ab34Slling if (entry->pl_fixed) 2354b1b8ab34Slling continue; 2355b1b8ab34Slling 2356b1b8ab34Slling if (entry->pl_prop != ZFS_PROP_INVAL && 2357b1b8ab34Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 2358b1b8ab34Slling NULL) == 0) { 2359b1b8ab34Slling if (strlen(buf) > entry->pl_width) 2360b1b8ab34Slling entry->pl_width = strlen(buf); 2361b1b8ab34Slling } 2362b1b8ab34Slling } 2363b1b8ab34Slling 2364b1b8ab34Slling return (0); 2365b1b8ab34Slling } 2366