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" 46fa9e4066Sahrens #include "libzfs_impl.h" 47fa9e4066Sahrens 48fa9e4066Sahrens /* 49fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 50fa9e4066Sahrens * 'buf'. 51fa9e4066Sahrens */ 5299653d4eSeschrock static boolean_t 5399653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 54fa9e4066Sahrens { 55fa9e4066Sahrens namecheck_err_t why; 56fa9e4066Sahrens char what; 57b468a217Seschrock int ret; 58b468a217Seschrock 59b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 60b468a217Seschrock 61b468a217Seschrock /* 62b468a217Seschrock * The rules for reserved pool names were extended at a later point. 63b468a217Seschrock * But we need to support users with existing pools that may now be 64b468a217Seschrock * invalid. So we only check for this expanded set of names during a 65b468a217Seschrock * create (or import), and only in userland. 66b468a217Seschrock */ 67b468a217Seschrock if (ret == 0 && !isopen && 68b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 69b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 70b468a217Seschrock strncmp(pool, "spare", 5) == 0)) { 7199653d4eSeschrock zfs_error_aux(hdl, 7299653d4eSeschrock dgettext(TEXT_DOMAIN, "name is reserved")); 7399653d4eSeschrock return (B_FALSE); 74b468a217Seschrock } 75b468a217Seschrock 76fa9e4066Sahrens 77b468a217Seschrock if (ret != 0) { 7899653d4eSeschrock if (hdl != NULL) { 79fa9e4066Sahrens switch (why) { 80b81d61a6Slling case NAME_ERR_TOOLONG: 8199653d4eSeschrock zfs_error_aux(hdl, 82b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 83b81d61a6Slling break; 84b81d61a6Slling 85fa9e4066Sahrens case NAME_ERR_INVALCHAR: 8699653d4eSeschrock zfs_error_aux(hdl, 87fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 88fa9e4066Sahrens "'%c' in pool name"), what); 89fa9e4066Sahrens break; 90fa9e4066Sahrens 91fa9e4066Sahrens case NAME_ERR_NOLETTER: 9299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9399653d4eSeschrock "name must begin with a letter")); 94fa9e4066Sahrens break; 95fa9e4066Sahrens 96fa9e4066Sahrens case NAME_ERR_RESERVED: 9799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9899653d4eSeschrock "name is reserved")); 99fa9e4066Sahrens break; 100fa9e4066Sahrens 101fa9e4066Sahrens case NAME_ERR_DISKLIKE: 10299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10399653d4eSeschrock "pool name is reserved")); 104fa9e4066Sahrens break; 1055ad82045Snd 1065ad82045Snd case NAME_ERR_LEADING_SLASH: 1075ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1085ad82045Snd "leading slash in name")); 1095ad82045Snd break; 1105ad82045Snd 1115ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 1125ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1135ad82045Snd "empty component in name")); 1145ad82045Snd break; 1155ad82045Snd 1165ad82045Snd case NAME_ERR_TRAILING_SLASH: 1175ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1185ad82045Snd "trailing slash in name")); 1195ad82045Snd break; 1205ad82045Snd 1215ad82045Snd case NAME_ERR_MULTIPLE_AT: 1225ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1235ad82045Snd "multiple '@' delimiters in name")); 1245ad82045Snd break; 1255ad82045Snd 126fa9e4066Sahrens } 127fa9e4066Sahrens } 12899653d4eSeschrock return (B_FALSE); 129fa9e4066Sahrens } 130fa9e4066Sahrens 13199653d4eSeschrock return (B_TRUE); 132fa9e4066Sahrens } 133fa9e4066Sahrens 134fa9e4066Sahrens /* 135fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 136fa9e4066Sahrens * state. 137fa9e4066Sahrens */ 138fa9e4066Sahrens zpool_handle_t * 13999653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 140fa9e4066Sahrens { 141fa9e4066Sahrens zpool_handle_t *zhp; 14294de1d4cSeschrock boolean_t missing; 143fa9e4066Sahrens 144fa9e4066Sahrens /* 145fa9e4066Sahrens * Make sure the pool name is valid. 146fa9e4066Sahrens */ 14799653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 148ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME, 14999653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 15099653d4eSeschrock pool); 151fa9e4066Sahrens return (NULL); 152fa9e4066Sahrens } 153fa9e4066Sahrens 15499653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 15599653d4eSeschrock return (NULL); 156fa9e4066Sahrens 15799653d4eSeschrock zhp->zpool_hdl = hdl; 158fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 159fa9e4066Sahrens 16094de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 16194de1d4cSeschrock zpool_close(zhp); 16294de1d4cSeschrock return (NULL); 16394de1d4cSeschrock } 16494de1d4cSeschrock 16594de1d4cSeschrock if (missing) { 16694de1d4cSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 16794de1d4cSeschrock "no such pool")); 168ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_NOENT, 16994de1d4cSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 17094de1d4cSeschrock pool); 17194de1d4cSeschrock zpool_close(zhp); 17294de1d4cSeschrock return (NULL); 173fa9e4066Sahrens } 174fa9e4066Sahrens 175fa9e4066Sahrens return (zhp); 176fa9e4066Sahrens } 177fa9e4066Sahrens 178fa9e4066Sahrens /* 179fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 180fa9e4066Sahrens * the configuration cache may be out of date). 181fa9e4066Sahrens */ 18294de1d4cSeschrock int 18394de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 184fa9e4066Sahrens { 185fa9e4066Sahrens zpool_handle_t *zhp; 18694de1d4cSeschrock boolean_t missing; 187fa9e4066Sahrens 18894de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 18994de1d4cSeschrock return (-1); 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 (-1); 197fa9e4066Sahrens } 198fa9e4066Sahrens 19994de1d4cSeschrock if (missing) { 20094de1d4cSeschrock zpool_close(zhp); 20194de1d4cSeschrock *ret = NULL; 20294de1d4cSeschrock return (0); 20394de1d4cSeschrock } 20494de1d4cSeschrock 20594de1d4cSeschrock *ret = zhp; 20694de1d4cSeschrock return (0); 207fa9e4066Sahrens } 208fa9e4066Sahrens 209fa9e4066Sahrens /* 210fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 211fa9e4066Sahrens * state. 212fa9e4066Sahrens */ 213fa9e4066Sahrens zpool_handle_t * 21499653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 215fa9e4066Sahrens { 216fa9e4066Sahrens zpool_handle_t *zhp; 217fa9e4066Sahrens 21899653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 219fa9e4066Sahrens return (NULL); 220fa9e4066Sahrens 221fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 222ece3d9b3Slling (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL, 22399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 224fa9e4066Sahrens zpool_close(zhp); 225fa9e4066Sahrens return (NULL); 226fa9e4066Sahrens } 227fa9e4066Sahrens 228fa9e4066Sahrens return (zhp); 229fa9e4066Sahrens } 230fa9e4066Sahrens 231fa9e4066Sahrens /* 232fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 233fa9e4066Sahrens */ 234fa9e4066Sahrens void 235fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 236fa9e4066Sahrens { 237fa9e4066Sahrens if (zhp->zpool_config) 238fa9e4066Sahrens nvlist_free(zhp->zpool_config); 239088e9d47Seschrock if (zhp->zpool_old_config) 240088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 241fa9e4066Sahrens free(zhp); 242fa9e4066Sahrens } 243fa9e4066Sahrens 244fa9e4066Sahrens /* 245fa9e4066Sahrens * Return the name of the pool. 246fa9e4066Sahrens */ 247fa9e4066Sahrens const char * 248fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 249fa9e4066Sahrens { 250fa9e4066Sahrens return (zhp->zpool_name); 251fa9e4066Sahrens } 252fa9e4066Sahrens 253fa9e4066Sahrens /* 254fa9e4066Sahrens * Return the GUID of the pool. 255fa9e4066Sahrens */ 256fa9e4066Sahrens uint64_t 257fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp) 258fa9e4066Sahrens { 259fa9e4066Sahrens uint64_t guid; 260fa9e4066Sahrens 261fa9e4066Sahrens verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID, 262fa9e4066Sahrens &guid) == 0); 263fa9e4066Sahrens return (guid); 264fa9e4066Sahrens } 265fa9e4066Sahrens 26699653d4eSeschrock /* 26799653d4eSeschrock * Return the version of the pool. 26899653d4eSeschrock */ 26999653d4eSeschrock uint64_t 27099653d4eSeschrock zpool_get_version(zpool_handle_t *zhp) 27199653d4eSeschrock { 27299653d4eSeschrock uint64_t version; 27399653d4eSeschrock 27499653d4eSeschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION, 27599653d4eSeschrock &version) == 0); 27699653d4eSeschrock 27799653d4eSeschrock return (version); 27899653d4eSeschrock } 27999653d4eSeschrock 280fa9e4066Sahrens /* 281fa9e4066Sahrens * Return the amount of space currently consumed by the pool. 282fa9e4066Sahrens */ 283fa9e4066Sahrens uint64_t 284fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp) 285fa9e4066Sahrens { 286fa9e4066Sahrens nvlist_t *nvroot; 287fa9e4066Sahrens vdev_stat_t *vs; 288fa9e4066Sahrens uint_t vsc; 289fa9e4066Sahrens 290fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 291fa9e4066Sahrens &nvroot) == 0); 292fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 293fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 294fa9e4066Sahrens 295fa9e4066Sahrens return (vs->vs_alloc); 296fa9e4066Sahrens } 297fa9e4066Sahrens 298fa9e4066Sahrens /* 299fa9e4066Sahrens * Return the total space in the pool. 300fa9e4066Sahrens */ 301fa9e4066Sahrens uint64_t 302fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp) 303fa9e4066Sahrens { 304fa9e4066Sahrens nvlist_t *nvroot; 305fa9e4066Sahrens vdev_stat_t *vs; 306fa9e4066Sahrens uint_t vsc; 307fa9e4066Sahrens 308fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 309fa9e4066Sahrens &nvroot) == 0); 310fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 311fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 312fa9e4066Sahrens 313fa9e4066Sahrens return (vs->vs_space); 314fa9e4066Sahrens } 315fa9e4066Sahrens 316fa9e4066Sahrens /* 317fa9e4066Sahrens * Return the alternate root for this pool, if any. 318fa9e4066Sahrens */ 319fa9e4066Sahrens int 320fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen) 321fa9e4066Sahrens { 322fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 323fa9e4066Sahrens 324fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 32599653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 || 326e9dbad6fSeschrock zc.zc_value[0] == '\0') 327fa9e4066Sahrens return (-1); 328fa9e4066Sahrens 329e9dbad6fSeschrock (void) strlcpy(buf, zc.zc_value, buflen); 330fa9e4066Sahrens 331fa9e4066Sahrens return (0); 332fa9e4066Sahrens } 333fa9e4066Sahrens 334fa9e4066Sahrens /* 335fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 336fa9e4066Sahrens */ 337fa9e4066Sahrens int 338fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 339fa9e4066Sahrens { 340fa9e4066Sahrens return (zhp->zpool_state); 341fa9e4066Sahrens } 342fa9e4066Sahrens 343fa9e4066Sahrens /* 344fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 345fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 346fa9e4066Sahrens * don't have to worry about error semantics. 347fa9e4066Sahrens */ 348fa9e4066Sahrens int 34999653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 35099653d4eSeschrock const char *altroot) 351fa9e4066Sahrens { 352fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 35399653d4eSeschrock char msg[1024]; 354fa9e4066Sahrens 35599653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 35699653d4eSeschrock "cannot create '%s'"), pool); 357fa9e4066Sahrens 35899653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 35999653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 360fa9e4066Sahrens 36199653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 362ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 36399653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot)); 364fa9e4066Sahrens 365e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 36699653d4eSeschrock return (-1); 36799653d4eSeschrock 368fa9e4066Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 369fa9e4066Sahrens 370fa9e4066Sahrens if (altroot != NULL) 371e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 372fa9e4066Sahrens 37399653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) { 374e9dbad6fSeschrock zcmd_free_nvlists(&zc); 375fa9e4066Sahrens 37699653d4eSeschrock switch (errno) { 377fa9e4066Sahrens case EBUSY: 378fa9e4066Sahrens /* 379fa9e4066Sahrens * This can happen if the user has specified the same 380fa9e4066Sahrens * device multiple times. We can't reliably detect this 381fa9e4066Sahrens * until we try to add it and see we already have a 382fa9e4066Sahrens * label. 383fa9e4066Sahrens */ 38499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 38599653d4eSeschrock "one or more vdevs refer to the same device")); 38699653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 387fa9e4066Sahrens 388fa9e4066Sahrens case EOVERFLOW: 389fa9e4066Sahrens /* 39099653d4eSeschrock * This occurs when one of the devices is below 391fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 392fa9e4066Sahrens * device was the problem device since there's no 393fa9e4066Sahrens * reliable way to determine device size from userland. 394fa9e4066Sahrens */ 395fa9e4066Sahrens { 396fa9e4066Sahrens char buf[64]; 397fa9e4066Sahrens 398fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 399fa9e4066Sahrens 40099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 40199653d4eSeschrock "one or more devices is less than the " 40299653d4eSeschrock "minimum size (%s)"), buf); 403fa9e4066Sahrens } 40499653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 405fa9e4066Sahrens 406fa9e4066Sahrens case ENOSPC: 40799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 40899653d4eSeschrock "one or more devices is out of space")); 40999653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 410fa9e4066Sahrens 411fa9e4066Sahrens default: 41299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 413fa9e4066Sahrens } 414fa9e4066Sahrens } 415fa9e4066Sahrens 416e9dbad6fSeschrock zcmd_free_nvlists(&zc); 417fa9e4066Sahrens 418fa9e4066Sahrens /* 419fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 420e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 421fa9e4066Sahrens */ 422fa9e4066Sahrens if (altroot != NULL) { 423fa9e4066Sahrens zfs_handle_t *zhp; 424fa9e4066Sahrens 42599653d4eSeschrock verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL); 426e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 427e9dbad6fSeschrock "/") == 0); 428fa9e4066Sahrens 429fa9e4066Sahrens zfs_close(zhp); 430fa9e4066Sahrens } 431fa9e4066Sahrens 432fa9e4066Sahrens return (0); 433fa9e4066Sahrens } 434fa9e4066Sahrens 435fa9e4066Sahrens /* 436fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 437fa9e4066Sahrens * datasets left in the pool. 438fa9e4066Sahrens */ 439fa9e4066Sahrens int 440fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 441fa9e4066Sahrens { 442fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 443fa9e4066Sahrens zfs_handle_t *zfp = NULL; 44499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 44599653d4eSeschrock char msg[1024]; 446fa9e4066Sahrens 447fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 44899653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 44999653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 450fa9e4066Sahrens return (-1); 451fa9e4066Sahrens 4525ad82045Snd if (zpool_remove_zvol_links(zhp) != 0) 453fa9e4066Sahrens return (-1); 454fa9e4066Sahrens 455fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 456fa9e4066Sahrens 45799653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 45899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 45999653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 460fa9e4066Sahrens 46199653d4eSeschrock if (errno == EROFS) { 46299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 46399653d4eSeschrock "one or more devices is read only")); 46499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 46599653d4eSeschrock } else { 46699653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 467fa9e4066Sahrens } 468fa9e4066Sahrens 469fa9e4066Sahrens if (zfp) 470fa9e4066Sahrens zfs_close(zfp); 471fa9e4066Sahrens return (-1); 472fa9e4066Sahrens } 473fa9e4066Sahrens 474fa9e4066Sahrens if (zfp) { 475fa9e4066Sahrens remove_mountpoint(zfp); 476fa9e4066Sahrens zfs_close(zfp); 477fa9e4066Sahrens } 478fa9e4066Sahrens 479fa9e4066Sahrens return (0); 480fa9e4066Sahrens } 481fa9e4066Sahrens 482fa9e4066Sahrens /* 483fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 484fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 485fa9e4066Sahrens */ 486fa9e4066Sahrens int 487fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 488fa9e4066Sahrens { 489e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 49099653d4eSeschrock int ret; 49199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 49299653d4eSeschrock char msg[1024]; 49399653d4eSeschrock nvlist_t **spares; 49499653d4eSeschrock uint_t nspares; 49599653d4eSeschrock 49699653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 49799653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 49899653d4eSeschrock 49999653d4eSeschrock if (zpool_get_version(zhp) < ZFS_VERSION_SPARES && 50099653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 50199653d4eSeschrock &spares, &nspares) == 0) { 50299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 50399653d4eSeschrock "upgraded to add hot spares")); 50499653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 50599653d4eSeschrock } 506fa9e4066Sahrens 507e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 50899653d4eSeschrock return (-1); 509fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 510fa9e4066Sahrens 51199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) { 512fa9e4066Sahrens switch (errno) { 513fa9e4066Sahrens case EBUSY: 514fa9e4066Sahrens /* 515fa9e4066Sahrens * This can happen if the user has specified the same 516fa9e4066Sahrens * device multiple times. We can't reliably detect this 517fa9e4066Sahrens * until we try to add it and see we already have a 518fa9e4066Sahrens * label. 519fa9e4066Sahrens */ 52099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 52199653d4eSeschrock "one or more vdevs refer to the same device")); 52299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 523fa9e4066Sahrens break; 524fa9e4066Sahrens 525fa9e4066Sahrens case EOVERFLOW: 526fa9e4066Sahrens /* 527fa9e4066Sahrens * This occurrs when one of the devices is below 528fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 529fa9e4066Sahrens * device was the problem device since there's no 530fa9e4066Sahrens * reliable way to determine device size from userland. 531fa9e4066Sahrens */ 532fa9e4066Sahrens { 533fa9e4066Sahrens char buf[64]; 534fa9e4066Sahrens 535fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 536fa9e4066Sahrens 53799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 53899653d4eSeschrock "device is less than the minimum " 53999653d4eSeschrock "size (%s)"), buf); 540fa9e4066Sahrens } 54199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 54299653d4eSeschrock break; 54399653d4eSeschrock 54499653d4eSeschrock case ENOTSUP: 54599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 54699653d4eSeschrock "pool must be upgraded to add raidz2 vdevs")); 54799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 548fa9e4066Sahrens break; 549fa9e4066Sahrens 550fa9e4066Sahrens default: 55199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 552fa9e4066Sahrens } 553fa9e4066Sahrens 55499653d4eSeschrock ret = -1; 55599653d4eSeschrock } else { 55699653d4eSeschrock ret = 0; 557fa9e4066Sahrens } 558fa9e4066Sahrens 559e9dbad6fSeschrock zcmd_free_nvlists(&zc); 560fa9e4066Sahrens 56199653d4eSeschrock return (ret); 562fa9e4066Sahrens } 563fa9e4066Sahrens 564fa9e4066Sahrens /* 565fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 566fa9e4066Sahrens * mounted datasets in the pool. 567fa9e4066Sahrens */ 568fa9e4066Sahrens int 569fa9e4066Sahrens zpool_export(zpool_handle_t *zhp) 570fa9e4066Sahrens { 571fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 572fa9e4066Sahrens 573fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 574fa9e4066Sahrens return (-1); 575fa9e4066Sahrens 576fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 577fa9e4066Sahrens 57899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0) 579ece3d9b3Slling return (zpool_standard_error_fmt(zhp->zpool_hdl, errno, 58099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot export '%s'"), 58199653d4eSeschrock zhp->zpool_name)); 582fa9e4066Sahrens 583fa9e4066Sahrens return (0); 584fa9e4066Sahrens } 585fa9e4066Sahrens 586fa9e4066Sahrens /* 587fa9e4066Sahrens * Import the given pool using the known configuration. The configuration 588fa9e4066Sahrens * should have come from zpool_find_import(). The 'newname' and 'altroot' 589fa9e4066Sahrens * parameters control whether the pool is imported with a different name or with 590fa9e4066Sahrens * an alternate root, respectively. 591fa9e4066Sahrens */ 592fa9e4066Sahrens int 59399653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 59499653d4eSeschrock const char *altroot) 595fa9e4066Sahrens { 596e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 597fa9e4066Sahrens char *thename; 598fa9e4066Sahrens char *origname; 599fa9e4066Sahrens int ret; 600fa9e4066Sahrens 601fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 602fa9e4066Sahrens &origname) == 0); 603fa9e4066Sahrens 604fa9e4066Sahrens if (newname != NULL) { 60599653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 606ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_INVALIDNAME, 60799653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 60899653d4eSeschrock newname)); 609fa9e4066Sahrens thename = (char *)newname; 610fa9e4066Sahrens } else { 611fa9e4066Sahrens thename = origname; 612fa9e4066Sahrens } 613fa9e4066Sahrens 61499653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 615ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_BADPATH, 61699653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), 61799653d4eSeschrock altroot)); 618fa9e4066Sahrens 619fa9e4066Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 620fa9e4066Sahrens 621fa9e4066Sahrens if (altroot != NULL) 622e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 623fa9e4066Sahrens else 624e9dbad6fSeschrock zc.zc_value[0] = '\0'; 625fa9e4066Sahrens 626fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 627ea8dc4b6Seschrock &zc.zc_guid) == 0); 628fa9e4066Sahrens 629e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0) 63099653d4eSeschrock return (-1); 631fa9e4066Sahrens 632fa9e4066Sahrens ret = 0; 63399653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 634fa9e4066Sahrens char desc[1024]; 635fa9e4066Sahrens if (newname == NULL) 636fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 637fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 638fa9e4066Sahrens thename); 639fa9e4066Sahrens else 640fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 641fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 642fa9e4066Sahrens origname, thename); 643fa9e4066Sahrens 644fa9e4066Sahrens switch (errno) { 645ea8dc4b6Seschrock case ENOTSUP: 646ea8dc4b6Seschrock /* 647ea8dc4b6Seschrock * Unsupported version. 648ea8dc4b6Seschrock */ 64999653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 650ea8dc4b6Seschrock break; 651ea8dc4b6Seschrock 652b5989ec7Seschrock case EINVAL: 653b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 654b5989ec7Seschrock break; 655b5989ec7Seschrock 656fa9e4066Sahrens default: 65799653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 658fa9e4066Sahrens } 659fa9e4066Sahrens 660fa9e4066Sahrens ret = -1; 661fa9e4066Sahrens } else { 662fa9e4066Sahrens zpool_handle_t *zhp; 663fa9e4066Sahrens /* 664fa9e4066Sahrens * This should never fail, but play it safe anyway. 665fa9e4066Sahrens */ 66694de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 66794de1d4cSeschrock ret = -1; 66894de1d4cSeschrock } else if (zhp != NULL) { 669fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 670fa9e4066Sahrens zpool_close(zhp); 671fa9e4066Sahrens } 672fa9e4066Sahrens } 673fa9e4066Sahrens 674e9dbad6fSeschrock zcmd_free_nvlists(&zc); 675fa9e4066Sahrens return (ret); 676fa9e4066Sahrens } 677fa9e4066Sahrens 678fa9e4066Sahrens /* 679fa9e4066Sahrens * Scrub the pool. 680fa9e4066Sahrens */ 681fa9e4066Sahrens int 682fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 683fa9e4066Sahrens { 684fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 685fa9e4066Sahrens char msg[1024]; 68699653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 687fa9e4066Sahrens 688fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 689fa9e4066Sahrens zc.zc_cookie = type; 690fa9e4066Sahrens 69199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0) 692fa9e4066Sahrens return (0); 693fa9e4066Sahrens 694fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 695fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 696fa9e4066Sahrens 69799653d4eSeschrock if (errno == EBUSY) 69899653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 69999653d4eSeschrock else 70099653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 701fa9e4066Sahrens } 702fa9e4066Sahrens 703a43d325bSek /* 704a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 705a43d325bSek * spare; but FALSE if its an INUSE spare. 706a43d325bSek */ 70799653d4eSeschrock static nvlist_t * 70899653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, 709a43d325bSek boolean_t *avail_spare) 710ea8dc4b6Seschrock { 711ea8dc4b6Seschrock uint_t c, children; 712ea8dc4b6Seschrock nvlist_t **child; 71399653d4eSeschrock uint64_t theguid, present; 714ea8dc4b6Seschrock char *path; 715ea8dc4b6Seschrock uint64_t wholedisk = 0; 71699653d4eSeschrock nvlist_t *ret; 717ea8dc4b6Seschrock 71899653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0); 719ea8dc4b6Seschrock 720ea8dc4b6Seschrock if (search == NULL && 721ea8dc4b6Seschrock nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) { 722ea8dc4b6Seschrock /* 723ea8dc4b6Seschrock * If the device has never been present since import, the only 724ea8dc4b6Seschrock * reliable way to match the vdev is by GUID. 725ea8dc4b6Seschrock */ 72699653d4eSeschrock if (theguid == guid) 72799653d4eSeschrock return (nv); 728ea8dc4b6Seschrock } else if (search != NULL && 729ea8dc4b6Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 730ea8dc4b6Seschrock (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 731ea8dc4b6Seschrock &wholedisk); 732ea8dc4b6Seschrock if (wholedisk) { 733ea8dc4b6Seschrock /* 734ea8dc4b6Seschrock * For whole disks, the internal path has 's0', but the 735ea8dc4b6Seschrock * path passed in by the user doesn't. 736ea8dc4b6Seschrock */ 737ea8dc4b6Seschrock if (strlen(search) == strlen(path) - 2 && 738ea8dc4b6Seschrock strncmp(search, path, strlen(search)) == 0) 73999653d4eSeschrock return (nv); 740ea8dc4b6Seschrock } else if (strcmp(search, path) == 0) { 74199653d4eSeschrock return (nv); 742ea8dc4b6Seschrock } 743ea8dc4b6Seschrock } 744ea8dc4b6Seschrock 745ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 746ea8dc4b6Seschrock &child, &children) != 0) 74799653d4eSeschrock return (NULL); 748ea8dc4b6Seschrock 749ea8dc4b6Seschrock for (c = 0; c < children; c++) 75099653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 751a43d325bSek avail_spare)) != NULL) 752ea8dc4b6Seschrock return (ret); 753ea8dc4b6Seschrock 75499653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 75599653d4eSeschrock &child, &children) == 0) { 75699653d4eSeschrock for (c = 0; c < children; c++) { 75799653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 758a43d325bSek avail_spare)) != NULL) { 759a43d325bSek *avail_spare = B_TRUE; 76099653d4eSeschrock return (ret); 76199653d4eSeschrock } 76299653d4eSeschrock } 76399653d4eSeschrock } 76499653d4eSeschrock 76599653d4eSeschrock return (NULL); 766ea8dc4b6Seschrock } 767ea8dc4b6Seschrock 76899653d4eSeschrock nvlist_t * 769a43d325bSek zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) 770ea8dc4b6Seschrock { 771ea8dc4b6Seschrock char buf[MAXPATHLEN]; 772ea8dc4b6Seschrock const char *search; 773ea8dc4b6Seschrock char *end; 774ea8dc4b6Seschrock nvlist_t *nvroot; 775ea8dc4b6Seschrock uint64_t guid; 776ea8dc4b6Seschrock 7770917b783Seschrock guid = strtoull(path, &end, 10); 778ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 779ea8dc4b6Seschrock search = NULL; 780ea8dc4b6Seschrock } else if (path[0] != '/') { 781ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 782ea8dc4b6Seschrock search = buf; 783ea8dc4b6Seschrock } else { 784ea8dc4b6Seschrock search = path; 785ea8dc4b6Seschrock } 786ea8dc4b6Seschrock 787ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 788ea8dc4b6Seschrock &nvroot) == 0); 789ea8dc4b6Seschrock 790a43d325bSek *avail_spare = B_FALSE; 791a43d325bSek return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare)); 792a43d325bSek } 793a43d325bSek 794a43d325bSek /* 795a43d325bSek * Returns TRUE if the given guid corresponds to a spare (INUSE or not). 796a43d325bSek */ 797a43d325bSek static boolean_t 798a43d325bSek is_spare(zpool_handle_t *zhp, uint64_t guid) 799a43d325bSek { 800a43d325bSek uint64_t spare_guid; 801a43d325bSek nvlist_t *nvroot; 802a43d325bSek nvlist_t **spares; 803a43d325bSek uint_t nspares; 804a43d325bSek int i; 805a43d325bSek 806a43d325bSek verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 807a43d325bSek &nvroot) == 0); 808a43d325bSek if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 809a43d325bSek &spares, &nspares) == 0) { 810a43d325bSek for (i = 0; i < nspares; i++) { 811a43d325bSek verify(nvlist_lookup_uint64(spares[i], 812a43d325bSek ZPOOL_CONFIG_GUID, &spare_guid) == 0); 813a43d325bSek if (guid == spare_guid) 814a43d325bSek return (B_TRUE); 815a43d325bSek } 816a43d325bSek } 817a43d325bSek 818a43d325bSek return (B_FALSE); 819ea8dc4b6Seschrock } 820ea8dc4b6Seschrock 821fa9e4066Sahrens /* 822fa9e4066Sahrens * Bring the specified vdev online 823fa9e4066Sahrens */ 824fa9e4066Sahrens int 825fa9e4066Sahrens zpool_vdev_online(zpool_handle_t *zhp, const char *path) 826fa9e4066Sahrens { 827fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 828fa9e4066Sahrens char msg[1024]; 82999653d4eSeschrock nvlist_t *tgt; 830a43d325bSek boolean_t avail_spare; 83199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 832fa9e4066Sahrens 833ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 834ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot online %s"), path); 835ea8dc4b6Seschrock 836fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 837a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 83899653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 839fa9e4066Sahrens 84099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 841fa9e4066Sahrens 842a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 843a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 844a43d325bSek 84599653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0) 84699653d4eSeschrock return (0); 847fa9e4066Sahrens 84899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 849fa9e4066Sahrens } 850fa9e4066Sahrens 851fa9e4066Sahrens /* 852fa9e4066Sahrens * Take the specified vdev offline 853fa9e4066Sahrens */ 854fa9e4066Sahrens int 855441d80aaSlling zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp) 856fa9e4066Sahrens { 857fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 858fa9e4066Sahrens char msg[1024]; 85999653d4eSeschrock nvlist_t *tgt; 860a43d325bSek boolean_t avail_spare; 86199653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 862fa9e4066Sahrens 863ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 864ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 865ea8dc4b6Seschrock 866fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 867a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 86899653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 86999653d4eSeschrock 87099653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 871fa9e4066Sahrens 872a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 873a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 874a43d325bSek 875441d80aaSlling zc.zc_cookie = istmp; 876441d80aaSlling 87799653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0) 878fa9e4066Sahrens return (0); 879fa9e4066Sahrens 880fa9e4066Sahrens switch (errno) { 88199653d4eSeschrock case EBUSY: 882fa9e4066Sahrens 883fa9e4066Sahrens /* 884fa9e4066Sahrens * There are no other replicas of this device. 885fa9e4066Sahrens */ 88699653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 887fa9e4066Sahrens 88899653d4eSeschrock default: 88999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 890fa9e4066Sahrens } 89199653d4eSeschrock } 89299653d4eSeschrock 89399653d4eSeschrock /* 89499653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 89599653d4eSeschrock * a hot spare. 89699653d4eSeschrock */ 89799653d4eSeschrock static boolean_t 89899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 89999653d4eSeschrock { 90099653d4eSeschrock nvlist_t **child; 90199653d4eSeschrock uint_t c, children; 90299653d4eSeschrock char *type; 90399653d4eSeschrock 90499653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 90599653d4eSeschrock &children) == 0) { 90699653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 90799653d4eSeschrock &type) == 0); 90899653d4eSeschrock 90999653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 91099653d4eSeschrock children == 2 && child[which] == tgt) 91199653d4eSeschrock return (B_TRUE); 91299653d4eSeschrock 91399653d4eSeschrock for (c = 0; c < children; c++) 91499653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 91599653d4eSeschrock return (B_TRUE); 91699653d4eSeschrock } 91799653d4eSeschrock 91899653d4eSeschrock return (B_FALSE); 919fa9e4066Sahrens } 920fa9e4066Sahrens 921fa9e4066Sahrens /* 922fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 923fa9e4066Sahrens * If 'replacing' is specified, tne new disk will replace the old one. 924fa9e4066Sahrens */ 925fa9e4066Sahrens int 926fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 927fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 928fa9e4066Sahrens { 929fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 930fa9e4066Sahrens char msg[1024]; 931fa9e4066Sahrens int ret; 93299653d4eSeschrock nvlist_t *tgt; 933a43d325bSek boolean_t avail_spare; 93499653d4eSeschrock uint64_t val; 93599653d4eSeschrock char *path; 93699653d4eSeschrock nvlist_t **child; 93799653d4eSeschrock uint_t children; 93899653d4eSeschrock nvlist_t *config_root; 93999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 940fa9e4066Sahrens 941ea8dc4b6Seschrock if (replacing) 942ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 943ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 944ea8dc4b6Seschrock else 945ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 946ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 947ea8dc4b6Seschrock 948fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 949a43d325bSek if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0) 95099653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 95199653d4eSeschrock 952a43d325bSek if (avail_spare) 95399653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 95499653d4eSeschrock 95599653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 956fa9e4066Sahrens zc.zc_cookie = replacing; 957fa9e4066Sahrens 95899653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 95999653d4eSeschrock &child, &children) != 0 || children != 1) { 96099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 96199653d4eSeschrock "new device must be a single disk")); 96299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 96399653d4eSeschrock } 96499653d4eSeschrock 96599653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 96699653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 96799653d4eSeschrock 96899653d4eSeschrock /* 96999653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 97099653d4eSeschrock * replace it with another hot spare. 97199653d4eSeschrock */ 97299653d4eSeschrock if (replacing && 97399653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 97499653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 975a43d325bSek (zpool_find_vdev(zhp, path, &avail_spare) == NULL || 976a43d325bSek !avail_spare) && is_replacing_spare(config_root, tgt, 1)) { 97799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 97899653d4eSeschrock "can only be replaced by another hot spare")); 97999653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 98099653d4eSeschrock } 98199653d4eSeschrock 98299653d4eSeschrock /* 98399653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 98499653d4eSeschrock * already spared device. 98599653d4eSeschrock */ 98699653d4eSeschrock if (replacing && 98799653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 988a43d325bSek zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare && 98999653d4eSeschrock is_replacing_spare(config_root, tgt, 0)) { 99099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 99199653d4eSeschrock "device has already been replaced with a spare")); 99299653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 99399653d4eSeschrock } 99499653d4eSeschrock 995e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 99699653d4eSeschrock return (-1); 997fa9e4066Sahrens 99899653d4eSeschrock ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc); 999fa9e4066Sahrens 1000e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1001fa9e4066Sahrens 1002fa9e4066Sahrens if (ret == 0) 1003fa9e4066Sahrens return (0); 1004fa9e4066Sahrens 1005fa9e4066Sahrens switch (errno) { 1006ea8dc4b6Seschrock case ENOTSUP: 1007fa9e4066Sahrens /* 1008fa9e4066Sahrens * Can't attach to or replace this type of vdev. 1009fa9e4066Sahrens */ 1010fa9e4066Sahrens if (replacing) 101199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 101299653d4eSeschrock "cannot replace a replacing device")); 1013fa9e4066Sahrens else 101499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 101599653d4eSeschrock "can only attach to mirrors and top-level " 101699653d4eSeschrock "disks")); 101799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 1018fa9e4066Sahrens break; 1019fa9e4066Sahrens 1020ea8dc4b6Seschrock case EINVAL: 1021fa9e4066Sahrens /* 1022fa9e4066Sahrens * The new device must be a single disk. 1023fa9e4066Sahrens */ 102499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 102599653d4eSeschrock "new device must be a single disk")); 102699653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 1027fa9e4066Sahrens break; 1028fa9e4066Sahrens 1029ea8dc4b6Seschrock case EBUSY: 103099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 103199653d4eSeschrock new_disk); 103299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1033fa9e4066Sahrens break; 1034fa9e4066Sahrens 1035ea8dc4b6Seschrock case EOVERFLOW: 1036fa9e4066Sahrens /* 1037fa9e4066Sahrens * The new device is too small. 1038fa9e4066Sahrens */ 103999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 104099653d4eSeschrock "device is too small")); 104199653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1042fa9e4066Sahrens break; 1043fa9e4066Sahrens 1044ea8dc4b6Seschrock case EDOM: 1045fa9e4066Sahrens /* 1046fa9e4066Sahrens * The new device has a different alignment requirement. 1047fa9e4066Sahrens */ 104899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 104999653d4eSeschrock "devices have different sector alignment")); 105099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1051fa9e4066Sahrens break; 1052fa9e4066Sahrens 1053ea8dc4b6Seschrock case ENAMETOOLONG: 1054fa9e4066Sahrens /* 1055fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 1056fa9e4066Sahrens */ 105799653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 1058fa9e4066Sahrens break; 1059fa9e4066Sahrens 1060ea8dc4b6Seschrock default: 106199653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1062fa9e4066Sahrens } 1063fa9e4066Sahrens 106499653d4eSeschrock return (-1); 1065fa9e4066Sahrens } 1066fa9e4066Sahrens 1067fa9e4066Sahrens /* 1068fa9e4066Sahrens * Detach the specified device. 1069fa9e4066Sahrens */ 1070fa9e4066Sahrens int 1071fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 1072fa9e4066Sahrens { 1073fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1074fa9e4066Sahrens char msg[1024]; 107599653d4eSeschrock nvlist_t *tgt; 1076a43d325bSek boolean_t avail_spare; 107799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1078fa9e4066Sahrens 1079ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1080ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 1081ea8dc4b6Seschrock 1082fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1083a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 108499653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1085fa9e4066Sahrens 1086a43d325bSek if (avail_spare) 108799653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 108899653d4eSeschrock 108999653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 109099653d4eSeschrock 109199653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0) 1092fa9e4066Sahrens return (0); 1093fa9e4066Sahrens 1094fa9e4066Sahrens switch (errno) { 1095fa9e4066Sahrens 1096ea8dc4b6Seschrock case ENOTSUP: 1097fa9e4066Sahrens /* 1098fa9e4066Sahrens * Can't detach from this type of vdev. 1099fa9e4066Sahrens */ 110099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 110199653d4eSeschrock "applicable to mirror and replacing vdevs")); 110299653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 1103fa9e4066Sahrens break; 1104fa9e4066Sahrens 1105ea8dc4b6Seschrock case EBUSY: 1106fa9e4066Sahrens /* 1107fa9e4066Sahrens * There are no other replicas of this device. 1108fa9e4066Sahrens */ 110999653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 1110fa9e4066Sahrens break; 1111fa9e4066Sahrens 1112ea8dc4b6Seschrock default: 111399653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1114ea8dc4b6Seschrock } 1115ea8dc4b6Seschrock 111699653d4eSeschrock return (-1); 111799653d4eSeschrock } 111899653d4eSeschrock 111999653d4eSeschrock /* 112099653d4eSeschrock * Remove the given device. Currently, this is supported only for hot spares. 112199653d4eSeschrock */ 112299653d4eSeschrock int 112399653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 112499653d4eSeschrock { 112599653d4eSeschrock zfs_cmd_t zc = { 0 }; 112699653d4eSeschrock char msg[1024]; 112799653d4eSeschrock nvlist_t *tgt; 1128a43d325bSek boolean_t avail_spare; 112999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 113099653d4eSeschrock 113199653d4eSeschrock (void) snprintf(msg, sizeof (msg), 113299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 113399653d4eSeschrock 113499653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1135a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 113699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 113799653d4eSeschrock 1138a43d325bSek if (!avail_spare) { 113999653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 114039c23413Seschrock "only inactive hot spares can be removed")); 114199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 114299653d4eSeschrock } 114399653d4eSeschrock 114499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 114599653d4eSeschrock 114699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 114799653d4eSeschrock return (0); 114899653d4eSeschrock 114999653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1150ea8dc4b6Seschrock } 1151ea8dc4b6Seschrock 1152ea8dc4b6Seschrock /* 1153ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 1154ea8dc4b6Seschrock */ 1155ea8dc4b6Seschrock int 1156ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 1157ea8dc4b6Seschrock { 1158ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1159ea8dc4b6Seschrock char msg[1024]; 116099653d4eSeschrock nvlist_t *tgt; 1161a43d325bSek boolean_t avail_spare; 116299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1163ea8dc4b6Seschrock 1164ea8dc4b6Seschrock if (path) 1165ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1166ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1167e9dbad6fSeschrock path); 1168ea8dc4b6Seschrock else 1169ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1170ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1171ea8dc4b6Seschrock zhp->zpool_name); 1172ea8dc4b6Seschrock 1173ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 117499653d4eSeschrock if (path) { 1175a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 117699653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1177ea8dc4b6Seschrock 1178a43d325bSek if (avail_spare) 117999653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1180ea8dc4b6Seschrock 118199653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 118299653d4eSeschrock &zc.zc_guid) == 0); 1183fa9e4066Sahrens } 1184fa9e4066Sahrens 118599653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 118699653d4eSeschrock return (0); 118799653d4eSeschrock 118899653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1189fa9e4066Sahrens } 1190fa9e4066Sahrens 1191f3861e1aSahl /* 1192f3861e1aSahl * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool> 1193f3861e1aSahl * hierarchy. 1194f3861e1aSahl */ 1195f3861e1aSahl int 1196f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *), 1197f3861e1aSahl void *data) 1198fa9e4066Sahrens { 1199f3861e1aSahl libzfs_handle_t *hdl = zhp->zpool_hdl; 1200f3861e1aSahl char (*paths)[MAXPATHLEN]; 1201f3861e1aSahl size_t size = 4; 1202f3861e1aSahl int curr, fd, base, ret = 0; 1203f3861e1aSahl DIR *dirp; 1204f3861e1aSahl struct dirent *dp; 1205f3861e1aSahl struct stat st; 1206f3861e1aSahl 1207f3861e1aSahl if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0) 1208f3861e1aSahl return (errno == ENOENT ? 0 : -1); 1209f3861e1aSahl 1210f3861e1aSahl if (fstatat(base, zhp->zpool_name, &st, 0) != 0) { 1211f3861e1aSahl int err = errno; 1212f3861e1aSahl (void) close(base); 1213f3861e1aSahl return (err == ENOENT ? 0 : -1); 1214f3861e1aSahl } 1215fa9e4066Sahrens 1216fa9e4066Sahrens /* 1217f3861e1aSahl * Oddly this wasn't a directory -- ignore that failure since we 1218f3861e1aSahl * know there are no links lower in the (non-existant) hierarchy. 1219fa9e4066Sahrens */ 1220f3861e1aSahl if (!S_ISDIR(st.st_mode)) { 1221f3861e1aSahl (void) close(base); 1222f3861e1aSahl return (0); 1223fa9e4066Sahrens } 1224fa9e4066Sahrens 1225f3861e1aSahl if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) { 1226f3861e1aSahl (void) close(base); 1227f3861e1aSahl return (-1); 1228f3861e1aSahl } 1229f3861e1aSahl 1230f3861e1aSahl (void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0])); 1231f3861e1aSahl curr = 0; 1232f3861e1aSahl 1233f3861e1aSahl while (curr >= 0) { 1234f3861e1aSahl if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0) 1235f3861e1aSahl goto err; 1236f3861e1aSahl 1237f3861e1aSahl if (S_ISDIR(st.st_mode)) { 1238f3861e1aSahl if ((fd = openat(base, paths[curr], O_RDONLY)) < 0) 1239f3861e1aSahl goto err; 1240f3861e1aSahl 1241f3861e1aSahl if ((dirp = fdopendir(fd)) == NULL) { 1242f3861e1aSahl (void) close(fd); 1243f3861e1aSahl goto err; 1244f3861e1aSahl } 1245f3861e1aSahl 1246f3861e1aSahl while ((dp = readdir(dirp)) != NULL) { 1247f3861e1aSahl if (dp->d_name[0] == '.') 1248f3861e1aSahl continue; 1249f3861e1aSahl 1250f3861e1aSahl if (curr + 1 == size) { 1251f3861e1aSahl paths = zfs_realloc(hdl, paths, 1252f3861e1aSahl size * sizeof (paths[0]), 1253f3861e1aSahl size * 2 * sizeof (paths[0])); 1254f3861e1aSahl if (paths == NULL) { 1255f3861e1aSahl (void) closedir(dirp); 1256f3861e1aSahl (void) close(fd); 1257f3861e1aSahl goto err; 1258f3861e1aSahl } 1259f3861e1aSahl 1260f3861e1aSahl size *= 2; 1261f3861e1aSahl } 1262f3861e1aSahl 1263f3861e1aSahl (void) strlcpy(paths[curr + 1], paths[curr], 1264f3861e1aSahl sizeof (paths[curr + 1])); 1265f3861e1aSahl (void) strlcat(paths[curr], "/", 1266f3861e1aSahl sizeof (paths[curr])); 1267f3861e1aSahl (void) strlcat(paths[curr], dp->d_name, 1268f3861e1aSahl sizeof (paths[curr])); 1269f3861e1aSahl curr++; 1270f3861e1aSahl } 1271f3861e1aSahl 1272f3861e1aSahl (void) closedir(dirp); 1273f3861e1aSahl 1274f3861e1aSahl } else { 1275f3861e1aSahl if ((ret = cb(paths[curr], data)) != 0) 1276f3861e1aSahl break; 1277f3861e1aSahl } 1278f3861e1aSahl 1279f3861e1aSahl curr--; 1280f3861e1aSahl } 1281f3861e1aSahl 1282f3861e1aSahl free(paths); 1283f3861e1aSahl (void) close(base); 1284f3861e1aSahl 1285f3861e1aSahl return (ret); 1286f3861e1aSahl 1287f3861e1aSahl err: 1288f3861e1aSahl free(paths); 1289f3861e1aSahl (void) close(base); 1290f3861e1aSahl return (-1); 1291f3861e1aSahl } 1292f3861e1aSahl 1293f3861e1aSahl typedef struct zvol_cb { 1294f3861e1aSahl zpool_handle_t *zcb_pool; 1295f3861e1aSahl boolean_t zcb_create; 1296f3861e1aSahl } zvol_cb_t; 1297f3861e1aSahl 1298f3861e1aSahl /*ARGSUSED*/ 1299f3861e1aSahl static int 1300f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data) 1301f3861e1aSahl { 1302f3861e1aSahl int ret; 1303f3861e1aSahl 1304f3861e1aSahl if (ZFS_IS_VOLUME(zhp)) 1305f3861e1aSahl (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 1306f3861e1aSahl 1307f3861e1aSahl ret = zfs_iter_children(zhp, do_zvol_create, NULL); 1308fa9e4066Sahrens 1309fa9e4066Sahrens zfs_close(zhp); 1310f3861e1aSahl 1311fa9e4066Sahrens return (ret); 1312fa9e4066Sahrens } 1313fa9e4066Sahrens 1314fa9e4066Sahrens /* 1315fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 1316fa9e4066Sahrens */ 1317fa9e4066Sahrens int 1318fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 1319fa9e4066Sahrens { 1320fa9e4066Sahrens zfs_handle_t *zfp; 1321fa9e4066Sahrens int ret; 1322fa9e4066Sahrens 1323fa9e4066Sahrens /* 1324fa9e4066Sahrens * If the pool is unavailable, just return success. 1325fa9e4066Sahrens */ 132699653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 132799653d4eSeschrock zhp->zpool_name)) == NULL) 1328fa9e4066Sahrens return (0); 1329fa9e4066Sahrens 1330f3861e1aSahl ret = zfs_iter_children(zfp, do_zvol_create, NULL); 1331fa9e4066Sahrens 1332fa9e4066Sahrens zfs_close(zfp); 1333fa9e4066Sahrens return (ret); 1334fa9e4066Sahrens } 1335fa9e4066Sahrens 1336f3861e1aSahl static int 1337f3861e1aSahl do_zvol_remove(const char *dataset, void *data) 1338f3861e1aSahl { 1339f3861e1aSahl zpool_handle_t *zhp = data; 1340f3861e1aSahl 1341f3861e1aSahl return (zvol_remove_link(zhp->zpool_hdl, dataset)); 1342f3861e1aSahl } 1343f3861e1aSahl 1344fa9e4066Sahrens /* 1345f3861e1aSahl * Iterate over all zvols in the pool and remove any minor nodes. We iterate 1346f3861e1aSahl * by examining the /dev links so that a corrupted pool doesn't impede this 1347f3861e1aSahl * operation. 1348fa9e4066Sahrens */ 1349fa9e4066Sahrens int 1350fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 1351fa9e4066Sahrens { 1352f3861e1aSahl return (zpool_iter_zvol(zhp, do_zvol_remove, zhp)); 1353fa9e4066Sahrens } 1354c67d9675Seschrock 1355c67d9675Seschrock /* 1356c67d9675Seschrock * Convert from a devid string to a path. 1357c67d9675Seschrock */ 1358c67d9675Seschrock static char * 1359c67d9675Seschrock devid_to_path(char *devid_str) 1360c67d9675Seschrock { 1361c67d9675Seschrock ddi_devid_t devid; 1362c67d9675Seschrock char *minor; 1363c67d9675Seschrock char *path; 1364c67d9675Seschrock devid_nmlist_t *list = NULL; 1365c67d9675Seschrock int ret; 1366c67d9675Seschrock 1367c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 1368c67d9675Seschrock return (NULL); 1369c67d9675Seschrock 1370c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 1371c67d9675Seschrock 1372c67d9675Seschrock devid_str_free(minor); 1373c67d9675Seschrock devid_free(devid); 1374c67d9675Seschrock 1375c67d9675Seschrock if (ret != 0) 1376c67d9675Seschrock return (NULL); 1377c67d9675Seschrock 137899653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 137999653d4eSeschrock return (NULL); 138099653d4eSeschrock 1381c67d9675Seschrock devid_free_nmlist(list); 1382c67d9675Seschrock 1383c67d9675Seschrock return (path); 1384c67d9675Seschrock } 1385c67d9675Seschrock 1386c67d9675Seschrock /* 1387c67d9675Seschrock * Convert from a path to a devid string. 1388c67d9675Seschrock */ 1389c67d9675Seschrock static char * 1390c67d9675Seschrock path_to_devid(const char *path) 1391c67d9675Seschrock { 1392c67d9675Seschrock int fd; 1393c67d9675Seschrock ddi_devid_t devid; 1394c67d9675Seschrock char *minor, *ret; 1395c67d9675Seschrock 1396c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 1397c67d9675Seschrock return (NULL); 1398c67d9675Seschrock 1399c67d9675Seschrock minor = NULL; 1400c67d9675Seschrock ret = NULL; 1401c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 1402c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 1403c67d9675Seschrock ret = devid_str_encode(devid, minor); 1404c67d9675Seschrock if (minor != NULL) 1405c67d9675Seschrock devid_str_free(minor); 1406c67d9675Seschrock devid_free(devid); 1407c67d9675Seschrock } 1408c67d9675Seschrock (void) close(fd); 1409c67d9675Seschrock 1410c67d9675Seschrock return (ret); 1411c67d9675Seschrock } 1412c67d9675Seschrock 1413c67d9675Seschrock /* 1414c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 1415c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 1416c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 1417c67d9675Seschrock */ 1418c67d9675Seschrock static void 1419c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 1420c67d9675Seschrock { 1421c67d9675Seschrock zfs_cmd_t zc = { 0 }; 1422c67d9675Seschrock 1423c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1424e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 1425c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1426ea8dc4b6Seschrock &zc.zc_guid) == 0); 1427c67d9675Seschrock 142899653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 1429c67d9675Seschrock } 1430c67d9675Seschrock 1431c67d9675Seschrock /* 1432c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 1433c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 1434c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 1435c67d9675Seschrock * trailing 's0' slice name. 1436c67d9675Seschrock * 1437c67d9675Seschrock * This routine is also responsible for identifying when disks have been 1438c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 1439c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 1440c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 1441c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 1442c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 1443c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 1444c67d9675Seschrock * of these checks. 1445c67d9675Seschrock */ 1446c67d9675Seschrock char * 144799653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 1448c67d9675Seschrock { 1449c67d9675Seschrock char *path, *devid; 1450ea8dc4b6Seschrock uint64_t value; 1451ea8dc4b6Seschrock char buf[64]; 1452c67d9675Seschrock 1453ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1454ea8dc4b6Seschrock &value) == 0) { 1455ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1456ea8dc4b6Seschrock &value) == 0); 14575ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 14585ad82045Snd (u_longlong_t)value); 1459ea8dc4b6Seschrock path = buf; 1460ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 1461c67d9675Seschrock 1462c67d9675Seschrock if (zhp != NULL && 1463c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 1464c67d9675Seschrock /* 1465c67d9675Seschrock * Determine if the current path is correct. 1466c67d9675Seschrock */ 1467c67d9675Seschrock char *newdevid = path_to_devid(path); 1468c67d9675Seschrock 1469c67d9675Seschrock if (newdevid == NULL || 1470c67d9675Seschrock strcmp(devid, newdevid) != 0) { 1471c67d9675Seschrock char *newpath; 1472c67d9675Seschrock 1473c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 1474c67d9675Seschrock /* 1475c67d9675Seschrock * Update the path appropriately. 1476c67d9675Seschrock */ 1477c67d9675Seschrock set_path(zhp, nv, newpath); 147899653d4eSeschrock if (nvlist_add_string(nv, 147999653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 148099653d4eSeschrock verify(nvlist_lookup_string(nv, 148199653d4eSeschrock ZPOOL_CONFIG_PATH, 148299653d4eSeschrock &path) == 0); 1483c67d9675Seschrock free(newpath); 1484c67d9675Seschrock } 1485c67d9675Seschrock } 1486c67d9675Seschrock 148799653d4eSeschrock if (newdevid) 148899653d4eSeschrock devid_str_free(newdevid); 1489c67d9675Seschrock } 1490c67d9675Seschrock 1491c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 1492c67d9675Seschrock path += 9; 1493c67d9675Seschrock 1494c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1495ea8dc4b6Seschrock &value) == 0 && value) { 149699653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 149799653d4eSeschrock if (tmp == NULL) 149899653d4eSeschrock return (NULL); 1499c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 1500c67d9675Seschrock return (tmp); 1501c67d9675Seschrock } 1502c67d9675Seschrock } else { 1503c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 150499653d4eSeschrock 150599653d4eSeschrock /* 150699653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 150799653d4eSeschrock */ 150899653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 150999653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 151099653d4eSeschrock &value) == 0); 151199653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 15125ad82045Snd (u_longlong_t)value); 151399653d4eSeschrock path = buf; 151499653d4eSeschrock } 1515c67d9675Seschrock } 1516c67d9675Seschrock 151799653d4eSeschrock return (zfs_strdup(hdl, path)); 1518c67d9675Seschrock } 1519ea8dc4b6Seschrock 1520ea8dc4b6Seschrock static int 1521ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 1522ea8dc4b6Seschrock { 1523ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 1524ea8dc4b6Seschrock } 1525ea8dc4b6Seschrock 1526ea8dc4b6Seschrock /* 1527ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 1528ea8dc4b6Seschrock * caller. 1529ea8dc4b6Seschrock */ 1530ea8dc4b6Seschrock int 153155434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp) 1532ea8dc4b6Seschrock { 1533ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1534ea8dc4b6Seschrock uint64_t count; 1535e9dbad6fSeschrock zbookmark_t *zb = NULL; 153655434c77Sek int i; 1537ea8dc4b6Seschrock 1538ea8dc4b6Seschrock /* 1539ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 1540ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 1541ea8dc4b6Seschrock * entire list. 1542ea8dc4b6Seschrock */ 1543ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 1544ea8dc4b6Seschrock &count) == 0); 1545e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 15465ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 154799653d4eSeschrock return (-1); 1548e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 1549ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 1550ea8dc4b6Seschrock for (;;) { 155199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 155299653d4eSeschrock &zc) != 0) { 1553e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 1554ea8dc4b6Seschrock if (errno == ENOMEM) { 1555*bf561db0Svb count = zc.zc_nvlist_dst_size; 1556e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 1557*bf561db0Svb zfs_alloc(zhp->zpool_hdl, count * 1558*bf561db0Svb sizeof (zbookmark_t))) == (uintptr_t)NULL) 155999653d4eSeschrock return (-1); 1560ea8dc4b6Seschrock } else { 1561ea8dc4b6Seschrock return (-1); 1562ea8dc4b6Seschrock } 1563ea8dc4b6Seschrock } else { 1564ea8dc4b6Seschrock break; 1565ea8dc4b6Seschrock } 1566ea8dc4b6Seschrock } 1567ea8dc4b6Seschrock 1568ea8dc4b6Seschrock /* 1569ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 1570ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 1571e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 1572ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 1573ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 1574ea8dc4b6Seschrock */ 1575e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 1576e9dbad6fSeschrock zc.zc_nvlist_dst_size; 1577e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 1578ea8dc4b6Seschrock 1579ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 1580ea8dc4b6Seschrock 158155434c77Sek verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0); 1582ea8dc4b6Seschrock 1583ea8dc4b6Seschrock /* 158455434c77Sek * Fill in the nverrlistp with nvlist's of dataset and object numbers. 1585ea8dc4b6Seschrock */ 1586ea8dc4b6Seschrock for (i = 0; i < count; i++) { 1587ea8dc4b6Seschrock nvlist_t *nv; 1588ea8dc4b6Seschrock 1589c0a81264Sek /* ignoring zb_blkid and zb_level for now */ 1590c0a81264Sek if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset && 1591c0a81264Sek zb[i-1].zb_object == zb[i].zb_object) 1592ea8dc4b6Seschrock continue; 1593ea8dc4b6Seschrock 159455434c77Sek if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0) 159555434c77Sek goto nomem; 159655434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET, 159755434c77Sek zb[i].zb_objset) != 0) { 159855434c77Sek nvlist_free(nv); 159999653d4eSeschrock goto nomem; 1600ea8dc4b6Seschrock } 160155434c77Sek if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT, 160255434c77Sek zb[i].zb_object) != 0) { 160355434c77Sek nvlist_free(nv); 160455434c77Sek goto nomem; 160555434c77Sek } 160655434c77Sek if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) { 160755434c77Sek nvlist_free(nv); 160855434c77Sek goto nomem; 160955434c77Sek } 161055434c77Sek nvlist_free(nv); 1611ea8dc4b6Seschrock } 1612ea8dc4b6Seschrock 16133ccfa83cSahrens free((void *)(uintptr_t)zc.zc_nvlist_dst); 1614ea8dc4b6Seschrock return (0); 161599653d4eSeschrock 161699653d4eSeschrock nomem: 1617e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 161899653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 1619ea8dc4b6Seschrock } 1620eaca9bbdSeschrock 1621eaca9bbdSeschrock /* 1622eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 1623eaca9bbdSeschrock */ 1624eaca9bbdSeschrock int 1625eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp) 1626eaca9bbdSeschrock { 1627eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 162899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1629eaca9bbdSeschrock 1630eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 163199653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 1632ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 163399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 163499653d4eSeschrock zhp->zpool_name)); 1635eaca9bbdSeschrock 1636eaca9bbdSeschrock return (0); 1637eaca9bbdSeschrock } 163806eeb2adSek 163906eeb2adSek /* 164006eeb2adSek * Log command history. 164106eeb2adSek * 164206eeb2adSek * 'pool' is B_TRUE if we are logging a command for 'zpool'; B_FALSE 164306eeb2adSek * otherwise ('zfs'). 'pool_create' is B_TRUE if we are logging the creation 164406eeb2adSek * of the pool; B_FALSE otherwise. 'path' is the pathanme containing the 164506eeb2adSek * poolname. 'argc' and 'argv' are used to construct the command string. 164606eeb2adSek */ 164706eeb2adSek void 164806eeb2adSek zpool_log_history(libzfs_handle_t *hdl, int argc, char **argv, const char *path, 164906eeb2adSek boolean_t pool, boolean_t pool_create) 165006eeb2adSek { 165106eeb2adSek char cmd_buf[HIS_MAX_RECORD_LEN]; 165206eeb2adSek char *dspath; 165306eeb2adSek zfs_cmd_t zc = { 0 }; 165406eeb2adSek int i; 165506eeb2adSek 165606eeb2adSek /* construct the command string */ 165706eeb2adSek (void) strcpy(cmd_buf, pool ? "zpool" : "zfs"); 165806eeb2adSek for (i = 0; i < argc; i++) { 165906eeb2adSek if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN) 166006eeb2adSek break; 166106eeb2adSek (void) strcat(cmd_buf, " "); 166206eeb2adSek (void) strcat(cmd_buf, argv[i]); 166306eeb2adSek } 166406eeb2adSek 166506eeb2adSek /* figure out the poolname */ 166606eeb2adSek dspath = strpbrk(path, "/@"); 166706eeb2adSek if (dspath == NULL) { 166806eeb2adSek (void) strcpy(zc.zc_name, path); 166906eeb2adSek } else { 167006eeb2adSek (void) strncpy(zc.zc_name, path, dspath - path); 167106eeb2adSek zc.zc_name[dspath-path] = '\0'; 167206eeb2adSek } 167306eeb2adSek 167406eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)cmd_buf; 167506eeb2adSek zc.zc_history_len = strlen(cmd_buf); 167606eeb2adSek 167706eeb2adSek /* overloading zc_history_offset */ 167806eeb2adSek zc.zc_history_offset = pool_create; 167906eeb2adSek 168006eeb2adSek (void) ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_LOG_HISTORY, &zc); 168106eeb2adSek } 168206eeb2adSek 168306eeb2adSek /* 168406eeb2adSek * Perform ioctl to get some command history of a pool. 168506eeb2adSek * 168606eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 168706eeb2adSek * logical offset of the history buffer to start reading from. 168806eeb2adSek * 168906eeb2adSek * Upon return, 'off' is the next logical offset to read from and 169006eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 169106eeb2adSek */ 169206eeb2adSek static int 169306eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 169406eeb2adSek { 169506eeb2adSek zfs_cmd_t zc = { 0 }; 169606eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 169706eeb2adSek 169806eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 169906eeb2adSek 170006eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 170106eeb2adSek zc.zc_history_len = *len; 170206eeb2adSek zc.zc_history_offset = *off; 170306eeb2adSek 170406eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 170506eeb2adSek switch (errno) { 170606eeb2adSek case EPERM: 1707ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_PERM, 1708ece3d9b3Slling dgettext(TEXT_DOMAIN, 170906eeb2adSek "cannot show history for pool '%s'"), 171006eeb2adSek zhp->zpool_name)); 171106eeb2adSek case ENOENT: 1712ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_NOHISTORY, 171306eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 171406eeb2adSek "'%s'"), zhp->zpool_name)); 171506eeb2adSek default: 1716ece3d9b3Slling return (zpool_standard_error_fmt(hdl, errno, 171706eeb2adSek dgettext(TEXT_DOMAIN, 171806eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 171906eeb2adSek } 172006eeb2adSek } 172106eeb2adSek 172206eeb2adSek *len = zc.zc_history_len; 172306eeb2adSek *off = zc.zc_history_offset; 172406eeb2adSek 172506eeb2adSek return (0); 172606eeb2adSek } 172706eeb2adSek 172806eeb2adSek /* 172906eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 173006eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 173106eeb2adSek * processed as there wasn't a complete record. 173206eeb2adSek */ 173306eeb2adSek static int 173406eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 173506eeb2adSek nvlist_t ***records, uint_t *numrecords) 173606eeb2adSek { 173706eeb2adSek uint64_t reclen; 173806eeb2adSek nvlist_t *nv; 173906eeb2adSek int i; 174006eeb2adSek 174106eeb2adSek while (bytes_read > sizeof (reclen)) { 174206eeb2adSek 174306eeb2adSek /* get length of packed record (stored as little endian) */ 174406eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 174506eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 174606eeb2adSek 174706eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 174806eeb2adSek break; 174906eeb2adSek 175006eeb2adSek /* unpack record */ 175106eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 175206eeb2adSek return (ENOMEM); 175306eeb2adSek bytes_read -= sizeof (reclen) + reclen; 175406eeb2adSek buf += sizeof (reclen) + reclen; 175506eeb2adSek 175606eeb2adSek /* add record to nvlist array */ 175706eeb2adSek (*numrecords)++; 175806eeb2adSek if (ISP2(*numrecords + 1)) { 175906eeb2adSek *records = realloc(*records, 176006eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 176106eeb2adSek } 176206eeb2adSek (*records)[*numrecords - 1] = nv; 176306eeb2adSek } 176406eeb2adSek 176506eeb2adSek *leftover = bytes_read; 176606eeb2adSek return (0); 176706eeb2adSek } 176806eeb2adSek 176906eeb2adSek #define HIS_BUF_LEN (128*1024) 177006eeb2adSek 177106eeb2adSek /* 177206eeb2adSek * Retrieve the command history of a pool. 177306eeb2adSek */ 177406eeb2adSek int 177506eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 177606eeb2adSek { 177706eeb2adSek char buf[HIS_BUF_LEN]; 177806eeb2adSek uint64_t off = 0; 177906eeb2adSek nvlist_t **records = NULL; 178006eeb2adSek uint_t numrecords = 0; 178106eeb2adSek int err, i; 178206eeb2adSek 178306eeb2adSek do { 178406eeb2adSek uint64_t bytes_read = sizeof (buf); 178506eeb2adSek uint64_t leftover; 178606eeb2adSek 178706eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 178806eeb2adSek break; 178906eeb2adSek 179006eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 179106eeb2adSek if (!bytes_read) 179206eeb2adSek break; 179306eeb2adSek 179406eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 179506eeb2adSek &leftover, &records, &numrecords)) != 0) 179606eeb2adSek break; 179706eeb2adSek off -= leftover; 179806eeb2adSek 179906eeb2adSek /* CONSTCOND */ 180006eeb2adSek } while (1); 180106eeb2adSek 180206eeb2adSek if (!err) { 180306eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 180406eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 180506eeb2adSek records, numrecords) == 0); 180606eeb2adSek } 180706eeb2adSek for (i = 0; i < numrecords; i++) 180806eeb2adSek nvlist_free(records[i]); 180906eeb2adSek free(records); 181006eeb2adSek 181106eeb2adSek return (err); 181206eeb2adSek } 181355434c77Sek 181455434c77Sek void 181555434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, 181655434c77Sek char *pathname, size_t len) 181755434c77Sek { 181855434c77Sek zfs_cmd_t zc = { 0 }; 181955434c77Sek boolean_t mounted = B_FALSE; 182055434c77Sek char *mntpnt = NULL; 182155434c77Sek char dsname[MAXNAMELEN]; 182255434c77Sek 182355434c77Sek if (dsobj == 0) { 182455434c77Sek /* special case for the MOS */ 182555434c77Sek (void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj); 182655434c77Sek return; 182755434c77Sek } 182855434c77Sek 182955434c77Sek /* get the dataset's name */ 183055434c77Sek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 183155434c77Sek zc.zc_obj = dsobj; 183255434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, 183355434c77Sek ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) { 183455434c77Sek /* just write out a path of two object numbers */ 183555434c77Sek (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>", 183655434c77Sek dsobj, obj); 183755434c77Sek return; 183855434c77Sek } 183955434c77Sek (void) strlcpy(dsname, zc.zc_value, sizeof (dsname)); 184055434c77Sek 184155434c77Sek /* find out if the dataset is mounted */ 184255434c77Sek mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt); 184355434c77Sek 184455434c77Sek /* get the corrupted object's path */ 184555434c77Sek (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name)); 184655434c77Sek zc.zc_obj = obj; 184755434c77Sek if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH, 184855434c77Sek &zc) == 0) { 184955434c77Sek if (mounted) { 185055434c77Sek (void) snprintf(pathname, len, "%s%s", mntpnt, 185155434c77Sek zc.zc_value); 185255434c77Sek } else { 185355434c77Sek (void) snprintf(pathname, len, "%s:%s", 185455434c77Sek dsname, zc.zc_value); 185555434c77Sek } 185655434c77Sek } else { 185755434c77Sek (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj); 185855434c77Sek } 185955434c77Sek free(mntpnt); 186055434c77Sek } 1861