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> 41fa9e4066Sahrens #include <sys/zfs_ioctl.h> 42ea8dc4b6Seschrock #include <sys/zio.h> 4306eeb2adSek #include <strings.h> 44fa9e4066Sahrens 45fa9e4066Sahrens #include "zfs_namecheck.h" 46*b1b8ab34Slling #include "zfs_prop.h" 47fa9e4066Sahrens #include "libzfs_impl.h" 48fa9e4066Sahrens 49fa9e4066Sahrens /* 50fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 51fa9e4066Sahrens * 'buf'. 52fa9e4066Sahrens */ 5399653d4eSeschrock static boolean_t 5499653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 55fa9e4066Sahrens { 56fa9e4066Sahrens namecheck_err_t why; 57fa9e4066Sahrens char what; 58b468a217Seschrock int ret; 59b468a217Seschrock 60b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 61b468a217Seschrock 62b468a217Seschrock /* 63b468a217Seschrock * The rules for reserved pool names were extended at a later point. 64b468a217Seschrock * But we need to support users with existing pools that may now be 65b468a217Seschrock * invalid. So we only check for this expanded set of names during a 66b468a217Seschrock * create (or import), and only in userland. 67b468a217Seschrock */ 68b468a217Seschrock if (ret == 0 && !isopen && 69b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 70b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 71b468a217Seschrock strncmp(pool, "spare", 5) == 0)) { 7299653d4eSeschrock zfs_error_aux(hdl, 7399653d4eSeschrock dgettext(TEXT_DOMAIN, "name is reserved")); 7499653d4eSeschrock return (B_FALSE); 75b468a217Seschrock } 76b468a217Seschrock 77fa9e4066Sahrens 78b468a217Seschrock if (ret != 0) { 7999653d4eSeschrock if (hdl != NULL) { 80fa9e4066Sahrens switch (why) { 81b81d61a6Slling case NAME_ERR_TOOLONG: 8299653d4eSeschrock zfs_error_aux(hdl, 83b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 84b81d61a6Slling break; 85b81d61a6Slling 86fa9e4066Sahrens case NAME_ERR_INVALCHAR: 8799653d4eSeschrock zfs_error_aux(hdl, 88fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 89fa9e4066Sahrens "'%c' in pool name"), what); 90fa9e4066Sahrens break; 91fa9e4066Sahrens 92fa9e4066Sahrens case NAME_ERR_NOLETTER: 9399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9499653d4eSeschrock "name must begin with a letter")); 95fa9e4066Sahrens break; 96fa9e4066Sahrens 97fa9e4066Sahrens case NAME_ERR_RESERVED: 9899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9999653d4eSeschrock "name is reserved")); 100fa9e4066Sahrens break; 101fa9e4066Sahrens 102fa9e4066Sahrens case NAME_ERR_DISKLIKE: 10399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10499653d4eSeschrock "pool name is reserved")); 105fa9e4066Sahrens break; 1065ad82045Snd 1075ad82045Snd case NAME_ERR_LEADING_SLASH: 1085ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1095ad82045Snd "leading slash in name")); 1105ad82045Snd break; 1115ad82045Snd 1125ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 1135ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1145ad82045Snd "empty component in name")); 1155ad82045Snd break; 1165ad82045Snd 1175ad82045Snd case NAME_ERR_TRAILING_SLASH: 1185ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1195ad82045Snd "trailing slash in name")); 1205ad82045Snd break; 1215ad82045Snd 1225ad82045Snd case NAME_ERR_MULTIPLE_AT: 1235ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1245ad82045Snd "multiple '@' delimiters in name")); 1255ad82045Snd break; 1265ad82045Snd 127fa9e4066Sahrens } 128fa9e4066Sahrens } 12999653d4eSeschrock return (B_FALSE); 130fa9e4066Sahrens } 131fa9e4066Sahrens 13299653d4eSeschrock return (B_TRUE); 133fa9e4066Sahrens } 134fa9e4066Sahrens 135*b1b8ab34Slling static int 136*b1b8ab34Slling zpool_get_all_props(zpool_handle_t *zhp) 137*b1b8ab34Slling { 138*b1b8ab34Slling zfs_cmd_t zc = { 0 }; 139*b1b8ab34Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 140*b1b8ab34Slling 141*b1b8ab34Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 142*b1b8ab34Slling 143*b1b8ab34Slling if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 144*b1b8ab34Slling return (-1); 145*b1b8ab34Slling 146*b1b8ab34Slling while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) { 147*b1b8ab34Slling if (errno == ENOMEM) { 148*b1b8ab34Slling if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) { 149*b1b8ab34Slling zcmd_free_nvlists(&zc); 150*b1b8ab34Slling return (-1); 151*b1b8ab34Slling } 152*b1b8ab34Slling } else { 153*b1b8ab34Slling zcmd_free_nvlists(&zc); 154*b1b8ab34Slling return (-1); 155*b1b8ab34Slling } 156*b1b8ab34Slling } 157*b1b8ab34Slling 158*b1b8ab34Slling if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) { 159*b1b8ab34Slling zcmd_free_nvlists(&zc); 160*b1b8ab34Slling return (-1); 161*b1b8ab34Slling } 162*b1b8ab34Slling 163*b1b8ab34Slling zcmd_free_nvlists(&zc); 164*b1b8ab34Slling 165*b1b8ab34Slling return (0); 166*b1b8ab34Slling } 167*b1b8ab34Slling 168fa9e4066Sahrens /* 169fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 170fa9e4066Sahrens * state. 171fa9e4066Sahrens */ 172fa9e4066Sahrens zpool_handle_t * 17399653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 174fa9e4066Sahrens { 175fa9e4066Sahrens zpool_handle_t *zhp; 17694de1d4cSeschrock boolean_t missing; 177fa9e4066Sahrens 178fa9e4066Sahrens /* 179fa9e4066Sahrens * Make sure the pool name is valid. 180fa9e4066Sahrens */ 18199653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 182ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 18399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 18499653d4eSeschrock pool); 185fa9e4066Sahrens return (NULL); 186fa9e4066Sahrens } 187fa9e4066Sahrens 18899653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 18999653d4eSeschrock return (NULL); 190fa9e4066Sahrens 19199653d4eSeschrock zhp->zpool_hdl = hdl; 192fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 193fa9e4066Sahrens 19494de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 19594de1d4cSeschrock zpool_close(zhp); 19694de1d4cSeschrock return (NULL); 19794de1d4cSeschrock } 19894de1d4cSeschrock 19994de1d4cSeschrock if (missing) { 20094de1d4cSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20194de1d4cSeschrock "no such pool")); 202ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 20394de1d4cSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 20494de1d4cSeschrock pool); 20594de1d4cSeschrock zpool_close(zhp); 20694de1d4cSeschrock return (NULL); 207fa9e4066Sahrens } 208fa9e4066Sahrens 209fa9e4066Sahrens return (zhp); 210fa9e4066Sahrens } 211fa9e4066Sahrens 212fa9e4066Sahrens /* 213fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 214fa9e4066Sahrens * the configuration cache may be out of date). 215fa9e4066Sahrens */ 21694de1d4cSeschrock int 21794de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 218fa9e4066Sahrens { 219fa9e4066Sahrens zpool_handle_t *zhp; 22094de1d4cSeschrock boolean_t missing; 221fa9e4066Sahrens 22294de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 22394de1d4cSeschrock return (-1); 224fa9e4066Sahrens 22599653d4eSeschrock zhp->zpool_hdl = hdl; 226fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 227fa9e4066Sahrens 22894de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 22994de1d4cSeschrock zpool_close(zhp); 23094de1d4cSeschrock return (-1); 231fa9e4066Sahrens } 232fa9e4066Sahrens 23394de1d4cSeschrock if (missing) { 23494de1d4cSeschrock zpool_close(zhp); 23594de1d4cSeschrock *ret = NULL; 23694de1d4cSeschrock return (0); 23794de1d4cSeschrock } 23894de1d4cSeschrock 23994de1d4cSeschrock *ret = zhp; 24094de1d4cSeschrock return (0); 241fa9e4066Sahrens } 242fa9e4066Sahrens 243fa9e4066Sahrens /* 244fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 245fa9e4066Sahrens * state. 246fa9e4066Sahrens */ 247fa9e4066Sahrens zpool_handle_t * 24899653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 249fa9e4066Sahrens { 250fa9e4066Sahrens zpool_handle_t *zhp; 251fa9e4066Sahrens 25299653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 253fa9e4066Sahrens return (NULL); 254fa9e4066Sahrens 255fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 256ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 25799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 258fa9e4066Sahrens zpool_close(zhp); 259fa9e4066Sahrens return (NULL); 260fa9e4066Sahrens } 261fa9e4066Sahrens 262fa9e4066Sahrens return (zhp); 263fa9e4066Sahrens } 264fa9e4066Sahrens 265fa9e4066Sahrens /* 266fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 267fa9e4066Sahrens */ 268fa9e4066Sahrens void 269fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 270fa9e4066Sahrens { 271fa9e4066Sahrens if (zhp->zpool_config) 272fa9e4066Sahrens nvlist_free(zhp->zpool_config); 273088e9d47Seschrock if (zhp->zpool_old_config) 274088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 275*b1b8ab34Slling if (zhp->zpool_props) 276*b1b8ab34Slling nvlist_free(zhp->zpool_props); 277fa9e4066Sahrens free(zhp); 278fa9e4066Sahrens } 279fa9e4066Sahrens 280fa9e4066Sahrens /* 281fa9e4066Sahrens * Return the name of the pool. 282fa9e4066Sahrens */ 283fa9e4066Sahrens const char * 284fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 285fa9e4066Sahrens { 286fa9e4066Sahrens return (zhp->zpool_name); 287fa9e4066Sahrens } 288fa9e4066Sahrens 289fa9e4066Sahrens /* 290fa9e4066Sahrens * Return the GUID of the pool. 291fa9e4066Sahrens */ 292fa9e4066Sahrens uint64_t 293fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp) 294fa9e4066Sahrens { 295fa9e4066Sahrens uint64_t guid; 296fa9e4066Sahrens 297fa9e4066Sahrens verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID, 298fa9e4066Sahrens &guid) == 0); 299fa9e4066Sahrens return (guid); 300fa9e4066Sahrens } 301fa9e4066Sahrens 30299653d4eSeschrock /* 30399653d4eSeschrock * Return the version of the pool. 30499653d4eSeschrock */ 30599653d4eSeschrock uint64_t 30699653d4eSeschrock zpool_get_version(zpool_handle_t *zhp) 30799653d4eSeschrock { 30899653d4eSeschrock uint64_t version; 30999653d4eSeschrock 31099653d4eSeschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION, 31199653d4eSeschrock &version) == 0); 31299653d4eSeschrock 31399653d4eSeschrock return (version); 31499653d4eSeschrock } 31599653d4eSeschrock 316fa9e4066Sahrens /* 317fa9e4066Sahrens * Return the amount of space currently consumed by the pool. 318fa9e4066Sahrens */ 319fa9e4066Sahrens uint64_t 320fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp) 321fa9e4066Sahrens { 322fa9e4066Sahrens nvlist_t *nvroot; 323fa9e4066Sahrens vdev_stat_t *vs; 324fa9e4066Sahrens uint_t vsc; 325fa9e4066Sahrens 326fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 327fa9e4066Sahrens &nvroot) == 0); 328fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 329fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 330fa9e4066Sahrens 331fa9e4066Sahrens return (vs->vs_alloc); 332fa9e4066Sahrens } 333fa9e4066Sahrens 334fa9e4066Sahrens /* 335fa9e4066Sahrens * Return the total space in the pool. 336fa9e4066Sahrens */ 337fa9e4066Sahrens uint64_t 338fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp) 339fa9e4066Sahrens { 340fa9e4066Sahrens nvlist_t *nvroot; 341fa9e4066Sahrens vdev_stat_t *vs; 342fa9e4066Sahrens uint_t vsc; 343fa9e4066Sahrens 344fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 345fa9e4066Sahrens &nvroot) == 0); 346fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 347fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 348fa9e4066Sahrens 349fa9e4066Sahrens return (vs->vs_space); 350fa9e4066Sahrens } 351fa9e4066Sahrens 352fa9e4066Sahrens /* 353fa9e4066Sahrens * Return the alternate root for this pool, if any. 354fa9e4066Sahrens */ 355fa9e4066Sahrens int 356fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen) 357fa9e4066Sahrens { 358fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 359fa9e4066Sahrens 360fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 36199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 || 362e9dbad6fSeschrock zc.zc_value[0] == '\0') 363fa9e4066Sahrens return (-1); 364fa9e4066Sahrens 365e9dbad6fSeschrock (void) strlcpy(buf, zc.zc_value, buflen); 366fa9e4066Sahrens 367fa9e4066Sahrens return (0); 368fa9e4066Sahrens } 369fa9e4066Sahrens 370fa9e4066Sahrens /* 371fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 372fa9e4066Sahrens */ 373fa9e4066Sahrens int 374fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 375fa9e4066Sahrens { 376fa9e4066Sahrens return (zhp->zpool_state); 377fa9e4066Sahrens } 378fa9e4066Sahrens 379fa9e4066Sahrens /* 380fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 381fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 382fa9e4066Sahrens * don't have to worry about error semantics. 383fa9e4066Sahrens */ 384fa9e4066Sahrens int 38599653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 38699653d4eSeschrock const char *altroot) 387fa9e4066Sahrens { 388fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 38999653d4eSeschrock char msg[1024]; 390fa9e4066Sahrens 39199653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 39299653d4eSeschrock "cannot create '%s'"), pool); 393fa9e4066Sahrens 39499653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 39599653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 396fa9e4066Sahrens 39799653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 398ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 39999653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot)); 400fa9e4066Sahrens 401e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 40299653d4eSeschrock return (-1); 40399653d4eSeschrock 404fa9e4066Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 405fa9e4066Sahrens 406fa9e4066Sahrens if (altroot != NULL) 407e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 408fa9e4066Sahrens 40999653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) { 410e9dbad6fSeschrock zcmd_free_nvlists(&zc); 411fa9e4066Sahrens 41299653d4eSeschrock switch (errno) { 413fa9e4066Sahrens case EBUSY: 414fa9e4066Sahrens /* 415fa9e4066Sahrens * This can happen if the user has specified the same 416fa9e4066Sahrens * device multiple times. We can't reliably detect this 417fa9e4066Sahrens * until we try to add it and see we already have a 418fa9e4066Sahrens * label. 419fa9e4066Sahrens */ 42099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 42199653d4eSeschrock "one or more vdevs refer to the same device")); 42299653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 423fa9e4066Sahrens 424fa9e4066Sahrens case EOVERFLOW: 425fa9e4066Sahrens /* 42699653d4eSeschrock * This occurs when one of the devices is below 427fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 428fa9e4066Sahrens * device was the problem device since there's no 429fa9e4066Sahrens * reliable way to determine device size from userland. 430fa9e4066Sahrens */ 431fa9e4066Sahrens { 432fa9e4066Sahrens char buf[64]; 433fa9e4066Sahrens 434fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 435fa9e4066Sahrens 43699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 43799653d4eSeschrock "one or more devices is less than the " 43899653d4eSeschrock "minimum size (%s)"), buf); 439fa9e4066Sahrens } 44099653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 441fa9e4066Sahrens 442fa9e4066Sahrens case ENOSPC: 44399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 44499653d4eSeschrock "one or more devices is out of space")); 44599653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 446fa9e4066Sahrens 447fa9e4066Sahrens default: 44899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 449fa9e4066Sahrens } 450fa9e4066Sahrens } 451fa9e4066Sahrens 452e9dbad6fSeschrock zcmd_free_nvlists(&zc); 453fa9e4066Sahrens 454fa9e4066Sahrens /* 455fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 456e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 457fa9e4066Sahrens */ 458fa9e4066Sahrens if (altroot != NULL) { 459fa9e4066Sahrens zfs_handle_t *zhp; 460fa9e4066Sahrens 46199653d4eSeschrock verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL); 462e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 463e9dbad6fSeschrock "/") == 0); 464fa9e4066Sahrens 465fa9e4066Sahrens zfs_close(zhp); 466fa9e4066Sahrens } 467fa9e4066Sahrens 468fa9e4066Sahrens return (0); 469fa9e4066Sahrens } 470fa9e4066Sahrens 471fa9e4066Sahrens /* 472fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 473fa9e4066Sahrens * datasets left in the pool. 474fa9e4066Sahrens */ 475fa9e4066Sahrens int 476fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 477fa9e4066Sahrens { 478fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 479fa9e4066Sahrens zfs_handle_t *zfp = NULL; 48099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 48199653d4eSeschrock char msg[1024]; 482fa9e4066Sahrens 483fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 48499653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 48599653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 486fa9e4066Sahrens return (-1); 487fa9e4066Sahrens 4885ad82045Snd if (zpool_remove_zvol_links(zhp) != 0) 489fa9e4066Sahrens return (-1); 490fa9e4066Sahrens 491fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 492fa9e4066Sahrens 49399653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 49499653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 49599653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 496fa9e4066Sahrens 49799653d4eSeschrock if (errno == EROFS) { 49899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 49999653d4eSeschrock "one or more devices is read only")); 50099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 50199653d4eSeschrock } else { 50299653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 503fa9e4066Sahrens } 504fa9e4066Sahrens 505fa9e4066Sahrens if (zfp) 506fa9e4066Sahrens zfs_close(zfp); 507fa9e4066Sahrens return (-1); 508fa9e4066Sahrens } 509fa9e4066Sahrens 510fa9e4066Sahrens if (zfp) { 511fa9e4066Sahrens remove_mountpoint(zfp); 512fa9e4066Sahrens zfs_close(zfp); 513fa9e4066Sahrens } 514fa9e4066Sahrens 515fa9e4066Sahrens return (0); 516fa9e4066Sahrens } 517fa9e4066Sahrens 518fa9e4066Sahrens /* 519fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 520fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 521fa9e4066Sahrens */ 522fa9e4066Sahrens int 523fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 524fa9e4066Sahrens { 525e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 52699653d4eSeschrock int ret; 52799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 52899653d4eSeschrock char msg[1024]; 52999653d4eSeschrock nvlist_t **spares; 53099653d4eSeschrock uint_t nspares; 53199653d4eSeschrock 53299653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 53399653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 53499653d4eSeschrock 53599653d4eSeschrock if (zpool_get_version(zhp) < ZFS_VERSION_SPARES && 53699653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 53799653d4eSeschrock &spares, &nspares) == 0) { 53899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 53999653d4eSeschrock "upgraded to add hot spares")); 54099653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 54199653d4eSeschrock } 542fa9e4066Sahrens 543e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 54499653d4eSeschrock return (-1); 545fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 546fa9e4066Sahrens 54799653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) { 548fa9e4066Sahrens switch (errno) { 549fa9e4066Sahrens case EBUSY: 550fa9e4066Sahrens /* 551fa9e4066Sahrens * This can happen if the user has specified the same 552fa9e4066Sahrens * device multiple times. We can't reliably detect this 553fa9e4066Sahrens * until we try to add it and see we already have a 554fa9e4066Sahrens * label. 555fa9e4066Sahrens */ 55699653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 55799653d4eSeschrock "one or more vdevs refer to the same device")); 55899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 559fa9e4066Sahrens break; 560fa9e4066Sahrens 561fa9e4066Sahrens case EOVERFLOW: 562fa9e4066Sahrens /* 563fa9e4066Sahrens * This occurrs when one of the devices is below 564fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 565fa9e4066Sahrens * device was the problem device since there's no 566fa9e4066Sahrens * reliable way to determine device size from userland. 567fa9e4066Sahrens */ 568fa9e4066Sahrens { 569fa9e4066Sahrens char buf[64]; 570fa9e4066Sahrens 571fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 572fa9e4066Sahrens 57399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 57499653d4eSeschrock "device is less than the minimum " 57599653d4eSeschrock "size (%s)"), buf); 576fa9e4066Sahrens } 57799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 57899653d4eSeschrock break; 57999653d4eSeschrock 58099653d4eSeschrock case ENOTSUP: 58199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 58299653d4eSeschrock "pool must be upgraded to add raidz2 vdevs")); 58399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 584fa9e4066Sahrens break; 585fa9e4066Sahrens 586*b1b8ab34Slling case EDOM: 587*b1b8ab34Slling zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 588*b1b8ab34Slling "root pool can not have concatenated devices")); 589*b1b8ab34Slling (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg); 590*b1b8ab34Slling break; 591*b1b8ab34Slling 592fa9e4066Sahrens default: 59399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 594fa9e4066Sahrens } 595fa9e4066Sahrens 59699653d4eSeschrock ret = -1; 59799653d4eSeschrock } else { 59899653d4eSeschrock ret = 0; 599fa9e4066Sahrens } 600fa9e4066Sahrens 601e9dbad6fSeschrock zcmd_free_nvlists(&zc); 602fa9e4066Sahrens 60399653d4eSeschrock return (ret); 604fa9e4066Sahrens } 605fa9e4066Sahrens 606fa9e4066Sahrens /* 607fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 608fa9e4066Sahrens * mounted datasets in the pool. 609fa9e4066Sahrens */ 610fa9e4066Sahrens int 611fa9e4066Sahrens zpool_export(zpool_handle_t *zhp) 612fa9e4066Sahrens { 613fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 614fa9e4066Sahrens 615fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 616fa9e4066Sahrens return (-1); 617fa9e4066Sahrens 618fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 619fa9e4066Sahrens 62099653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0) 621ece3d9b3Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 62299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot export '%s'"), 62399653d4eSeschrock zhp->zpool_name)); 624fa9e4066Sahrens return (0); 625fa9e4066Sahrens } 626fa9e4066Sahrens 627fa9e4066Sahrens /* 628fa9e4066Sahrens * Import the given pool using the known configuration. The configuration 629fa9e4066Sahrens * should have come from zpool_find_import(). The 'newname' and 'altroot' 630fa9e4066Sahrens * parameters control whether the pool is imported with a different name or with 631fa9e4066Sahrens * an alternate root, respectively. 632fa9e4066Sahrens */ 633fa9e4066Sahrens int 63499653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 63599653d4eSeschrock const char *altroot) 636fa9e4066Sahrens { 637e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 638fa9e4066Sahrens char *thename; 639fa9e4066Sahrens char *origname; 640fa9e4066Sahrens int ret; 641fa9e4066Sahrens 642fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 643fa9e4066Sahrens &origname) == 0); 644fa9e4066Sahrens 645fa9e4066Sahrens if (newname != NULL) { 64699653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 647ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 64899653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 64999653d4eSeschrock newname)); 650fa9e4066Sahrens thename = (char *)newname; 651fa9e4066Sahrens } else { 652fa9e4066Sahrens thename = origname; 653fa9e4066Sahrens } 654fa9e4066Sahrens 65599653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 656ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 65799653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), 65899653d4eSeschrock altroot)); 659fa9e4066Sahrens 660fa9e4066Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 661fa9e4066Sahrens 662fa9e4066Sahrens if (altroot != NULL) 663e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 664fa9e4066Sahrens else 665e9dbad6fSeschrock zc.zc_value[0] = '\0'; 666fa9e4066Sahrens 667fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 668ea8dc4b6Seschrock &zc.zc_guid) == 0); 669fa9e4066Sahrens 670e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0) 67199653d4eSeschrock return (-1); 672fa9e4066Sahrens 673fa9e4066Sahrens ret = 0; 67499653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 675fa9e4066Sahrens char desc[1024]; 676fa9e4066Sahrens if (newname == NULL) 677fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 678fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 679fa9e4066Sahrens thename); 680fa9e4066Sahrens else 681fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 682fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 683fa9e4066Sahrens origname, thename); 684fa9e4066Sahrens 685fa9e4066Sahrens switch (errno) { 686ea8dc4b6Seschrock case ENOTSUP: 687ea8dc4b6Seschrock /* 688ea8dc4b6Seschrock * Unsupported version. 689ea8dc4b6Seschrock */ 69099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 691ea8dc4b6Seschrock break; 692ea8dc4b6Seschrock 693b5989ec7Seschrock case EINVAL: 694b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 695b5989ec7Seschrock break; 696b5989ec7Seschrock 697fa9e4066Sahrens default: 69899653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 699fa9e4066Sahrens } 700fa9e4066Sahrens 701fa9e4066Sahrens ret = -1; 702fa9e4066Sahrens } else { 703fa9e4066Sahrens zpool_handle_t *zhp; 704fa9e4066Sahrens /* 705fa9e4066Sahrens * This should never fail, but play it safe anyway. 706fa9e4066Sahrens */ 70794de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 70894de1d4cSeschrock ret = -1; 70994de1d4cSeschrock } else if (zhp != NULL) { 710fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 711fa9e4066Sahrens zpool_close(zhp); 712fa9e4066Sahrens } 713fa9e4066Sahrens } 714fa9e4066Sahrens 715e9dbad6fSeschrock zcmd_free_nvlists(&zc); 716fa9e4066Sahrens return (ret); 717fa9e4066Sahrens } 718fa9e4066Sahrens 719fa9e4066Sahrens /* 720fa9e4066Sahrens * Scrub the pool. 721fa9e4066Sahrens */ 722fa9e4066Sahrens int 723fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 724fa9e4066Sahrens { 725fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 726fa9e4066Sahrens char msg[1024]; 72799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 728fa9e4066Sahrens 729fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 730fa9e4066Sahrens zc.zc_cookie = type; 731fa9e4066Sahrens 73299653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0) 733fa9e4066Sahrens return (0); 734fa9e4066Sahrens 735fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 736fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 737fa9e4066Sahrens 73899653d4eSeschrock if (errno == EBUSY) 73999653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 74099653d4eSeschrock else 74199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 742fa9e4066Sahrens } 743fa9e4066Sahrens 744a43d325bSek /* 745a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 746a43d325bSek * spare; but FALSE if its an INUSE spare. 747a43d325bSek */ 74899653d4eSeschrock static nvlist_t * 74999653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, 750a43d325bSek boolean_t *avail_spare) 751ea8dc4b6Seschrock { 752ea8dc4b6Seschrock uint_t c, children; 753ea8dc4b6Seschrock nvlist_t **child; 75499653d4eSeschrock uint64_t theguid, present; 755ea8dc4b6Seschrock char *path; 756ea8dc4b6Seschrock uint64_t wholedisk = 0; 75799653d4eSeschrock nvlist_t *ret; 758ea8dc4b6Seschrock 75999653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0); 760ea8dc4b6Seschrock 761ea8dc4b6Seschrock if (search == NULL && 762ea8dc4b6Seschrock nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) { 763ea8dc4b6Seschrock /* 764ea8dc4b6Seschrock * If the device has never been present since import, the only 765ea8dc4b6Seschrock * reliable way to match the vdev is by GUID. 766ea8dc4b6Seschrock */ 76799653d4eSeschrock if (theguid == guid) 76899653d4eSeschrock return (nv); 769ea8dc4b6Seschrock } else if (search != NULL && 770ea8dc4b6Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 771ea8dc4b6Seschrock (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 772ea8dc4b6Seschrock &wholedisk); 773ea8dc4b6Seschrock if (wholedisk) { 774ea8dc4b6Seschrock /* 775ea8dc4b6Seschrock * For whole disks, the internal path has 's0', but the 776ea8dc4b6Seschrock * path passed in by the user doesn't. 777ea8dc4b6Seschrock */ 778ea8dc4b6Seschrock if (strlen(search) == strlen(path) - 2 && 779ea8dc4b6Seschrock strncmp(search, path, strlen(search)) == 0) 78099653d4eSeschrock return (nv); 781ea8dc4b6Seschrock } else if (strcmp(search, path) == 0) { 78299653d4eSeschrock return (nv); 783ea8dc4b6Seschrock } 784ea8dc4b6Seschrock } 785ea8dc4b6Seschrock 786ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 787ea8dc4b6Seschrock &child, &children) != 0) 78899653d4eSeschrock return (NULL); 789ea8dc4b6Seschrock 790ea8dc4b6Seschrock for (c = 0; c < children; c++) 79199653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 792a43d325bSek avail_spare)) != NULL) 793ea8dc4b6Seschrock return (ret); 794ea8dc4b6Seschrock 79599653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 79699653d4eSeschrock &child, &children) == 0) { 79799653d4eSeschrock for (c = 0; c < children; c++) { 79899653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 799a43d325bSek avail_spare)) != NULL) { 800a43d325bSek *avail_spare = B_TRUE; 80199653d4eSeschrock return (ret); 80299653d4eSeschrock } 80399653d4eSeschrock } 80499653d4eSeschrock } 80599653d4eSeschrock 80699653d4eSeschrock return (NULL); 807ea8dc4b6Seschrock } 808ea8dc4b6Seschrock 80999653d4eSeschrock nvlist_t * 810a43d325bSek zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) 811ea8dc4b6Seschrock { 812ea8dc4b6Seschrock char buf[MAXPATHLEN]; 813ea8dc4b6Seschrock const char *search; 814ea8dc4b6Seschrock char *end; 815ea8dc4b6Seschrock nvlist_t *nvroot; 816ea8dc4b6Seschrock uint64_t guid; 817ea8dc4b6Seschrock 8180917b783Seschrock guid = strtoull(path, &end, 10); 819ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 820ea8dc4b6Seschrock search = NULL; 821ea8dc4b6Seschrock } else if (path[0] != '/') { 822ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 823ea8dc4b6Seschrock search = buf; 824ea8dc4b6Seschrock } else { 825ea8dc4b6Seschrock search = path; 826ea8dc4b6Seschrock } 827ea8dc4b6Seschrock 828ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 829ea8dc4b6Seschrock &nvroot) == 0); 830ea8dc4b6Seschrock 831a43d325bSek *avail_spare = B_FALSE; 832a43d325bSek return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare)); 833a43d325bSek } 834a43d325bSek 835a43d325bSek /* 836a43d325bSek * Returns TRUE if the given guid corresponds to a spare (INUSE or not). 837a43d325bSek */ 838a43d325bSek static boolean_t 839a43d325bSek is_spare(zpool_handle_t *zhp, uint64_t guid) 840a43d325bSek { 841a43d325bSek uint64_t spare_guid; 842a43d325bSek nvlist_t *nvroot; 843a43d325bSek nvlist_t **spares; 844a43d325bSek uint_t nspares; 845a43d325bSek int i; 846a43d325bSek 847a43d325bSek verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 848a43d325bSek &nvroot) == 0); 849a43d325bSek if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 850a43d325bSek &spares, &nspares) == 0) { 851a43d325bSek for (i = 0; i < nspares; i++) { 852a43d325bSek verify(nvlist_lookup_uint64(spares[i], 853a43d325bSek ZPOOL_CONFIG_GUID, &spare_guid) == 0); 854a43d325bSek if (guid == spare_guid) 855a43d325bSek return (B_TRUE); 856a43d325bSek } 857a43d325bSek } 858a43d325bSek 859a43d325bSek return (B_FALSE); 860ea8dc4b6Seschrock } 861ea8dc4b6Seschrock 862fa9e4066Sahrens /* 863fa9e4066Sahrens * Bring the specified vdev online 864fa9e4066Sahrens */ 865fa9e4066Sahrens int 866fa9e4066Sahrens zpool_vdev_online(zpool_handle_t *zhp, const char *path) 867fa9e4066Sahrens { 868fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 869fa9e4066Sahrens char msg[1024]; 87099653d4eSeschrock nvlist_t *tgt; 871a43d325bSek boolean_t avail_spare; 87299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 873fa9e4066Sahrens 874ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 875ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot online %s"), path); 876ea8dc4b6Seschrock 877fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 878a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 87999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 880fa9e4066Sahrens 88199653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 882fa9e4066Sahrens 883a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 884a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 885a43d325bSek 88699653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0) 88799653d4eSeschrock return (0); 888fa9e4066Sahrens 88999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 890fa9e4066Sahrens } 891fa9e4066Sahrens 892fa9e4066Sahrens /* 893fa9e4066Sahrens * Take the specified vdev offline 894fa9e4066Sahrens */ 895fa9e4066Sahrens int 896441d80aaSlling zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp) 897fa9e4066Sahrens { 898fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 899fa9e4066Sahrens char msg[1024]; 90099653d4eSeschrock nvlist_t *tgt; 901a43d325bSek boolean_t avail_spare; 90299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 903fa9e4066Sahrens 904ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 905ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 906ea8dc4b6Seschrock 907fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 908a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 90999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 91099653d4eSeschrock 91199653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 912fa9e4066Sahrens 913a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 914a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 915a43d325bSek 916441d80aaSlling zc.zc_cookie = istmp; 917441d80aaSlling 91899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0) 919fa9e4066Sahrens return (0); 920fa9e4066Sahrens 921fa9e4066Sahrens switch (errno) { 92299653d4eSeschrock case EBUSY: 923fa9e4066Sahrens 924fa9e4066Sahrens /* 925fa9e4066Sahrens * There are no other replicas of this device. 926fa9e4066Sahrens */ 92799653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 928fa9e4066Sahrens 92999653d4eSeschrock default: 93099653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 931fa9e4066Sahrens } 93299653d4eSeschrock } 93399653d4eSeschrock 93499653d4eSeschrock /* 93599653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 93699653d4eSeschrock * a hot spare. 93799653d4eSeschrock */ 93899653d4eSeschrock static boolean_t 93999653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 94099653d4eSeschrock { 94199653d4eSeschrock nvlist_t **child; 94299653d4eSeschrock uint_t c, children; 94399653d4eSeschrock char *type; 94499653d4eSeschrock 94599653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 94699653d4eSeschrock &children) == 0) { 94799653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 94899653d4eSeschrock &type) == 0); 94999653d4eSeschrock 95099653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 95199653d4eSeschrock children == 2 && child[which] == tgt) 95299653d4eSeschrock return (B_TRUE); 95399653d4eSeschrock 95499653d4eSeschrock for (c = 0; c < children; c++) 95599653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 95699653d4eSeschrock return (B_TRUE); 95799653d4eSeschrock } 95899653d4eSeschrock 95999653d4eSeschrock return (B_FALSE); 960fa9e4066Sahrens } 961fa9e4066Sahrens 962fa9e4066Sahrens /* 963fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 964fa9e4066Sahrens * If 'replacing' is specified, tne new disk will replace the old one. 965fa9e4066Sahrens */ 966fa9e4066Sahrens int 967fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 968fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 969fa9e4066Sahrens { 970fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 971fa9e4066Sahrens char msg[1024]; 972fa9e4066Sahrens int ret; 97399653d4eSeschrock nvlist_t *tgt; 974a43d325bSek boolean_t avail_spare; 97599653d4eSeschrock uint64_t val; 97699653d4eSeschrock char *path; 97799653d4eSeschrock nvlist_t **child; 97899653d4eSeschrock uint_t children; 97999653d4eSeschrock nvlist_t *config_root; 98099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 981fa9e4066Sahrens 982ea8dc4b6Seschrock if (replacing) 983ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 984ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 985ea8dc4b6Seschrock else 986ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 987ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 988ea8dc4b6Seschrock 989fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 990a43d325bSek if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0) 99199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 99299653d4eSeschrock 993a43d325bSek if (avail_spare) 99499653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 99599653d4eSeschrock 99699653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 997fa9e4066Sahrens zc.zc_cookie = replacing; 998fa9e4066Sahrens 99999653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 100099653d4eSeschrock &child, &children) != 0 || children != 1) { 100199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 100299653d4eSeschrock "new device must be a single disk")); 100399653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 100499653d4eSeschrock } 100599653d4eSeschrock 100699653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 100799653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 100899653d4eSeschrock 100999653d4eSeschrock /* 101099653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 101199653d4eSeschrock * replace it with another hot spare. 101299653d4eSeschrock */ 101399653d4eSeschrock if (replacing && 101499653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 101599653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1016a43d325bSek (zpool_find_vdev(zhp, path, &avail_spare) == NULL || 1017a43d325bSek !avail_spare) && is_replacing_spare(config_root, tgt, 1)) { 101899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 101999653d4eSeschrock "can only be replaced by another hot spare")); 102099653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 102199653d4eSeschrock } 102299653d4eSeschrock 102399653d4eSeschrock /* 102499653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 102599653d4eSeschrock * already spared device. 102699653d4eSeschrock */ 102799653d4eSeschrock if (replacing && 102899653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1029a43d325bSek zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare && 103099653d4eSeschrock is_replacing_spare(config_root, tgt, 0)) { 103199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 103299653d4eSeschrock "device has already been replaced with a spare")); 103399653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 103499653d4eSeschrock } 103599653d4eSeschrock 1036e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 103799653d4eSeschrock return (-1); 1038fa9e4066Sahrens 103999653d4eSeschrock ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc); 1040fa9e4066Sahrens 1041e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1042fa9e4066Sahrens 1043fa9e4066Sahrens if (ret == 0) 1044fa9e4066Sahrens return (0); 1045fa9e4066Sahrens 1046fa9e4066Sahrens switch (errno) { 1047ea8dc4b6Seschrock case ENOTSUP: 1048fa9e4066Sahrens /* 1049fa9e4066Sahrens * Can't attach to or replace this type of vdev. 1050fa9e4066Sahrens */ 1051fa9e4066Sahrens if (replacing) 105299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 105399653d4eSeschrock "cannot replace a replacing device")); 1054fa9e4066Sahrens else 105599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 105699653d4eSeschrock "can only attach to mirrors and top-level " 105799653d4eSeschrock "disks")); 105899653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 1059fa9e4066Sahrens break; 1060fa9e4066Sahrens 1061ea8dc4b6Seschrock case EINVAL: 1062fa9e4066Sahrens /* 1063fa9e4066Sahrens * The new device must be a single disk. 1064fa9e4066Sahrens */ 106599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 106699653d4eSeschrock "new device must be a single disk")); 106799653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 1068fa9e4066Sahrens break; 1069fa9e4066Sahrens 1070ea8dc4b6Seschrock case EBUSY: 107199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 107299653d4eSeschrock new_disk); 107399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1074fa9e4066Sahrens break; 1075fa9e4066Sahrens 1076ea8dc4b6Seschrock case EOVERFLOW: 1077fa9e4066Sahrens /* 1078fa9e4066Sahrens * The new device is too small. 1079fa9e4066Sahrens */ 108099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 108199653d4eSeschrock "device is too small")); 108299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1083fa9e4066Sahrens break; 1084fa9e4066Sahrens 1085ea8dc4b6Seschrock case EDOM: 1086fa9e4066Sahrens /* 1087fa9e4066Sahrens * The new device has a different alignment requirement. 1088fa9e4066Sahrens */ 108999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 109099653d4eSeschrock "devices have different sector alignment")); 109199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1092fa9e4066Sahrens break; 1093fa9e4066Sahrens 1094ea8dc4b6Seschrock case ENAMETOOLONG: 1095fa9e4066Sahrens /* 1096fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 1097fa9e4066Sahrens */ 109899653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 1099fa9e4066Sahrens break; 1100fa9e4066Sahrens 1101ea8dc4b6Seschrock default: 110299653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1103fa9e4066Sahrens } 1104fa9e4066Sahrens 110599653d4eSeschrock return (-1); 1106fa9e4066Sahrens } 1107fa9e4066Sahrens 1108fa9e4066Sahrens /* 1109fa9e4066Sahrens * Detach the specified device. 1110fa9e4066Sahrens */ 1111fa9e4066Sahrens int 1112fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 1113fa9e4066Sahrens { 1114fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1115fa9e4066Sahrens char msg[1024]; 111699653d4eSeschrock nvlist_t *tgt; 1117a43d325bSek boolean_t avail_spare; 111899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1119fa9e4066Sahrens 1120ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1121ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 1122ea8dc4b6Seschrock 1123fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1124a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 112599653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1126fa9e4066Sahrens 1127a43d325bSek if (avail_spare) 112899653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 112999653d4eSeschrock 113099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 113199653d4eSeschrock 113299653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0) 1133fa9e4066Sahrens return (0); 1134fa9e4066Sahrens 1135fa9e4066Sahrens switch (errno) { 1136fa9e4066Sahrens 1137ea8dc4b6Seschrock case ENOTSUP: 1138fa9e4066Sahrens /* 1139fa9e4066Sahrens * Can't detach from this type of vdev. 1140fa9e4066Sahrens */ 114199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 114299653d4eSeschrock "applicable to mirror and replacing vdevs")); 114399653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 1144fa9e4066Sahrens break; 1145fa9e4066Sahrens 1146ea8dc4b6Seschrock case EBUSY: 1147fa9e4066Sahrens /* 1148fa9e4066Sahrens * There are no other replicas of this device. 1149fa9e4066Sahrens */ 115099653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 1151fa9e4066Sahrens break; 1152fa9e4066Sahrens 1153ea8dc4b6Seschrock default: 115499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1155ea8dc4b6Seschrock } 1156ea8dc4b6Seschrock 115799653d4eSeschrock return (-1); 115899653d4eSeschrock } 115999653d4eSeschrock 116099653d4eSeschrock /* 116199653d4eSeschrock * Remove the given device. Currently, this is supported only for hot spares. 116299653d4eSeschrock */ 116399653d4eSeschrock int 116499653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 116599653d4eSeschrock { 116699653d4eSeschrock zfs_cmd_t zc = { 0 }; 116799653d4eSeschrock char msg[1024]; 116899653d4eSeschrock nvlist_t *tgt; 1169a43d325bSek boolean_t avail_spare; 117099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 117199653d4eSeschrock 117299653d4eSeschrock (void) snprintf(msg, sizeof (msg), 117399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 117499653d4eSeschrock 117599653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1176a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 117799653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 117899653d4eSeschrock 1179a43d325bSek if (!avail_spare) { 118099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 118139c23413Seschrock "only inactive hot spares can be removed")); 118299653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 118399653d4eSeschrock } 118499653d4eSeschrock 118599653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 118699653d4eSeschrock 118799653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 118899653d4eSeschrock return (0); 118999653d4eSeschrock 119099653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1191ea8dc4b6Seschrock } 1192ea8dc4b6Seschrock 1193ea8dc4b6Seschrock /* 1194ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 1195ea8dc4b6Seschrock */ 1196ea8dc4b6Seschrock int 1197ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 1198ea8dc4b6Seschrock { 1199ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1200ea8dc4b6Seschrock char msg[1024]; 120199653d4eSeschrock nvlist_t *tgt; 1202a43d325bSek boolean_t avail_spare; 120399653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1204ea8dc4b6Seschrock 1205ea8dc4b6Seschrock if (path) 1206ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1207ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1208e9dbad6fSeschrock path); 1209ea8dc4b6Seschrock else 1210ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1211ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1212ea8dc4b6Seschrock zhp->zpool_name); 1213ea8dc4b6Seschrock 1214ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 121599653d4eSeschrock if (path) { 1216a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 121799653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1218ea8dc4b6Seschrock 1219a43d325bSek if (avail_spare) 122099653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1221ea8dc4b6Seschrock 122299653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 122399653d4eSeschrock &zc.zc_guid) == 0); 1224fa9e4066Sahrens } 1225fa9e4066Sahrens 122699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 122799653d4eSeschrock return (0); 122899653d4eSeschrock 122999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1230fa9e4066Sahrens } 1231fa9e4066Sahrens 1232f3861e1aSahl /* 1233f3861e1aSahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 1234f3861e1aSahl * hierarchy. 1235f3861e1aSahl */ 1236f3861e1aSahl int 1237f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 1238f3861e1aSahl void *data) 1239fa9e4066Sahrens { 1240f3861e1aSahl libzfs_handle_t *hdl = zhp->zpool_hdl; 1241f3861e1aSahl char (*paths)[MAXPATHLEN]; 1242f3861e1aSahl size_t size = 4; 1243f3861e1aSahl int curr, fd, base, ret = 0; 1244f3861e1aSahl DIR *dirp; 1245f3861e1aSahl struct dirent *dp; 1246f3861e1aSahl struct stat st; 1247f3861e1aSahl 1248f3861e1aSahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 1249f3861e1aSahl return (errno == ENOENT ? 0 : -1); 1250f3861e1aSahl 1251f3861e1aSahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 1252f3861e1aSahl int err = errno; 1253f3861e1aSahl (void) close(base); 1254f3861e1aSahl return (err == ENOENT ? 0 : -1); 1255f3861e1aSahl } 1256fa9e4066Sahrens 1257fa9e4066Sahrens /* 1258f3861e1aSahl * Oddly this wasn't a directory -- ignore that failure since we 1259f3861e1aSahl * know there are no links lower in the (non-existant) hierarchy. 1260fa9e4066Sahrens */ 1261f3861e1aSahl if (!S_ISDIR(st.st_mode)) { 1262f3861e1aSahl (void) close(base); 1263f3861e1aSahl return (0); 1264fa9e4066Sahrens } 1265fa9e4066Sahrens 1266f3861e1aSahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 1267f3861e1aSahl (void) close(base); 1268f3861e1aSahl return (-1); 1269f3861e1aSahl } 1270f3861e1aSahl 1271f3861e1aSahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 1272f3861e1aSahl curr = 0; 1273f3861e1aSahl 1274f3861e1aSahl while (curr >= 0) { 1275f3861e1aSahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 1276f3861e1aSahl goto err; 1277f3861e1aSahl 1278f3861e1aSahl if (S_ISDIR(st.st_mode)) { 1279f3861e1aSahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 1280f3861e1aSahl goto err; 1281f3861e1aSahl 1282f3861e1aSahl if ((dirp = fdopendir(fd)) == NULL) { 1283f3861e1aSahl (void) close(fd); 1284f3861e1aSahl goto err; 1285f3861e1aSahl } 1286f3861e1aSahl 1287f3861e1aSahl while ((dp = readdir(dirp)) != NULL) { 1288f3861e1aSahl if (dp->d_name[0] == '.') 1289f3861e1aSahl continue; 1290f3861e1aSahl 1291f3861e1aSahl if (curr + 1 == size) { 1292f3861e1aSahl paths = zfs_realloc(hdl, paths, 1293f3861e1aSahl size * sizeof (paths[0]), 1294f3861e1aSahl size * 2 * sizeof (paths[0])); 1295f3861e1aSahl if (paths == NULL) { 1296f3861e1aSahl (void) closedir(dirp); 1297f3861e1aSahl (void) close(fd); 1298f3861e1aSahl goto err; 1299f3861e1aSahl } 1300f3861e1aSahl 1301f3861e1aSahl size *= 2; 1302f3861e1aSahl } 1303f3861e1aSahl 1304f3861e1aSahl (void) strlcpy(paths[curr + 1], paths[curr], 1305f3861e1aSahl sizeof (paths[curr + 1])); 1306f3861e1aSahl (void) strlcat(paths[curr], "/", 1307f3861e1aSahl sizeof (paths[curr])); 1308f3861e1aSahl (void) strlcat(paths[curr], dp->d_name, 1309f3861e1aSahl sizeof (paths[curr])); 1310f3861e1aSahl curr++; 1311f3861e1aSahl } 1312f3861e1aSahl 1313f3861e1aSahl (void) closedir(dirp); 1314f3861e1aSahl 1315f3861e1aSahl } else { 1316f3861e1aSahl if ((ret = cb(paths[curr], data)) != 0) 1317f3861e1aSahl break; 1318f3861e1aSahl } 1319f3861e1aSahl 1320f3861e1aSahl curr--; 1321f3861e1aSahl } 1322f3861e1aSahl 1323f3861e1aSahl free(paths); 1324f3861e1aSahl (void) close(base); 1325f3861e1aSahl 1326f3861e1aSahl return (ret); 1327f3861e1aSahl 1328f3861e1aSahl err: 1329f3861e1aSahl free(paths); 1330f3861e1aSahl (void) close(base); 1331f3861e1aSahl return (-1); 1332f3861e1aSahl } 1333f3861e1aSahl 1334f3861e1aSahl typedef struct zvol_cb { 1335f3861e1aSahl zpool_handle_t *zcb_pool; 1336f3861e1aSahl boolean_t zcb_create; 1337f3861e1aSahl } zvol_cb_t; 1338f3861e1aSahl 1339f3861e1aSahl /*ARGSUSED*/ 1340f3861e1aSahl static int 1341f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data) 1342f3861e1aSahl { 1343f3861e1aSahl int ret; 1344f3861e1aSahl 1345f3861e1aSahl if (ZFS_IS_VOLUME(zhp)) 1346f3861e1aSahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 1347f3861e1aSahl 1348f3861e1aSahl ret = zfs_iter_children(zhp, do_zvol_create, NULL); 1349fa9e4066Sahrens 1350fa9e4066Sahrens zfs_close(zhp); 1351f3861e1aSahl 1352fa9e4066Sahrens return (ret); 1353fa9e4066Sahrens } 1354fa9e4066Sahrens 1355fa9e4066Sahrens /* 1356fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 1357fa9e4066Sahrens */ 1358fa9e4066Sahrens int 1359fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 1360fa9e4066Sahrens { 1361fa9e4066Sahrens zfs_handle_t *zfp; 1362fa9e4066Sahrens int ret; 1363fa9e4066Sahrens 1364fa9e4066Sahrens /* 1365fa9e4066Sahrens * If the pool is unavailable, just return success. 1366fa9e4066Sahrens */ 136799653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 136899653d4eSeschrock zhp->zpool_name)) == NULL) 1369fa9e4066Sahrens return (0); 1370fa9e4066Sahrens 1371f3861e1aSahl ret = zfs_iter_children(zfp, do_zvol_create, NULL); 1372fa9e4066Sahrens 1373fa9e4066Sahrens zfs_close(zfp); 1374fa9e4066Sahrens return (ret); 1375fa9e4066Sahrens } 1376fa9e4066Sahrens 1377f3861e1aSahl static int 1378f3861e1aSahl do_zvol_remove(const char *dataset, void *data) 1379f3861e1aSahl { 1380f3861e1aSahl zpool_handle_t *zhp = data; 1381f3861e1aSahl 1382f3861e1aSahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 1383f3861e1aSahl } 1384f3861e1aSahl 1385fa9e4066Sahrens /* 1386f3861e1aSahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 1387f3861e1aSahl * by examining the /dev links so that a corrupted pool doesn't impede this 1388f3861e1aSahl * operation. 1389fa9e4066Sahrens */ 1390fa9e4066Sahrens int 1391fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 1392fa9e4066Sahrens { 1393f3861e1aSahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 1394fa9e4066Sahrens } 1395c67d9675Seschrock 1396c67d9675Seschrock /* 1397c67d9675Seschrock * Convert from a devid string to a path. 1398c67d9675Seschrock */ 1399c67d9675Seschrock static char * 1400c67d9675Seschrock devid_to_path(char *devid_str) 1401c67d9675Seschrock { 1402c67d9675Seschrock ddi_devid_t devid; 1403c67d9675Seschrock char *minor; 1404c67d9675Seschrock char *path; 1405c67d9675Seschrock devid_nmlist_t *list = NULL; 1406c67d9675Seschrock int ret; 1407c67d9675Seschrock 1408c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 1409c67d9675Seschrock return (NULL); 1410c67d9675Seschrock 1411c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 1412c67d9675Seschrock 1413c67d9675Seschrock devid_str_free(minor); 1414c67d9675Seschrock devid_free(devid); 1415c67d9675Seschrock 1416c67d9675Seschrock if (ret != 0) 1417c67d9675Seschrock return (NULL); 1418c67d9675Seschrock 141999653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 142099653d4eSeschrock return (NULL); 142199653d4eSeschrock 1422c67d9675Seschrock devid_free_nmlist(list); 1423c67d9675Seschrock 1424c67d9675Seschrock return (path); 1425c67d9675Seschrock } 1426c67d9675Seschrock 1427c67d9675Seschrock /* 1428c67d9675Seschrock * Convert from a path to a devid string. 1429c67d9675Seschrock */ 1430c67d9675Seschrock static char * 1431c67d9675Seschrock path_to_devid(const char *path) 1432c67d9675Seschrock { 1433c67d9675Seschrock int fd; 1434c67d9675Seschrock ddi_devid_t devid; 1435c67d9675Seschrock char *minor, *ret; 1436c67d9675Seschrock 1437c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 1438c67d9675Seschrock return (NULL); 1439c67d9675Seschrock 1440c67d9675Seschrock minor = NULL; 1441c67d9675Seschrock ret = NULL; 1442c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 1443c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 1444c67d9675Seschrock ret = devid_str_encode(devid, minor); 1445c67d9675Seschrock if (minor != NULL) 1446c67d9675Seschrock devid_str_free(minor); 1447c67d9675Seschrock devid_free(devid); 1448c67d9675Seschrock } 1449c67d9675Seschrock (void) close(fd); 1450c67d9675Seschrock 1451c67d9675Seschrock return (ret); 1452c67d9675Seschrock } 1453c67d9675Seschrock 1454c67d9675Seschrock /* 1455c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 1456c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 1457c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 1458c67d9675Seschrock */ 1459c67d9675Seschrock static void 1460c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 1461c67d9675Seschrock { 1462c67d9675Seschrock zfs_cmd_t zc = { 0 }; 1463c67d9675Seschrock 1464c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1465e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 1466c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1467ea8dc4b6Seschrock &zc.zc_guid) == 0); 1468c67d9675Seschrock 146999653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 1470c67d9675Seschrock } 1471c67d9675Seschrock 1472c67d9675Seschrock /* 1473c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 1474c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 1475c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 1476c67d9675Seschrock * trailing 's0' slice name. 1477c67d9675Seschrock * 1478c67d9675Seschrock * This routine is also responsible for identifying when disks have been 1479c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 1480c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 1481c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 1482c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 1483c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 1484c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 1485c67d9675Seschrock * of these checks. 1486c67d9675Seschrock */ 1487c67d9675Seschrock char * 148899653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 1489c67d9675Seschrock { 1490c67d9675Seschrock char *path, *devid; 1491ea8dc4b6Seschrock uint64_t value; 1492ea8dc4b6Seschrock char buf[64]; 1493c67d9675Seschrock 1494ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1495ea8dc4b6Seschrock &value) == 0) { 1496ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1497ea8dc4b6Seschrock &value) == 0); 14985ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 14995ad82045Snd (u_longlong_t)value); 1500ea8dc4b6Seschrock path = buf; 1501ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 1502c67d9675Seschrock 1503c67d9675Seschrock if (zhp != NULL && 1504c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 1505c67d9675Seschrock /* 1506c67d9675Seschrock * Determine if the current path is correct. 1507c67d9675Seschrock */ 1508c67d9675Seschrock char *newdevid = path_to_devid(path); 1509c67d9675Seschrock 1510c67d9675Seschrock if (newdevid == NULL || 1511c67d9675Seschrock strcmp(devid, newdevid) != 0) { 1512c67d9675Seschrock char *newpath; 1513c67d9675Seschrock 1514c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 1515c67d9675Seschrock /* 1516c67d9675Seschrock * Update the path appropriately. 1517c67d9675Seschrock */ 1518c67d9675Seschrock set_path(zhp, nv, newpath); 151999653d4eSeschrock if (nvlist_add_string(nv, 152099653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 152199653d4eSeschrock verify(nvlist_lookup_string(nv, 152299653d4eSeschrock ZPOOL_CONFIG_PATH, 152399653d4eSeschrock &path) == 0); 1524c67d9675Seschrock free(newpath); 1525c67d9675Seschrock } 1526c67d9675Seschrock } 1527c67d9675Seschrock 152899653d4eSeschrock if (newdevid) 152999653d4eSeschrock devid_str_free(newdevid); 1530c67d9675Seschrock } 1531c67d9675Seschrock 1532c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 1533c67d9675Seschrock path += 9; 1534c67d9675Seschrock 1535c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1536ea8dc4b6Seschrock &value) == 0 && value) { 153799653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 153899653d4eSeschrock if (tmp == NULL) 153999653d4eSeschrock return (NULL); 1540c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 1541c67d9675Seschrock return (tmp); 1542c67d9675Seschrock } 1543c67d9675Seschrock } else { 1544c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 154599653d4eSeschrock 154699653d4eSeschrock /* 154799653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 154899653d4eSeschrock */ 154999653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 155099653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 155199653d4eSeschrock &value) == 0); 155299653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 15535ad82045Snd (u_longlong_t)value); 155499653d4eSeschrock path = buf; 155599653d4eSeschrock } 1556c67d9675Seschrock } 1557c67d9675Seschrock 155899653d4eSeschrock return (zfs_strdup(hdl, path)); 1559c67d9675Seschrock } 1560ea8dc4b6Seschrock 1561ea8dc4b6Seschrock static int 1562ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 1563ea8dc4b6Seschrock { 1564ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 1565ea8dc4b6Seschrock } 1566ea8dc4b6Seschrock 1567ea8dc4b6Seschrock /* 1568ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 1569ea8dc4b6Seschrock * caller. 1570ea8dc4b6Seschrock */ 1571ea8dc4b6Seschrock int 157255434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 1573ea8dc4b6Seschrock { 1574ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1575ea8dc4b6Seschrock uint64_t count; 1576e9dbad6fSeschrock zbookmark_t *zb = NULL; 157755434c77Sek int i; 1578ea8dc4b6Seschrock 1579ea8dc4b6Seschrock /* 1580ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 1581ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 1582ea8dc4b6Seschrock * entire list. 1583ea8dc4b6Seschrock */ 1584ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 1585ea8dc4b6Seschrock &count) == 0); 1586e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 15875ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 158899653d4eSeschrock return (-1); 1589e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 1590ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 1591ea8dc4b6Seschrock for (;;) { 159299653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 159399653d4eSeschrock &zc) != 0) { 1594e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 1595ea8dc4b6Seschrock if (errno == ENOMEM) { 1596bf561db0Svb count = zc.zc_nvlist_dst_size; 1597e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 1598bf561db0Svb zfs_alloc(zhp->zpool_hdl, count * 1599bf561db0Svb sizeof (zbookmark_t))) == (uintptr_t)NULL) 160099653d4eSeschrock return (-1); 1601ea8dc4b6Seschrock } else { 1602ea8dc4b6Seschrock return (-1); 1603ea8dc4b6Seschrock } 1604ea8dc4b6Seschrock } else { 1605ea8dc4b6Seschrock break; 1606ea8dc4b6Seschrock } 1607ea8dc4b6Seschrock } 1608ea8dc4b6Seschrock 1609ea8dc4b6Seschrock /* 1610ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 1611ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 1612e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 1613ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 1614ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 1615ea8dc4b6Seschrock */ 1616e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 1617e9dbad6fSeschrock zc.zc_nvlist_dst_size; 1618e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 1619ea8dc4b6Seschrock 1620ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 1621ea8dc4b6Seschrock 162255434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 1623ea8dc4b6Seschrock 1624ea8dc4b6Seschrock /* 162555434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 1626ea8dc4b6Seschrock */ 1627ea8dc4b6Seschrock for (i = 0; i < count; i++) { 1628ea8dc4b6Seschrock nvlist_t *nv; 1629ea8dc4b6Seschrock 1630c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 1631c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 1632c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 1633ea8dc4b6Seschrock continue; 1634ea8dc4b6Seschrock 163555434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 163655434c77Sek goto nomem; 163755434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 163855434c77Sek zb[i].zb_objset) != 0) { 163955434c77Sek nvlist_free(nv); 164099653d4eSeschrock goto nomem; 1641ea8dc4b6Seschrock } 164255434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 164355434c77Sek zb[i].zb_object) != 0) { 164455434c77Sek nvlist_free(nv); 164555434c77Sek goto nomem; 164655434c77Sek } 164755434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 164855434c77Sek nvlist_free(nv); 164955434c77Sek goto nomem; 165055434c77Sek } 165155434c77Sek nvlist_free(nv); 1652ea8dc4b6Seschrock } 1653ea8dc4b6Seschrock 16543ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 1655ea8dc4b6Seschrock return (0); 165699653d4eSeschrock 165799653d4eSeschrock nomem: 1658e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 165999653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 1660ea8dc4b6Seschrock } 1661eaca9bbdSeschrock 1662eaca9bbdSeschrock /* 1663eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 1664eaca9bbdSeschrock */ 1665eaca9bbdSeschrock int 1666eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp) 1667eaca9bbdSeschrock { 1668eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 166999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1670eaca9bbdSeschrock 1671eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 167299653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 1673ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 167499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 167599653d4eSeschrock zhp->zpool_name)); 1676eaca9bbdSeschrock 1677eaca9bbdSeschrock return (0); 1678eaca9bbdSeschrock } 167906eeb2adSek 168006eeb2adSek /* 168106eeb2adSek * Log command history. 168206eeb2adSek * 168306eeb2adSek * 'pool' is B_TRUE if we are logging a command for 'zpool'; B_FALSE 168406eeb2adSek * otherwise ('zfs'). 'pool_create' is B_TRUE if we are logging the creation 168506eeb2adSek * of the pool; B_FALSE otherwise. 'path' is the pathanme containing the 168606eeb2adSek * poolname. 'argc' and 'argv' are used to construct the command string. 168706eeb2adSek */ 168806eeb2adSek void 168906eeb2adSek zpool_log_history(libzfs_handle_t *hdl, int argc, char **argv, const char *path, 1690*b1b8ab34Slling boolean_t pool, boolean_t pool_create) 169106eeb2adSek { 169206eeb2adSek char cmd_buf[HIS_MAX_RECORD_LEN]; 169306eeb2adSek char *dspath; 169406eeb2adSek zfs_cmd_t zc = { 0 }; 169506eeb2adSek int i; 169606eeb2adSek 169706eeb2adSek /* construct the command string */ 169806eeb2adSek (void) strcpy(cmd_buf, pool ? "zpool" : "zfs"); 169906eeb2adSek for (i = 0; i < argc; i++) { 170006eeb2adSek if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN) 170106eeb2adSek break; 170206eeb2adSek (void) strcat(cmd_buf, " "); 170306eeb2adSek (void) strcat(cmd_buf, argv[i]); 170406eeb2adSek } 170506eeb2adSek 170606eeb2adSek /* figure out the poolname */ 170706eeb2adSek dspath = strpbrk(path, "/@"); 170806eeb2adSek if (dspath == NULL) { 170906eeb2adSek (void) strcpy(zc.zc_name, path); 171006eeb2adSek } else { 171106eeb2adSek (void) strncpy(zc.zc_name, path, dspath - path); 171206eeb2adSek zc.zc_name[dspath-path] = '\0'; 171306eeb2adSek } 171406eeb2adSek 171506eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)cmd_buf; 171606eeb2adSek zc.zc_history_len = strlen(cmd_buf); 171706eeb2adSek 171806eeb2adSek /* overloading zc_history_offset */ 171906eeb2adSek zc.zc_history_offset = pool_create; 172006eeb2adSek 172106eeb2adSek (void) ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_LOG_HISTORY, &zc); 172206eeb2adSek } 172306eeb2adSek 172406eeb2adSek /* 172506eeb2adSek * Perform ioctl to get some command history of a pool. 172606eeb2adSek * 172706eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 172806eeb2adSek * logical offset of the history buffer to start reading from. 172906eeb2adSek * 173006eeb2adSek * Upon return, 'off' is the next logical offset to read from and 173106eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 173206eeb2adSek */ 173306eeb2adSek static int 173406eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 173506eeb2adSek { 173606eeb2adSek zfs_cmd_t zc = { 0 }; 173706eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 173806eeb2adSek 173906eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 174006eeb2adSek 174106eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 174206eeb2adSek zc.zc_history_len = *len; 174306eeb2adSek zc.zc_history_offset = *off; 174406eeb2adSek 174506eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 174606eeb2adSek switch (errno) { 174706eeb2adSek case EPERM: 1748ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 1749ece3d9b3Slling dgettext(TEXT_DOMAIN, 175006eeb2adSek "cannot show history for pool '%s'"), 175106eeb2adSek zhp->zpool_name)); 175206eeb2adSek case ENOENT: 1753ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 175406eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 175506eeb2adSek "'%s'"), zhp->zpool_name)); 1756d7306b64Sek case ENOTSUP: 1757d7306b64Sek return (zfs_error_fmt(hdl, EZFS_BADVERSION, 1758d7306b64Sek dgettext(TEXT_DOMAIN, "cannot get history for pool " 1759d7306b64Sek "'%s', pool must be upgraded"), zhp->zpool_name)); 176006eeb2adSek default: 1761ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 176206eeb2adSek dgettext(TEXT_DOMAIN, 176306eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 176406eeb2adSek } 176506eeb2adSek } 176606eeb2adSek 176706eeb2adSek *len = zc.zc_history_len; 176806eeb2adSek *off = zc.zc_history_offset; 176906eeb2adSek 177006eeb2adSek return (0); 177106eeb2adSek } 177206eeb2adSek 177306eeb2adSek /* 177406eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 177506eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 177606eeb2adSek * processed as there wasn't a complete record. 177706eeb2adSek */ 177806eeb2adSek static int 177906eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 178006eeb2adSek nvlist_t ***records, uint_t *numrecords) 178106eeb2adSek { 178206eeb2adSek uint64_t reclen; 178306eeb2adSek nvlist_t *nv; 178406eeb2adSek int i; 178506eeb2adSek 178606eeb2adSek while (bytes_read > sizeof (reclen)) { 178706eeb2adSek 178806eeb2adSek /* get length of packed record (stored as little endian) */ 178906eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 179006eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 179106eeb2adSek 179206eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 179306eeb2adSek break; 179406eeb2adSek 179506eeb2adSek /* unpack record */ 179606eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 179706eeb2adSek return (ENOMEM); 179806eeb2adSek bytes_read -= sizeof (reclen) + reclen; 179906eeb2adSek buf += sizeof (reclen) + reclen; 180006eeb2adSek 180106eeb2adSek /* add record to nvlist array */ 180206eeb2adSek (*numrecords)++; 180306eeb2adSek if (ISP2(*numrecords + 1)) { 180406eeb2adSek *records = realloc(*records, 180506eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 180606eeb2adSek } 180706eeb2adSek (*records)[*numrecords - 1] = nv; 180806eeb2adSek } 180906eeb2adSek 181006eeb2adSek *leftover = bytes_read; 181106eeb2adSek return (0); 181206eeb2adSek } 181306eeb2adSek 181406eeb2adSek #define HIS_BUF_LEN (128*1024) 181506eeb2adSek 181606eeb2adSek /* 181706eeb2adSek * Retrieve the command history of a pool. 181806eeb2adSek */ 181906eeb2adSek int 182006eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 182106eeb2adSek { 182206eeb2adSek char buf[HIS_BUF_LEN]; 182306eeb2adSek uint64_t off = 0; 182406eeb2adSek nvlist_t **records = NULL; 182506eeb2adSek uint_t numrecords = 0; 182606eeb2adSek int err, i; 182706eeb2adSek 182806eeb2adSek do { 182906eeb2adSek uint64_t bytes_read = sizeof (buf); 183006eeb2adSek uint64_t leftover; 183106eeb2adSek 183206eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 183306eeb2adSek break; 183406eeb2adSek 183506eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 183606eeb2adSek if (!bytes_read) 183706eeb2adSek break; 183806eeb2adSek 183906eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 184006eeb2adSek &leftover, &records, &numrecords)) != 0) 184106eeb2adSek break; 184206eeb2adSek off -= leftover; 184306eeb2adSek 184406eeb2adSek /* CONSTCOND */ 184506eeb2adSek } while (1); 184606eeb2adSek 184706eeb2adSek if (!err) { 184806eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 184906eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 185006eeb2adSek records, numrecords) == 0); 185106eeb2adSek } 185206eeb2adSek for (i = 0; i < numrecords; i++) 185306eeb2adSek nvlist_free(records[i]); 185406eeb2adSek free(records); 185506eeb2adSek 185606eeb2adSek return (err); 185706eeb2adSek } 185855434c77Sek 185955434c77Sek void 186055434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 186155434c77Sek char *pathname, size_t len) 186255434c77Sek { 186355434c77Sek zfs_cmd_t zc = { 0 }; 186455434c77Sek boolean_t mounted = B_FALSE; 186555434c77Sek char *mntpnt = NULL; 186655434c77Sek char dsname[MAXNAMELEN]; 186755434c77Sek 186855434c77Sek if (dsobj == 0) { 186955434c77Sek /* special case for the MOS */ 187055434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 187155434c77Sek return; 187255434c77Sek } 187355434c77Sek 187455434c77Sek /* get the dataset's name */ 187555434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 187655434c77Sek zc.zc_obj = dsobj; 187755434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 187855434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 187955434c77Sek /* just write out a path of two object numbers */ 188055434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 188155434c77Sek dsobj, obj); 188255434c77Sek return; 188355434c77Sek } 188455434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 188555434c77Sek 188655434c77Sek /* find out if the dataset is mounted */ 188755434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 188855434c77Sek 188955434c77Sek /* get the corrupted object's path */ 189055434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 189155434c77Sek zc.zc_obj = obj; 189255434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 189355434c77Sek &zc) == 0) { 189455434c77Sek if (mounted) { 189555434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 189655434c77Sek zc.zc_value); 189755434c77Sek } else { 189855434c77Sek (void) snprintf(pathname, len, "%s:%s", 189955434c77Sek dsname, zc.zc_value); 190055434c77Sek } 190155434c77Sek } else { 190255434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 190355434c77Sek } 190455434c77Sek free(mntpnt); 190555434c77Sek } 1906*b1b8ab34Slling 1907*b1b8ab34Slling int 1908*b1b8ab34Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) 1909*b1b8ab34Slling { 1910*b1b8ab34Slling zfs_cmd_t zc = { 0 }; 1911*b1b8ab34Slling int ret = -1; 1912*b1b8ab34Slling char errbuf[1024]; 1913*b1b8ab34Slling nvlist_t *nvl = NULL; 1914*b1b8ab34Slling nvlist_t *realprops; 1915*b1b8ab34Slling 1916*b1b8ab34Slling (void) snprintf(errbuf, sizeof (errbuf), 1917*b1b8ab34Slling dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1918*b1b8ab34Slling zhp->zpool_name); 1919*b1b8ab34Slling 1920*b1b8ab34Slling if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS) { 1921*b1b8ab34Slling zfs_error_aux(zhp->zpool_hdl, 1922*b1b8ab34Slling dgettext(TEXT_DOMAIN, "pool must be " 1923*b1b8ab34Slling "upgraded to support pool properties")); 1924*b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, errbuf)); 1925*b1b8ab34Slling } 1926*b1b8ab34Slling 1927*b1b8ab34Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) 1928*b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, errbuf)); 1929*b1b8ab34Slling 1930*b1b8ab34Slling if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1931*b1b8ab34Slling nvlist_add_string(nvl, propname, propval) != 0) { 1932*b1b8ab34Slling return (no_memory(zhp->zpool_hdl)); 1933*b1b8ab34Slling } 1934*b1b8ab34Slling 1935*b1b8ab34Slling if ((realprops = zfs_validate_properties(zhp->zpool_hdl, ZFS_TYPE_POOL, 1936*b1b8ab34Slling zhp->zpool_name, nvl, 0, NULL, errbuf)) == NULL) { 1937*b1b8ab34Slling nvlist_free(nvl); 1938*b1b8ab34Slling return (-1); 1939*b1b8ab34Slling } 1940*b1b8ab34Slling 1941*b1b8ab34Slling nvlist_free(nvl); 1942*b1b8ab34Slling nvl = realprops; 1943*b1b8ab34Slling 1944*b1b8ab34Slling /* 1945*b1b8ab34Slling * Execute the corresponding ioctl() to set this property. 1946*b1b8ab34Slling */ 1947*b1b8ab34Slling (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1948*b1b8ab34Slling 1949*b1b8ab34Slling if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl, NULL) != 0) 1950*b1b8ab34Slling return (-1); 1951*b1b8ab34Slling 1952*b1b8ab34Slling ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SET_PROPS, &zc); 1953*b1b8ab34Slling zcmd_free_nvlists(&zc); 1954*b1b8ab34Slling 1955*b1b8ab34Slling if (ret) 1956*b1b8ab34Slling (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf); 1957*b1b8ab34Slling 1958*b1b8ab34Slling return (ret); 1959*b1b8ab34Slling } 1960*b1b8ab34Slling 1961*b1b8ab34Slling int 1962*b1b8ab34Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf, 1963*b1b8ab34Slling size_t proplen, zfs_source_t *srctype) 1964*b1b8ab34Slling { 1965*b1b8ab34Slling uint64_t value; 1966*b1b8ab34Slling char msg[1024], *strvalue; 1967*b1b8ab34Slling nvlist_t *nvp; 1968*b1b8ab34Slling zfs_source_t src = ZFS_SRC_NONE; 1969*b1b8ab34Slling 1970*b1b8ab34Slling (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 1971*b1b8ab34Slling "cannot get property '%s'"), zpool_prop_to_name(prop)); 1972*b1b8ab34Slling 1973*b1b8ab34Slling if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS) { 1974*b1b8ab34Slling zfs_error_aux(zhp->zpool_hdl, 1975*b1b8ab34Slling dgettext(TEXT_DOMAIN, "pool must be " 1976*b1b8ab34Slling "upgraded to support pool properties")); 1977*b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, msg)); 1978*b1b8ab34Slling } 1979*b1b8ab34Slling 1980*b1b8ab34Slling if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) 1981*b1b8ab34Slling return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, msg)); 1982*b1b8ab34Slling 1983*b1b8ab34Slling /* 1984*b1b8ab34Slling * the "name" property is special cased 1985*b1b8ab34Slling */ 1986*b1b8ab34Slling if (!zfs_prop_valid_for_type(prop, ZFS_TYPE_POOL) && 1987*b1b8ab34Slling prop != ZFS_PROP_NAME) 1988*b1b8ab34Slling return (-1); 1989*b1b8ab34Slling 1990*b1b8ab34Slling switch (prop) { 1991*b1b8ab34Slling case ZFS_PROP_NAME: 1992*b1b8ab34Slling (void) strlcpy(propbuf, zhp->zpool_name, proplen); 1993*b1b8ab34Slling break; 1994*b1b8ab34Slling 1995*b1b8ab34Slling case ZFS_PROP_BOOTFS: 1996*b1b8ab34Slling if (nvlist_lookup_nvlist(zhp->zpool_props, 1997*b1b8ab34Slling zpool_prop_to_name(prop), &nvp) != 0) { 1998*b1b8ab34Slling strvalue = (char *)zfs_prop_default_string(prop); 1999*b1b8ab34Slling if (strvalue == NULL) 2000*b1b8ab34Slling strvalue = "-"; 2001*b1b8ab34Slling src = ZFS_SRC_DEFAULT; 2002*b1b8ab34Slling } else { 2003*b1b8ab34Slling VERIFY(nvlist_lookup_uint64(nvp, 2004*b1b8ab34Slling ZFS_PROP_SOURCE, &value) == 0); 2005*b1b8ab34Slling src = value; 2006*b1b8ab34Slling VERIFY(nvlist_lookup_string(nvp, ZFS_PROP_VALUE, 2007*b1b8ab34Slling &strvalue) == 0); 2008*b1b8ab34Slling if (strlen(strvalue) >= proplen) 2009*b1b8ab34Slling return (-1); 2010*b1b8ab34Slling } 2011*b1b8ab34Slling (void) strcpy(propbuf, strvalue); 2012*b1b8ab34Slling break; 2013*b1b8ab34Slling 2014*b1b8ab34Slling default: 2015*b1b8ab34Slling return (-1); 2016*b1b8ab34Slling } 2017*b1b8ab34Slling if (srctype) 2018*b1b8ab34Slling *srctype = src; 2019*b1b8ab34Slling return (0); 2020*b1b8ab34Slling } 2021*b1b8ab34Slling 2022*b1b8ab34Slling int 2023*b1b8ab34Slling zpool_get_proplist(libzfs_handle_t *hdl, char *fields, zpool_proplist_t **listp) 2024*b1b8ab34Slling { 2025*b1b8ab34Slling return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_POOL)); 2026*b1b8ab34Slling } 2027*b1b8ab34Slling 2028*b1b8ab34Slling 2029*b1b8ab34Slling int 2030*b1b8ab34Slling zpool_expand_proplist(zpool_handle_t *zhp, zpool_proplist_t **plp) 2031*b1b8ab34Slling { 2032*b1b8ab34Slling libzfs_handle_t *hdl = zhp->zpool_hdl; 2033*b1b8ab34Slling zpool_proplist_t *entry; 2034*b1b8ab34Slling char buf[ZFS_MAXPROPLEN]; 2035*b1b8ab34Slling 2036*b1b8ab34Slling if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_POOL) != 0) 2037*b1b8ab34Slling return (-1); 2038*b1b8ab34Slling 2039*b1b8ab34Slling for (entry = *plp; entry != NULL; entry = entry->pl_next) { 2040*b1b8ab34Slling 2041*b1b8ab34Slling if (entry->pl_fixed) 2042*b1b8ab34Slling continue; 2043*b1b8ab34Slling 2044*b1b8ab34Slling if (entry->pl_prop != ZFS_PROP_INVAL && 2045*b1b8ab34Slling zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), 2046*b1b8ab34Slling NULL) == 0) { 2047*b1b8ab34Slling if (strlen(buf) > entry->pl_width) 2048*b1b8ab34Slling entry->pl_width = strlen(buf); 2049*b1b8ab34Slling } 2050*b1b8ab34Slling } 2051*b1b8ab34Slling 2052*b1b8ab34Slling return (0); 2053*b1b8ab34Slling } 2054