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 /* 23c67d9675Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include <assert.h> 30fa9e4066Sahrens #include <ctype.h> 31fa9e4066Sahrens #include <errno.h> 32fa9e4066Sahrens #include <devid.h> 33fa9e4066Sahrens #include <fcntl.h> 34fa9e4066Sahrens #include <libintl.h> 35fa9e4066Sahrens #include <stdio.h> 36fa9e4066Sahrens #include <stdlib.h> 37fa9e4066Sahrens #include <string.h> 38fa9e4066Sahrens #include <unistd.h> 39fa9e4066Sahrens #include <sys/zfs_ioctl.h> 40ea8dc4b6Seschrock #include <sys/zio.h> 41*06eeb2adSek #include <strings.h> 42fa9e4066Sahrens 43fa9e4066Sahrens #include "zfs_namecheck.h" 44fa9e4066Sahrens #include "libzfs_impl.h" 45fa9e4066Sahrens 46fa9e4066Sahrens /* 47fa9e4066Sahrens * Validate the given pool name, optionally putting an extended error message in 48fa9e4066Sahrens * 'buf'. 49fa9e4066Sahrens */ 5099653d4eSeschrock static boolean_t 5199653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool) 52fa9e4066Sahrens { 53fa9e4066Sahrens namecheck_err_t why; 54fa9e4066Sahrens char what; 55b468a217Seschrock int ret; 56b468a217Seschrock 57b468a217Seschrock ret = pool_namecheck(pool, &why, &what); 58b468a217Seschrock 59b468a217Seschrock /* 60b468a217Seschrock * The rules for reserved pool names were extended at a later point. 61b468a217Seschrock * But we need to support users with existing pools that may now be 62b468a217Seschrock * invalid. So we only check for this expanded set of names during a 63b468a217Seschrock * create (or import), and only in userland. 64b468a217Seschrock */ 65b468a217Seschrock if (ret == 0 && !isopen && 66b468a217Seschrock (strncmp(pool, "mirror", 6) == 0 || 67b468a217Seschrock strncmp(pool, "raidz", 5) == 0 || 68b468a217Seschrock strncmp(pool, "spare", 5) == 0)) { 6999653d4eSeschrock zfs_error_aux(hdl, 7099653d4eSeschrock dgettext(TEXT_DOMAIN, "name is reserved")); 7199653d4eSeschrock return (B_FALSE); 72b468a217Seschrock } 73b468a217Seschrock 74fa9e4066Sahrens 75b468a217Seschrock if (ret != 0) { 7699653d4eSeschrock if (hdl != NULL) { 77fa9e4066Sahrens switch (why) { 78b81d61a6Slling case NAME_ERR_TOOLONG: 7999653d4eSeschrock zfs_error_aux(hdl, 80b81d61a6Slling dgettext(TEXT_DOMAIN, "name is too long")); 81b81d61a6Slling break; 82b81d61a6Slling 83fa9e4066Sahrens case NAME_ERR_INVALCHAR: 8499653d4eSeschrock zfs_error_aux(hdl, 85fa9e4066Sahrens dgettext(TEXT_DOMAIN, "invalid character " 86fa9e4066Sahrens "'%c' in pool name"), what); 87fa9e4066Sahrens break; 88fa9e4066Sahrens 89fa9e4066Sahrens case NAME_ERR_NOLETTER: 9099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9199653d4eSeschrock "name must begin with a letter")); 92fa9e4066Sahrens break; 93fa9e4066Sahrens 94fa9e4066Sahrens case NAME_ERR_RESERVED: 9599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 9699653d4eSeschrock "name is reserved")); 97fa9e4066Sahrens break; 98fa9e4066Sahrens 99fa9e4066Sahrens case NAME_ERR_DISKLIKE: 10099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10199653d4eSeschrock "pool name is reserved")); 102fa9e4066Sahrens break; 1035ad82045Snd 1045ad82045Snd case NAME_ERR_LEADING_SLASH: 1055ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1065ad82045Snd "leading slash in name")); 1075ad82045Snd break; 1085ad82045Snd 1095ad82045Snd case NAME_ERR_EMPTY_COMPONENT: 1105ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1115ad82045Snd "empty component in name")); 1125ad82045Snd break; 1135ad82045Snd 1145ad82045Snd case NAME_ERR_TRAILING_SLASH: 1155ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1165ad82045Snd "trailing slash in name")); 1175ad82045Snd break; 1185ad82045Snd 1195ad82045Snd case NAME_ERR_MULTIPLE_AT: 1205ad82045Snd zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1215ad82045Snd "multiple '@' delimiters in name")); 1225ad82045Snd break; 1235ad82045Snd 124fa9e4066Sahrens } 125fa9e4066Sahrens } 12699653d4eSeschrock return (B_FALSE); 127fa9e4066Sahrens } 128fa9e4066Sahrens 12999653d4eSeschrock return (B_TRUE); 130fa9e4066Sahrens } 131fa9e4066Sahrens 132fa9e4066Sahrens /* 133fa9e4066Sahrens * Set the pool-wide health based on the vdev state of the root vdev. 134fa9e4066Sahrens */ 13599653d4eSeschrock int 136fa9e4066Sahrens set_pool_health(nvlist_t *config) 137fa9e4066Sahrens { 138fa9e4066Sahrens nvlist_t *nvroot; 139fa9e4066Sahrens vdev_stat_t *vs; 140fa9e4066Sahrens uint_t vsc; 141fa9e4066Sahrens char *health; 142fa9e4066Sahrens 143fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 144fa9e4066Sahrens &nvroot) == 0); 145fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 146fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 147fa9e4066Sahrens 148fa9e4066Sahrens switch (vs->vs_state) { 149fa9e4066Sahrens 150fa9e4066Sahrens case VDEV_STATE_CLOSED: 151fa9e4066Sahrens case VDEV_STATE_CANT_OPEN: 152fa9e4066Sahrens case VDEV_STATE_OFFLINE: 153fa9e4066Sahrens health = dgettext(TEXT_DOMAIN, "FAULTED"); 154fa9e4066Sahrens break; 155fa9e4066Sahrens 156fa9e4066Sahrens case VDEV_STATE_DEGRADED: 157fa9e4066Sahrens health = dgettext(TEXT_DOMAIN, "DEGRADED"); 158fa9e4066Sahrens break; 159fa9e4066Sahrens 160fa9e4066Sahrens case VDEV_STATE_HEALTHY: 161fa9e4066Sahrens health = dgettext(TEXT_DOMAIN, "ONLINE"); 162fa9e4066Sahrens break; 163fa9e4066Sahrens 164fa9e4066Sahrens default: 16599653d4eSeschrock abort(); 166fa9e4066Sahrens } 167fa9e4066Sahrens 16899653d4eSeschrock return (nvlist_add_string(config, ZPOOL_CONFIG_POOL_HEALTH, health)); 169fa9e4066Sahrens } 170fa9e4066Sahrens 171fa9e4066Sahrens /* 172fa9e4066Sahrens * Open a handle to the given pool, even if the pool is currently in the FAULTED 173fa9e4066Sahrens * state. 174fa9e4066Sahrens */ 175fa9e4066Sahrens zpool_handle_t * 17699653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool) 177fa9e4066Sahrens { 178fa9e4066Sahrens zpool_handle_t *zhp; 17994de1d4cSeschrock boolean_t missing; 180fa9e4066Sahrens 181fa9e4066Sahrens /* 182fa9e4066Sahrens * Make sure the pool name is valid. 183fa9e4066Sahrens */ 18499653d4eSeschrock if (!zpool_name_valid(hdl, B_TRUE, pool)) { 18599653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALIDNAME, 18699653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 18799653d4eSeschrock pool); 188fa9e4066Sahrens return (NULL); 189fa9e4066Sahrens } 190fa9e4066Sahrens 19199653d4eSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 19299653d4eSeschrock return (NULL); 193fa9e4066Sahrens 19499653d4eSeschrock zhp->zpool_hdl = hdl; 195fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 196fa9e4066Sahrens 19794de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 19894de1d4cSeschrock zpool_close(zhp); 19994de1d4cSeschrock return (NULL); 20094de1d4cSeschrock } 20194de1d4cSeschrock 20294de1d4cSeschrock if (missing) { 20394de1d4cSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 20494de1d4cSeschrock "no such pool")); 20594de1d4cSeschrock (void) zfs_error(hdl, EZFS_NOENT, 20694de1d4cSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), 20794de1d4cSeschrock pool); 20894de1d4cSeschrock zpool_close(zhp); 20994de1d4cSeschrock return (NULL); 210fa9e4066Sahrens } 211fa9e4066Sahrens 212fa9e4066Sahrens return (zhp); 213fa9e4066Sahrens } 214fa9e4066Sahrens 215fa9e4066Sahrens /* 216fa9e4066Sahrens * Like the above, but silent on error. Used when iterating over pools (because 217fa9e4066Sahrens * the configuration cache may be out of date). 218fa9e4066Sahrens */ 21994de1d4cSeschrock int 22094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret) 221fa9e4066Sahrens { 222fa9e4066Sahrens zpool_handle_t *zhp; 22394de1d4cSeschrock boolean_t missing; 224fa9e4066Sahrens 22594de1d4cSeschrock if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL) 22694de1d4cSeschrock return (-1); 227fa9e4066Sahrens 22899653d4eSeschrock zhp->zpool_hdl = hdl; 229fa9e4066Sahrens (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name)); 230fa9e4066Sahrens 23194de1d4cSeschrock if (zpool_refresh_stats(zhp, &missing) != 0) { 23294de1d4cSeschrock zpool_close(zhp); 23394de1d4cSeschrock return (-1); 234fa9e4066Sahrens } 235fa9e4066Sahrens 23694de1d4cSeschrock if (missing) { 23794de1d4cSeschrock zpool_close(zhp); 23894de1d4cSeschrock *ret = NULL; 23994de1d4cSeschrock return (0); 24094de1d4cSeschrock } 24194de1d4cSeschrock 24294de1d4cSeschrock *ret = zhp; 24394de1d4cSeschrock return (0); 244fa9e4066Sahrens } 245fa9e4066Sahrens 246fa9e4066Sahrens /* 247fa9e4066Sahrens * Similar to zpool_open_canfail(), but refuses to open pools in the faulted 248fa9e4066Sahrens * state. 249fa9e4066Sahrens */ 250fa9e4066Sahrens zpool_handle_t * 25199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool) 252fa9e4066Sahrens { 253fa9e4066Sahrens zpool_handle_t *zhp; 254fa9e4066Sahrens 25599653d4eSeschrock if ((zhp = zpool_open_canfail(hdl, pool)) == NULL) 256fa9e4066Sahrens return (NULL); 257fa9e4066Sahrens 258fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_UNAVAIL) { 25999653d4eSeschrock (void) zfs_error(hdl, EZFS_POOLUNAVAIL, 26099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name); 261fa9e4066Sahrens zpool_close(zhp); 262fa9e4066Sahrens return (NULL); 263fa9e4066Sahrens } 264fa9e4066Sahrens 265fa9e4066Sahrens return (zhp); 266fa9e4066Sahrens } 267fa9e4066Sahrens 268fa9e4066Sahrens /* 269fa9e4066Sahrens * Close the handle. Simply frees the memory associated with the handle. 270fa9e4066Sahrens */ 271fa9e4066Sahrens void 272fa9e4066Sahrens zpool_close(zpool_handle_t *zhp) 273fa9e4066Sahrens { 274fa9e4066Sahrens if (zhp->zpool_config) 275fa9e4066Sahrens nvlist_free(zhp->zpool_config); 276088e9d47Seschrock if (zhp->zpool_old_config) 277088e9d47Seschrock nvlist_free(zhp->zpool_old_config); 278ea8dc4b6Seschrock if (zhp->zpool_error_log) { 279ea8dc4b6Seschrock int i; 280ea8dc4b6Seschrock for (i = 0; i < zhp->zpool_error_count; i++) 28199653d4eSeschrock nvlist_free(zhp->zpool_error_log[i]); 282ea8dc4b6Seschrock free(zhp->zpool_error_log); 283ea8dc4b6Seschrock } 284fa9e4066Sahrens free(zhp); 285fa9e4066Sahrens } 286fa9e4066Sahrens 287fa9e4066Sahrens /* 288fa9e4066Sahrens * Return the name of the pool. 289fa9e4066Sahrens */ 290fa9e4066Sahrens const char * 291fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp) 292fa9e4066Sahrens { 293fa9e4066Sahrens return (zhp->zpool_name); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296fa9e4066Sahrens /* 297fa9e4066Sahrens * Return the GUID of the pool. 298fa9e4066Sahrens */ 299fa9e4066Sahrens uint64_t 300fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp) 301fa9e4066Sahrens { 302fa9e4066Sahrens uint64_t guid; 303fa9e4066Sahrens 304fa9e4066Sahrens verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID, 305fa9e4066Sahrens &guid) == 0); 306fa9e4066Sahrens return (guid); 307fa9e4066Sahrens } 308fa9e4066Sahrens 30999653d4eSeschrock /* 31099653d4eSeschrock * Return the version of the pool. 31199653d4eSeschrock */ 31299653d4eSeschrock uint64_t 31399653d4eSeschrock zpool_get_version(zpool_handle_t *zhp) 31499653d4eSeschrock { 31599653d4eSeschrock uint64_t version; 31699653d4eSeschrock 31799653d4eSeschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION, 31899653d4eSeschrock &version) == 0); 31999653d4eSeschrock 32099653d4eSeschrock return (version); 32199653d4eSeschrock } 32299653d4eSeschrock 323fa9e4066Sahrens /* 324fa9e4066Sahrens * Return the amount of space currently consumed by the pool. 325fa9e4066Sahrens */ 326fa9e4066Sahrens uint64_t 327fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp) 328fa9e4066Sahrens { 329fa9e4066Sahrens nvlist_t *nvroot; 330fa9e4066Sahrens vdev_stat_t *vs; 331fa9e4066Sahrens uint_t vsc; 332fa9e4066Sahrens 333fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 334fa9e4066Sahrens &nvroot) == 0); 335fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 336fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 337fa9e4066Sahrens 338fa9e4066Sahrens return (vs->vs_alloc); 339fa9e4066Sahrens } 340fa9e4066Sahrens 341fa9e4066Sahrens /* 342fa9e4066Sahrens * Return the total space in the pool. 343fa9e4066Sahrens */ 344fa9e4066Sahrens uint64_t 345fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp) 346fa9e4066Sahrens { 347fa9e4066Sahrens nvlist_t *nvroot; 348fa9e4066Sahrens vdev_stat_t *vs; 349fa9e4066Sahrens uint_t vsc; 350fa9e4066Sahrens 351fa9e4066Sahrens verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 352fa9e4066Sahrens &nvroot) == 0); 353fa9e4066Sahrens verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, 354fa9e4066Sahrens (uint64_t **)&vs, &vsc) == 0); 355fa9e4066Sahrens 356fa9e4066Sahrens return (vs->vs_space); 357fa9e4066Sahrens } 358fa9e4066Sahrens 359fa9e4066Sahrens /* 360fa9e4066Sahrens * Return the alternate root for this pool, if any. 361fa9e4066Sahrens */ 362fa9e4066Sahrens int 363fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen) 364fa9e4066Sahrens { 365fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 366fa9e4066Sahrens 367fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 36899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 || 369e9dbad6fSeschrock zc.zc_value[0] == '\0') 370fa9e4066Sahrens return (-1); 371fa9e4066Sahrens 372e9dbad6fSeschrock (void) strlcpy(buf, zc.zc_value, buflen); 373fa9e4066Sahrens 374fa9e4066Sahrens return (0); 375fa9e4066Sahrens } 376fa9e4066Sahrens 377fa9e4066Sahrens /* 378fa9e4066Sahrens * Return the state of the pool (ACTIVE or UNAVAILABLE) 379fa9e4066Sahrens */ 380fa9e4066Sahrens int 381fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp) 382fa9e4066Sahrens { 383fa9e4066Sahrens return (zhp->zpool_state); 384fa9e4066Sahrens } 385fa9e4066Sahrens 386fa9e4066Sahrens /* 387fa9e4066Sahrens * Create the named pool, using the provided vdev list. It is assumed 388fa9e4066Sahrens * that the consumer has already validated the contents of the nvlist, so we 389fa9e4066Sahrens * don't have to worry about error semantics. 390fa9e4066Sahrens */ 391fa9e4066Sahrens int 39299653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot, 39399653d4eSeschrock const char *altroot) 394fa9e4066Sahrens { 395fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 39699653d4eSeschrock char msg[1024]; 397fa9e4066Sahrens 39899653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 39999653d4eSeschrock "cannot create '%s'"), pool); 400fa9e4066Sahrens 40199653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, pool)) 40299653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, msg)); 403fa9e4066Sahrens 40499653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 40599653d4eSeschrock return (zfs_error(hdl, EZFS_BADPATH, 40699653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot)); 407fa9e4066Sahrens 408e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 40999653d4eSeschrock return (-1); 41099653d4eSeschrock 411fa9e4066Sahrens (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 412fa9e4066Sahrens 413fa9e4066Sahrens if (altroot != NULL) 414e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 415fa9e4066Sahrens 41699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) { 417e9dbad6fSeschrock zcmd_free_nvlists(&zc); 418fa9e4066Sahrens 41999653d4eSeschrock switch (errno) { 420fa9e4066Sahrens case EBUSY: 421fa9e4066Sahrens /* 422fa9e4066Sahrens * This can happen if the user has specified the same 423fa9e4066Sahrens * device multiple times. We can't reliably detect this 424fa9e4066Sahrens * until we try to add it and see we already have a 425fa9e4066Sahrens * label. 426fa9e4066Sahrens */ 42799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 42899653d4eSeschrock "one or more vdevs refer to the same device")); 42999653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 430fa9e4066Sahrens 431fa9e4066Sahrens case EOVERFLOW: 432fa9e4066Sahrens /* 43399653d4eSeschrock * This occurs when one of the devices is below 434fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 435fa9e4066Sahrens * device was the problem device since there's no 436fa9e4066Sahrens * reliable way to determine device size from userland. 437fa9e4066Sahrens */ 438fa9e4066Sahrens { 439fa9e4066Sahrens char buf[64]; 440fa9e4066Sahrens 441fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 442fa9e4066Sahrens 44399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 44499653d4eSeschrock "one or more devices is less than the " 44599653d4eSeschrock "minimum size (%s)"), buf); 446fa9e4066Sahrens } 44799653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 448fa9e4066Sahrens 449fa9e4066Sahrens case ENOSPC: 45099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 45199653d4eSeschrock "one or more devices is out of space")); 45299653d4eSeschrock return (zfs_error(hdl, EZFS_BADDEV, msg)); 453fa9e4066Sahrens 454fa9e4066Sahrens default: 45599653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 456fa9e4066Sahrens } 457fa9e4066Sahrens } 458fa9e4066Sahrens 459e9dbad6fSeschrock zcmd_free_nvlists(&zc); 460fa9e4066Sahrens 461fa9e4066Sahrens /* 462fa9e4066Sahrens * If this is an alternate root pool, then we automatically set the 463e9dbad6fSeschrock * mountpoint of the root dataset to be '/'. 464fa9e4066Sahrens */ 465fa9e4066Sahrens if (altroot != NULL) { 466fa9e4066Sahrens zfs_handle_t *zhp; 467fa9e4066Sahrens 46899653d4eSeschrock verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL); 469e9dbad6fSeschrock verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 470e9dbad6fSeschrock "/") == 0); 471fa9e4066Sahrens 472fa9e4066Sahrens zfs_close(zhp); 473fa9e4066Sahrens } 474fa9e4066Sahrens 475fa9e4066Sahrens return (0); 476fa9e4066Sahrens } 477fa9e4066Sahrens 478fa9e4066Sahrens /* 479fa9e4066Sahrens * Destroy the given pool. It is up to the caller to ensure that there are no 480fa9e4066Sahrens * datasets left in the pool. 481fa9e4066Sahrens */ 482fa9e4066Sahrens int 483fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp) 484fa9e4066Sahrens { 485fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 486fa9e4066Sahrens zfs_handle_t *zfp = NULL; 48799653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 48899653d4eSeschrock char msg[1024]; 489fa9e4066Sahrens 490fa9e4066Sahrens if (zhp->zpool_state == POOL_STATE_ACTIVE && 49199653d4eSeschrock (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 49299653d4eSeschrock ZFS_TYPE_FILESYSTEM)) == NULL) 493fa9e4066Sahrens return (-1); 494fa9e4066Sahrens 4955ad82045Snd if (zpool_remove_zvol_links(zhp) != 0) 496fa9e4066Sahrens return (-1); 497fa9e4066Sahrens 498fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 499fa9e4066Sahrens 50099653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) { 50199653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 50299653d4eSeschrock "cannot destroy '%s'"), zhp->zpool_name); 503fa9e4066Sahrens 50499653d4eSeschrock if (errno == EROFS) { 50599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 50699653d4eSeschrock "one or more devices is read only")); 50799653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 50899653d4eSeschrock } else { 50999653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 510fa9e4066Sahrens } 511fa9e4066Sahrens 512fa9e4066Sahrens if (zfp) 513fa9e4066Sahrens zfs_close(zfp); 514fa9e4066Sahrens return (-1); 515fa9e4066Sahrens } 516fa9e4066Sahrens 517fa9e4066Sahrens if (zfp) { 518fa9e4066Sahrens remove_mountpoint(zfp); 519fa9e4066Sahrens zfs_close(zfp); 520fa9e4066Sahrens } 521fa9e4066Sahrens 522fa9e4066Sahrens return (0); 523fa9e4066Sahrens } 524fa9e4066Sahrens 525fa9e4066Sahrens /* 526fa9e4066Sahrens * Add the given vdevs to the pool. The caller must have already performed the 527fa9e4066Sahrens * necessary verification to ensure that the vdev specification is well-formed. 528fa9e4066Sahrens */ 529fa9e4066Sahrens int 530fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) 531fa9e4066Sahrens { 532e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 53399653d4eSeschrock int ret; 53499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 53599653d4eSeschrock char msg[1024]; 53699653d4eSeschrock nvlist_t **spares; 53799653d4eSeschrock uint_t nspares; 53899653d4eSeschrock 53999653d4eSeschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 54099653d4eSeschrock "cannot add to '%s'"), zhp->zpool_name); 54199653d4eSeschrock 54299653d4eSeschrock if (zpool_get_version(zhp) < ZFS_VERSION_SPARES && 54399653d4eSeschrock nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 54499653d4eSeschrock &spares, &nspares) == 0) { 54599653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " 54699653d4eSeschrock "upgraded to add hot spares")); 54799653d4eSeschrock return (zfs_error(hdl, EZFS_BADVERSION, msg)); 54899653d4eSeschrock } 549fa9e4066Sahrens 550e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 55199653d4eSeschrock return (-1); 552fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 553fa9e4066Sahrens 55499653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) { 555fa9e4066Sahrens switch (errno) { 556fa9e4066Sahrens case EBUSY: 557fa9e4066Sahrens /* 558fa9e4066Sahrens * This can happen if the user has specified the same 559fa9e4066Sahrens * device multiple times. We can't reliably detect this 560fa9e4066Sahrens * until we try to add it and see we already have a 561fa9e4066Sahrens * label. 562fa9e4066Sahrens */ 56399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 56499653d4eSeschrock "one or more vdevs refer to the same device")); 56599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 566fa9e4066Sahrens break; 567fa9e4066Sahrens 568fa9e4066Sahrens case EOVERFLOW: 569fa9e4066Sahrens /* 570fa9e4066Sahrens * This occurrs when one of the devices is below 571fa9e4066Sahrens * SPA_MINDEVSIZE. Unfortunately, we can't detect which 572fa9e4066Sahrens * device was the problem device since there's no 573fa9e4066Sahrens * reliable way to determine device size from userland. 574fa9e4066Sahrens */ 575fa9e4066Sahrens { 576fa9e4066Sahrens char buf[64]; 577fa9e4066Sahrens 578fa9e4066Sahrens zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf)); 579fa9e4066Sahrens 58099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 58199653d4eSeschrock "device is less than the minimum " 58299653d4eSeschrock "size (%s)"), buf); 583fa9e4066Sahrens } 58499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 58599653d4eSeschrock break; 58699653d4eSeschrock 58799653d4eSeschrock case ENOTSUP: 58899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 58999653d4eSeschrock "pool must be upgraded to add raidz2 vdevs")); 59099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, msg); 591fa9e4066Sahrens break; 592fa9e4066Sahrens 593fa9e4066Sahrens default: 59499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 595fa9e4066Sahrens } 596fa9e4066Sahrens 59799653d4eSeschrock ret = -1; 59899653d4eSeschrock } else { 59999653d4eSeschrock ret = 0; 600fa9e4066Sahrens } 601fa9e4066Sahrens 602e9dbad6fSeschrock zcmd_free_nvlists(&zc); 603fa9e4066Sahrens 60499653d4eSeschrock return (ret); 605fa9e4066Sahrens } 606fa9e4066Sahrens 607fa9e4066Sahrens /* 608fa9e4066Sahrens * Exports the pool from the system. The caller must ensure that there are no 609fa9e4066Sahrens * mounted datasets in the pool. 610fa9e4066Sahrens */ 611fa9e4066Sahrens int 612fa9e4066Sahrens zpool_export(zpool_handle_t *zhp) 613fa9e4066Sahrens { 614fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 615fa9e4066Sahrens 616fa9e4066Sahrens if (zpool_remove_zvol_links(zhp) != 0) 617fa9e4066Sahrens return (-1); 618fa9e4066Sahrens 619fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 620fa9e4066Sahrens 62199653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0) 62299653d4eSeschrock return (zpool_standard_error(zhp->zpool_hdl, errno, 62399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot export '%s'"), 62499653d4eSeschrock zhp->zpool_name)); 625fa9e4066Sahrens 626fa9e4066Sahrens return (0); 627fa9e4066Sahrens } 628fa9e4066Sahrens 629fa9e4066Sahrens /* 630fa9e4066Sahrens * Import the given pool using the known configuration. The configuration 631fa9e4066Sahrens * should have come from zpool_find_import(). The 'newname' and 'altroot' 632fa9e4066Sahrens * parameters control whether the pool is imported with a different name or with 633fa9e4066Sahrens * an alternate root, respectively. 634fa9e4066Sahrens */ 635fa9e4066Sahrens int 63699653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, 63799653d4eSeschrock const char *altroot) 638fa9e4066Sahrens { 639e9dbad6fSeschrock zfs_cmd_t zc = { 0 }; 640fa9e4066Sahrens char *thename; 641fa9e4066Sahrens char *origname; 642fa9e4066Sahrens int ret; 643fa9e4066Sahrens 644fa9e4066Sahrens verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 645fa9e4066Sahrens &origname) == 0); 646fa9e4066Sahrens 647fa9e4066Sahrens if (newname != NULL) { 64899653d4eSeschrock if (!zpool_name_valid(hdl, B_FALSE, newname)) 64999653d4eSeschrock return (zfs_error(hdl, EZFS_INVALIDNAME, 65099653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot import '%s'"), 65199653d4eSeschrock newname)); 652fa9e4066Sahrens thename = (char *)newname; 653fa9e4066Sahrens } else { 654fa9e4066Sahrens thename = origname; 655fa9e4066Sahrens } 656fa9e4066Sahrens 65799653d4eSeschrock if (altroot != NULL && altroot[0] != '/') 65899653d4eSeschrock return (zfs_error(hdl, EZFS_BADPATH, 65999653d4eSeschrock dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), 66099653d4eSeschrock altroot)); 661fa9e4066Sahrens 662fa9e4066Sahrens (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name)); 663fa9e4066Sahrens 664fa9e4066Sahrens if (altroot != NULL) 665e9dbad6fSeschrock (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value)); 666fa9e4066Sahrens else 667e9dbad6fSeschrock zc.zc_value[0] = '\0'; 668fa9e4066Sahrens 669fa9e4066Sahrens verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 670ea8dc4b6Seschrock &zc.zc_guid) == 0); 671fa9e4066Sahrens 672e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0) 67399653d4eSeschrock return (-1); 674fa9e4066Sahrens 675fa9e4066Sahrens ret = 0; 67699653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) { 677fa9e4066Sahrens char desc[1024]; 678fa9e4066Sahrens if (newname == NULL) 679fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 680fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s'"), 681fa9e4066Sahrens thename); 682fa9e4066Sahrens else 683fa9e4066Sahrens (void) snprintf(desc, sizeof (desc), 684fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"), 685fa9e4066Sahrens origname, thename); 686fa9e4066Sahrens 687fa9e4066Sahrens switch (errno) { 688ea8dc4b6Seschrock case ENOTSUP: 689ea8dc4b6Seschrock /* 690ea8dc4b6Seschrock * Unsupported version. 691ea8dc4b6Seschrock */ 69299653d4eSeschrock (void) zfs_error(hdl, EZFS_BADVERSION, desc); 693ea8dc4b6Seschrock break; 694ea8dc4b6Seschrock 695b5989ec7Seschrock case EINVAL: 696b5989ec7Seschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, desc); 697b5989ec7Seschrock break; 698b5989ec7Seschrock 699fa9e4066Sahrens default: 70099653d4eSeschrock (void) zpool_standard_error(hdl, errno, desc); 701fa9e4066Sahrens } 702fa9e4066Sahrens 703fa9e4066Sahrens ret = -1; 704fa9e4066Sahrens } else { 705fa9e4066Sahrens zpool_handle_t *zhp; 706fa9e4066Sahrens /* 707fa9e4066Sahrens * This should never fail, but play it safe anyway. 708fa9e4066Sahrens */ 70994de1d4cSeschrock if (zpool_open_silent(hdl, thename, &zhp) != 0) { 71094de1d4cSeschrock ret = -1; 71194de1d4cSeschrock } else if (zhp != NULL) { 712fa9e4066Sahrens ret = zpool_create_zvol_links(zhp); 713fa9e4066Sahrens zpool_close(zhp); 714fa9e4066Sahrens } 715fa9e4066Sahrens } 716fa9e4066Sahrens 717e9dbad6fSeschrock zcmd_free_nvlists(&zc); 718fa9e4066Sahrens return (ret); 719fa9e4066Sahrens } 720fa9e4066Sahrens 721fa9e4066Sahrens /* 722fa9e4066Sahrens * Scrub the pool. 723fa9e4066Sahrens */ 724fa9e4066Sahrens int 725fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type) 726fa9e4066Sahrens { 727fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 728fa9e4066Sahrens char msg[1024]; 72999653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 730fa9e4066Sahrens 731fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 732fa9e4066Sahrens zc.zc_cookie = type; 733fa9e4066Sahrens 73499653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0) 735fa9e4066Sahrens return (0); 736fa9e4066Sahrens 737fa9e4066Sahrens (void) snprintf(msg, sizeof (msg), 738fa9e4066Sahrens dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); 739fa9e4066Sahrens 74099653d4eSeschrock if (errno == EBUSY) 74199653d4eSeschrock return (zfs_error(hdl, EZFS_RESILVERING, msg)); 74299653d4eSeschrock else 74399653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 744fa9e4066Sahrens } 745fa9e4066Sahrens 746a43d325bSek /* 747a43d325bSek * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL 748a43d325bSek * spare; but FALSE if its an INUSE spare. 749a43d325bSek */ 75099653d4eSeschrock static nvlist_t * 75199653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid, 752a43d325bSek boolean_t *avail_spare) 753ea8dc4b6Seschrock { 754ea8dc4b6Seschrock uint_t c, children; 755ea8dc4b6Seschrock nvlist_t **child; 75699653d4eSeschrock uint64_t theguid, present; 757ea8dc4b6Seschrock char *path; 758ea8dc4b6Seschrock uint64_t wholedisk = 0; 75999653d4eSeschrock nvlist_t *ret; 760ea8dc4b6Seschrock 76199653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0); 762ea8dc4b6Seschrock 763ea8dc4b6Seschrock if (search == NULL && 764ea8dc4b6Seschrock nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) { 765ea8dc4b6Seschrock /* 766ea8dc4b6Seschrock * If the device has never been present since import, the only 767ea8dc4b6Seschrock * reliable way to match the vdev is by GUID. 768ea8dc4b6Seschrock */ 76999653d4eSeschrock if (theguid == guid) 77099653d4eSeschrock return (nv); 771ea8dc4b6Seschrock } else if (search != NULL && 772ea8dc4b6Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 773ea8dc4b6Seschrock (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 774ea8dc4b6Seschrock &wholedisk); 775ea8dc4b6Seschrock if (wholedisk) { 776ea8dc4b6Seschrock /* 777ea8dc4b6Seschrock * For whole disks, the internal path has 's0', but the 778ea8dc4b6Seschrock * path passed in by the user doesn't. 779ea8dc4b6Seschrock */ 780ea8dc4b6Seschrock if (strlen(search) == strlen(path) - 2 && 781ea8dc4b6Seschrock strncmp(search, path, strlen(search)) == 0) 78299653d4eSeschrock return (nv); 783ea8dc4b6Seschrock } else if (strcmp(search, path) == 0) { 78499653d4eSeschrock return (nv); 785ea8dc4b6Seschrock } 786ea8dc4b6Seschrock } 787ea8dc4b6Seschrock 788ea8dc4b6Seschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 789ea8dc4b6Seschrock &child, &children) != 0) 79099653d4eSeschrock return (NULL); 791ea8dc4b6Seschrock 792ea8dc4b6Seschrock for (c = 0; c < children; c++) 79399653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 794a43d325bSek avail_spare)) != NULL) 795ea8dc4b6Seschrock return (ret); 796ea8dc4b6Seschrock 79799653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 79899653d4eSeschrock &child, &children) == 0) { 79999653d4eSeschrock for (c = 0; c < children; c++) { 80099653d4eSeschrock if ((ret = vdev_to_nvlist_iter(child[c], search, guid, 801a43d325bSek avail_spare)) != NULL) { 802a43d325bSek *avail_spare = B_TRUE; 80399653d4eSeschrock return (ret); 80499653d4eSeschrock } 80599653d4eSeschrock } 80699653d4eSeschrock } 80799653d4eSeschrock 80899653d4eSeschrock return (NULL); 809ea8dc4b6Seschrock } 810ea8dc4b6Seschrock 81199653d4eSeschrock nvlist_t * 812a43d325bSek zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare) 813ea8dc4b6Seschrock { 814ea8dc4b6Seschrock char buf[MAXPATHLEN]; 815ea8dc4b6Seschrock const char *search; 816ea8dc4b6Seschrock char *end; 817ea8dc4b6Seschrock nvlist_t *nvroot; 818ea8dc4b6Seschrock uint64_t guid; 819ea8dc4b6Seschrock 8200917b783Seschrock guid = strtoull(path, &end, 10); 821ea8dc4b6Seschrock if (guid != 0 && *end == '\0') { 822ea8dc4b6Seschrock search = NULL; 823ea8dc4b6Seschrock } else if (path[0] != '/') { 824ea8dc4b6Seschrock (void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path); 825ea8dc4b6Seschrock search = buf; 826ea8dc4b6Seschrock } else { 827ea8dc4b6Seschrock search = path; 828ea8dc4b6Seschrock } 829ea8dc4b6Seschrock 830ea8dc4b6Seschrock verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 831ea8dc4b6Seschrock &nvroot) == 0); 832ea8dc4b6Seschrock 833a43d325bSek *avail_spare = B_FALSE; 834a43d325bSek return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare)); 835a43d325bSek } 836a43d325bSek 837a43d325bSek /* 838a43d325bSek * Returns TRUE if the given guid corresponds to a spare (INUSE or not). 839a43d325bSek */ 840a43d325bSek static boolean_t 841a43d325bSek is_spare(zpool_handle_t *zhp, uint64_t guid) 842a43d325bSek { 843a43d325bSek uint64_t spare_guid; 844a43d325bSek nvlist_t *nvroot; 845a43d325bSek nvlist_t **spares; 846a43d325bSek uint_t nspares; 847a43d325bSek int i; 848a43d325bSek 849a43d325bSek verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, 850a43d325bSek &nvroot) == 0); 851a43d325bSek if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 852a43d325bSek &spares, &nspares) == 0) { 853a43d325bSek for (i = 0; i < nspares; i++) { 854a43d325bSek verify(nvlist_lookup_uint64(spares[i], 855a43d325bSek ZPOOL_CONFIG_GUID, &spare_guid) == 0); 856a43d325bSek if (guid == spare_guid) 857a43d325bSek return (B_TRUE); 858a43d325bSek } 859a43d325bSek } 860a43d325bSek 861a43d325bSek return (B_FALSE); 862ea8dc4b6Seschrock } 863ea8dc4b6Seschrock 864fa9e4066Sahrens /* 865fa9e4066Sahrens * Bring the specified vdev online 866fa9e4066Sahrens */ 867fa9e4066Sahrens int 868fa9e4066Sahrens zpool_vdev_online(zpool_handle_t *zhp, const char *path) 869fa9e4066Sahrens { 870fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 871fa9e4066Sahrens char msg[1024]; 87299653d4eSeschrock nvlist_t *tgt; 873a43d325bSek boolean_t avail_spare; 87499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 875fa9e4066Sahrens 876ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 877ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot online %s"), path); 878ea8dc4b6Seschrock 879fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 880a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 88199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 882fa9e4066Sahrens 88399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 884fa9e4066Sahrens 885a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 886a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 887a43d325bSek 88899653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0) 88999653d4eSeschrock return (0); 890fa9e4066Sahrens 89199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 892fa9e4066Sahrens } 893fa9e4066Sahrens 894fa9e4066Sahrens /* 895fa9e4066Sahrens * Take the specified vdev offline 896fa9e4066Sahrens */ 897fa9e4066Sahrens int 898441d80aaSlling zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp) 899fa9e4066Sahrens { 900fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 901fa9e4066Sahrens char msg[1024]; 90299653d4eSeschrock nvlist_t *tgt; 903a43d325bSek boolean_t avail_spare; 90499653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 905fa9e4066Sahrens 906ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 907ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot offline %s"), path); 908ea8dc4b6Seschrock 909fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 910a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL) 91199653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 91299653d4eSeschrock 91399653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 914fa9e4066Sahrens 915a43d325bSek if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE) 916a43d325bSek return (zfs_error(hdl, EZFS_ISSPARE, msg)); 917a43d325bSek 918441d80aaSlling zc.zc_cookie = istmp; 919441d80aaSlling 92099653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0) 921fa9e4066Sahrens return (0); 922fa9e4066Sahrens 923fa9e4066Sahrens switch (errno) { 92499653d4eSeschrock case EBUSY: 925fa9e4066Sahrens 926fa9e4066Sahrens /* 927fa9e4066Sahrens * There are no other replicas of this device. 928fa9e4066Sahrens */ 92999653d4eSeschrock return (zfs_error(hdl, EZFS_NOREPLICAS, msg)); 930fa9e4066Sahrens 93199653d4eSeschrock default: 93299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 933fa9e4066Sahrens } 93499653d4eSeschrock } 93599653d4eSeschrock 93699653d4eSeschrock /* 93799653d4eSeschrock * Returns TRUE if the given nvlist is a vdev that was originally swapped in as 93899653d4eSeschrock * a hot spare. 93999653d4eSeschrock */ 94099653d4eSeschrock static boolean_t 94199653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which) 94299653d4eSeschrock { 94399653d4eSeschrock nvlist_t **child; 94499653d4eSeschrock uint_t c, children; 94599653d4eSeschrock char *type; 94699653d4eSeschrock 94799653d4eSeschrock if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child, 94899653d4eSeschrock &children) == 0) { 94999653d4eSeschrock verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE, 95099653d4eSeschrock &type) == 0); 95199653d4eSeschrock 95299653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0 && 95399653d4eSeschrock children == 2 && child[which] == tgt) 95499653d4eSeschrock return (B_TRUE); 95599653d4eSeschrock 95699653d4eSeschrock for (c = 0; c < children; c++) 95799653d4eSeschrock if (is_replacing_spare(child[c], tgt, which)) 95899653d4eSeschrock return (B_TRUE); 95999653d4eSeschrock } 96099653d4eSeschrock 96199653d4eSeschrock return (B_FALSE); 962fa9e4066Sahrens } 963fa9e4066Sahrens 964fa9e4066Sahrens /* 965fa9e4066Sahrens * Attach new_disk (fully described by nvroot) to old_disk. 966fa9e4066Sahrens * If 'replacing' is specified, tne new disk will replace the old one. 967fa9e4066Sahrens */ 968fa9e4066Sahrens int 969fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp, 970fa9e4066Sahrens const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing) 971fa9e4066Sahrens { 972fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 973fa9e4066Sahrens char msg[1024]; 974fa9e4066Sahrens int ret; 97599653d4eSeschrock nvlist_t *tgt; 976a43d325bSek boolean_t avail_spare; 97799653d4eSeschrock uint64_t val; 97899653d4eSeschrock char *path; 97999653d4eSeschrock nvlist_t **child; 98099653d4eSeschrock uint_t children; 98199653d4eSeschrock nvlist_t *config_root; 98299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 983fa9e4066Sahrens 984ea8dc4b6Seschrock if (replacing) 985ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 986ea8dc4b6Seschrock "cannot replace %s with %s"), old_disk, new_disk); 987ea8dc4b6Seschrock else 988ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, 989ea8dc4b6Seschrock "cannot attach %s to %s"), new_disk, old_disk); 990ea8dc4b6Seschrock 991fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 992a43d325bSek if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0) 99399653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 99499653d4eSeschrock 995a43d325bSek if (avail_spare) 99699653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 99799653d4eSeschrock 99899653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 999fa9e4066Sahrens zc.zc_cookie = replacing; 1000fa9e4066Sahrens 100199653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 100299653d4eSeschrock &child, &children) != 0 || children != 1) { 100399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 100499653d4eSeschrock "new device must be a single disk")); 100599653d4eSeschrock return (zfs_error(hdl, EZFS_INVALCONFIG, msg)); 100699653d4eSeschrock } 100799653d4eSeschrock 100899653d4eSeschrock verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), 100999653d4eSeschrock ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0); 101099653d4eSeschrock 101199653d4eSeschrock /* 101299653d4eSeschrock * If the target is a hot spare that has been swapped in, we can only 101399653d4eSeschrock * replace it with another hot spare. 101499653d4eSeschrock */ 101599653d4eSeschrock if (replacing && 101699653d4eSeschrock nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 && 101799653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1018a43d325bSek (zpool_find_vdev(zhp, path, &avail_spare) == NULL || 1019a43d325bSek !avail_spare) && is_replacing_spare(config_root, tgt, 1)) { 102099653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 102199653d4eSeschrock "can only be replaced by another hot spare")); 102299653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 102399653d4eSeschrock } 102499653d4eSeschrock 102599653d4eSeschrock /* 102699653d4eSeschrock * If we are attempting to replace a spare, it canot be applied to an 102799653d4eSeschrock * already spared device. 102899653d4eSeschrock */ 102999653d4eSeschrock if (replacing && 103099653d4eSeschrock nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 && 1031a43d325bSek zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare && 103299653d4eSeschrock is_replacing_spare(config_root, tgt, 0)) { 103399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 103499653d4eSeschrock "device has already been replaced with a spare")); 103599653d4eSeschrock return (zfs_error(hdl, EZFS_BADTARGET, msg)); 103699653d4eSeschrock } 103799653d4eSeschrock 1038e9dbad6fSeschrock if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0) 103999653d4eSeschrock return (-1); 1040fa9e4066Sahrens 104199653d4eSeschrock ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc); 1042fa9e4066Sahrens 1043e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1044fa9e4066Sahrens 1045fa9e4066Sahrens if (ret == 0) 1046fa9e4066Sahrens return (0); 1047fa9e4066Sahrens 1048fa9e4066Sahrens switch (errno) { 1049ea8dc4b6Seschrock case ENOTSUP: 1050fa9e4066Sahrens /* 1051fa9e4066Sahrens * Can't attach to or replace this type of vdev. 1052fa9e4066Sahrens */ 1053fa9e4066Sahrens if (replacing) 105499653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 105599653d4eSeschrock "cannot replace a replacing device")); 1056fa9e4066Sahrens else 105799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 105899653d4eSeschrock "can only attach to mirrors and top-level " 105999653d4eSeschrock "disks")); 106099653d4eSeschrock (void) zfs_error(hdl, EZFS_BADTARGET, msg); 1061fa9e4066Sahrens break; 1062fa9e4066Sahrens 1063ea8dc4b6Seschrock case EINVAL: 1064fa9e4066Sahrens /* 1065fa9e4066Sahrens * The new device must be a single disk. 1066fa9e4066Sahrens */ 106799653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 106899653d4eSeschrock "new device must be a single disk")); 106999653d4eSeschrock (void) zfs_error(hdl, EZFS_INVALCONFIG, msg); 1070fa9e4066Sahrens break; 1071fa9e4066Sahrens 1072ea8dc4b6Seschrock case EBUSY: 107399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"), 107499653d4eSeschrock new_disk); 107599653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1076fa9e4066Sahrens break; 1077fa9e4066Sahrens 1078ea8dc4b6Seschrock case EOVERFLOW: 1079fa9e4066Sahrens /* 1080fa9e4066Sahrens * The new device is too small. 1081fa9e4066Sahrens */ 108299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 108399653d4eSeschrock "device is too small")); 108499653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1085fa9e4066Sahrens break; 1086fa9e4066Sahrens 1087ea8dc4b6Seschrock case EDOM: 1088fa9e4066Sahrens /* 1089fa9e4066Sahrens * The new device has a different alignment requirement. 1090fa9e4066Sahrens */ 109199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 109299653d4eSeschrock "devices have different sector alignment")); 109399653d4eSeschrock (void) zfs_error(hdl, EZFS_BADDEV, msg); 1094fa9e4066Sahrens break; 1095fa9e4066Sahrens 1096ea8dc4b6Seschrock case ENAMETOOLONG: 1097fa9e4066Sahrens /* 1098fa9e4066Sahrens * The resulting top-level vdev spec won't fit in the label. 1099fa9e4066Sahrens */ 110099653d4eSeschrock (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg); 1101fa9e4066Sahrens break; 1102fa9e4066Sahrens 1103ea8dc4b6Seschrock default: 110499653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1105fa9e4066Sahrens } 1106fa9e4066Sahrens 110799653d4eSeschrock return (-1); 1108fa9e4066Sahrens } 1109fa9e4066Sahrens 1110fa9e4066Sahrens /* 1111fa9e4066Sahrens * Detach the specified device. 1112fa9e4066Sahrens */ 1113fa9e4066Sahrens int 1114fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path) 1115fa9e4066Sahrens { 1116fa9e4066Sahrens zfs_cmd_t zc = { 0 }; 1117fa9e4066Sahrens char msg[1024]; 111899653d4eSeschrock nvlist_t *tgt; 1119a43d325bSek boolean_t avail_spare; 112099653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1121fa9e4066Sahrens 1122ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1123ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot detach %s"), path); 1124ea8dc4b6Seschrock 1125fa9e4066Sahrens (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1126a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 112799653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1128fa9e4066Sahrens 1129a43d325bSek if (avail_spare) 113099653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 113199653d4eSeschrock 113299653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 113399653d4eSeschrock 113499653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0) 1135fa9e4066Sahrens return (0); 1136fa9e4066Sahrens 1137fa9e4066Sahrens switch (errno) { 1138fa9e4066Sahrens 1139ea8dc4b6Seschrock case ENOTSUP: 1140fa9e4066Sahrens /* 1141fa9e4066Sahrens * Can't detach from this type of vdev. 1142fa9e4066Sahrens */ 114399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only " 114499653d4eSeschrock "applicable to mirror and replacing vdevs")); 114599653d4eSeschrock (void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg); 1146fa9e4066Sahrens break; 1147fa9e4066Sahrens 1148ea8dc4b6Seschrock case EBUSY: 1149fa9e4066Sahrens /* 1150fa9e4066Sahrens * There are no other replicas of this device. 1151fa9e4066Sahrens */ 115299653d4eSeschrock (void) zfs_error(hdl, EZFS_NOREPLICAS, msg); 1153fa9e4066Sahrens break; 1154fa9e4066Sahrens 1155ea8dc4b6Seschrock default: 115699653d4eSeschrock (void) zpool_standard_error(hdl, errno, msg); 1157ea8dc4b6Seschrock } 1158ea8dc4b6Seschrock 115999653d4eSeschrock return (-1); 116099653d4eSeschrock } 116199653d4eSeschrock 116299653d4eSeschrock /* 116399653d4eSeschrock * Remove the given device. Currently, this is supported only for hot spares. 116499653d4eSeschrock */ 116599653d4eSeschrock int 116699653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path) 116799653d4eSeschrock { 116899653d4eSeschrock zfs_cmd_t zc = { 0 }; 116999653d4eSeschrock char msg[1024]; 117099653d4eSeschrock nvlist_t *tgt; 1171a43d325bSek boolean_t avail_spare; 117299653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 117399653d4eSeschrock 117499653d4eSeschrock (void) snprintf(msg, sizeof (msg), 117599653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot remove %s"), path); 117699653d4eSeschrock 117799653d4eSeschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1178a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 117999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 118099653d4eSeschrock 1181a43d325bSek if (!avail_spare) { 118299653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 118399653d4eSeschrock "only hot spares can be removed")); 118499653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 118599653d4eSeschrock } 118699653d4eSeschrock 118799653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0); 118899653d4eSeschrock 118999653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0) 119099653d4eSeschrock return (0); 119199653d4eSeschrock 119299653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1193ea8dc4b6Seschrock } 1194ea8dc4b6Seschrock 1195ea8dc4b6Seschrock /* 1196ea8dc4b6Seschrock * Clear the errors for the pool, or the particular device if specified. 1197ea8dc4b6Seschrock */ 1198ea8dc4b6Seschrock int 1199ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path) 1200ea8dc4b6Seschrock { 1201ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1202ea8dc4b6Seschrock char msg[1024]; 120399653d4eSeschrock nvlist_t *tgt; 1204a43d325bSek boolean_t avail_spare; 120599653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1206ea8dc4b6Seschrock 1207ea8dc4b6Seschrock if (path) 1208ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1209ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1210e9dbad6fSeschrock path); 1211ea8dc4b6Seschrock else 1212ea8dc4b6Seschrock (void) snprintf(msg, sizeof (msg), 1213ea8dc4b6Seschrock dgettext(TEXT_DOMAIN, "cannot clear errors for %s"), 1214ea8dc4b6Seschrock zhp->zpool_name); 1215ea8dc4b6Seschrock 1216ea8dc4b6Seschrock (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 121799653d4eSeschrock if (path) { 1218a43d325bSek if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0) 121999653d4eSeschrock return (zfs_error(hdl, EZFS_NODEVICE, msg)); 1220ea8dc4b6Seschrock 1221a43d325bSek if (avail_spare) 122299653d4eSeschrock return (zfs_error(hdl, EZFS_ISSPARE, msg)); 1223ea8dc4b6Seschrock 122499653d4eSeschrock verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, 122599653d4eSeschrock &zc.zc_guid) == 0); 1226fa9e4066Sahrens } 1227fa9e4066Sahrens 122899653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0) 122999653d4eSeschrock return (0); 123099653d4eSeschrock 123199653d4eSeschrock return (zpool_standard_error(hdl, errno, msg)); 1232fa9e4066Sahrens } 1233fa9e4066Sahrens 1234fa9e4066Sahrens static int 1235fa9e4066Sahrens do_zvol(zfs_handle_t *zhp, void *data) 1236fa9e4066Sahrens { 1237fa9e4066Sahrens int linktype = (int)(uintptr_t)data; 1238fa9e4066Sahrens int ret; 1239fa9e4066Sahrens 1240fa9e4066Sahrens /* 1241fa9e4066Sahrens * We check for volblocksize intead of ZFS_TYPE_VOLUME so that we 1242fa9e4066Sahrens * correctly handle snapshots of volumes. 1243fa9e4066Sahrens */ 1244e9dbad6fSeschrock if (ZFS_IS_VOLUME(zhp)) { 1245fa9e4066Sahrens if (linktype) 124699653d4eSeschrock ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 1247fa9e4066Sahrens else 124899653d4eSeschrock ret = zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); 1249fa9e4066Sahrens } 1250fa9e4066Sahrens 1251fa9e4066Sahrens ret = zfs_iter_children(zhp, do_zvol, data); 1252fa9e4066Sahrens 1253fa9e4066Sahrens zfs_close(zhp); 1254fa9e4066Sahrens return (ret); 1255fa9e4066Sahrens } 1256fa9e4066Sahrens 1257fa9e4066Sahrens /* 1258fa9e4066Sahrens * Iterate over all zvols in the pool and make any necessary minor nodes. 1259fa9e4066Sahrens */ 1260fa9e4066Sahrens int 1261fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp) 1262fa9e4066Sahrens { 1263fa9e4066Sahrens zfs_handle_t *zfp; 1264fa9e4066Sahrens int ret; 1265fa9e4066Sahrens 1266fa9e4066Sahrens /* 1267fa9e4066Sahrens * If the pool is unavailable, just return success. 1268fa9e4066Sahrens */ 126999653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 127099653d4eSeschrock zhp->zpool_name)) == NULL) 1271fa9e4066Sahrens return (0); 1272fa9e4066Sahrens 127399653d4eSeschrock ret = zfs_iter_children(zfp, do_zvol, (void *)B_TRUE); 1274fa9e4066Sahrens 1275fa9e4066Sahrens zfs_close(zfp); 1276fa9e4066Sahrens return (ret); 1277fa9e4066Sahrens } 1278fa9e4066Sahrens 1279fa9e4066Sahrens /* 1280fa9e4066Sahrens * Iterate over all zvols in the poool and remove any minor nodes. 1281fa9e4066Sahrens */ 1282fa9e4066Sahrens int 1283fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp) 1284fa9e4066Sahrens { 1285fa9e4066Sahrens zfs_handle_t *zfp; 1286fa9e4066Sahrens int ret; 1287fa9e4066Sahrens 1288fa9e4066Sahrens /* 1289fa9e4066Sahrens * If the pool is unavailable, just return success. 1290fa9e4066Sahrens */ 129199653d4eSeschrock if ((zfp = make_dataset_handle(zhp->zpool_hdl, 129299653d4eSeschrock zhp->zpool_name)) == NULL) 1293fa9e4066Sahrens return (0); 1294fa9e4066Sahrens 129599653d4eSeschrock ret = zfs_iter_children(zfp, do_zvol, (void *)B_FALSE); 1296fa9e4066Sahrens 1297fa9e4066Sahrens zfs_close(zfp); 1298fa9e4066Sahrens return (ret); 1299fa9e4066Sahrens } 1300c67d9675Seschrock 1301c67d9675Seschrock /* 1302c67d9675Seschrock * Convert from a devid string to a path. 1303c67d9675Seschrock */ 1304c67d9675Seschrock static char * 1305c67d9675Seschrock devid_to_path(char *devid_str) 1306c67d9675Seschrock { 1307c67d9675Seschrock ddi_devid_t devid; 1308c67d9675Seschrock char *minor; 1309c67d9675Seschrock char *path; 1310c67d9675Seschrock devid_nmlist_t *list = NULL; 1311c67d9675Seschrock int ret; 1312c67d9675Seschrock 1313c67d9675Seschrock if (devid_str_decode(devid_str, &devid, &minor) != 0) 1314c67d9675Seschrock return (NULL); 1315c67d9675Seschrock 1316c67d9675Seschrock ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list); 1317c67d9675Seschrock 1318c67d9675Seschrock devid_str_free(minor); 1319c67d9675Seschrock devid_free(devid); 1320c67d9675Seschrock 1321c67d9675Seschrock if (ret != 0) 1322c67d9675Seschrock return (NULL); 1323c67d9675Seschrock 132499653d4eSeschrock if ((path = strdup(list[0].devname)) == NULL) 132599653d4eSeschrock return (NULL); 132699653d4eSeschrock 1327c67d9675Seschrock devid_free_nmlist(list); 1328c67d9675Seschrock 1329c67d9675Seschrock return (path); 1330c67d9675Seschrock } 1331c67d9675Seschrock 1332c67d9675Seschrock /* 1333c67d9675Seschrock * Convert from a path to a devid string. 1334c67d9675Seschrock */ 1335c67d9675Seschrock static char * 1336c67d9675Seschrock path_to_devid(const char *path) 1337c67d9675Seschrock { 1338c67d9675Seschrock int fd; 1339c67d9675Seschrock ddi_devid_t devid; 1340c67d9675Seschrock char *minor, *ret; 1341c67d9675Seschrock 1342c67d9675Seschrock if ((fd = open(path, O_RDONLY)) < 0) 1343c67d9675Seschrock return (NULL); 1344c67d9675Seschrock 1345c67d9675Seschrock minor = NULL; 1346c67d9675Seschrock ret = NULL; 1347c67d9675Seschrock if (devid_get(fd, &devid) == 0) { 1348c67d9675Seschrock if (devid_get_minor_name(fd, &minor) == 0) 1349c67d9675Seschrock ret = devid_str_encode(devid, minor); 1350c67d9675Seschrock if (minor != NULL) 1351c67d9675Seschrock devid_str_free(minor); 1352c67d9675Seschrock devid_free(devid); 1353c67d9675Seschrock } 1354c67d9675Seschrock (void) close(fd); 1355c67d9675Seschrock 1356c67d9675Seschrock return (ret); 1357c67d9675Seschrock } 1358c67d9675Seschrock 1359c67d9675Seschrock /* 1360c67d9675Seschrock * Issue the necessary ioctl() to update the stored path value for the vdev. We 1361c67d9675Seschrock * ignore any failure here, since a common case is for an unprivileged user to 1362c67d9675Seschrock * type 'zpool status', and we'll display the correct information anyway. 1363c67d9675Seschrock */ 1364c67d9675Seschrock static void 1365c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) 1366c67d9675Seschrock { 1367c67d9675Seschrock zfs_cmd_t zc = { 0 }; 1368c67d9675Seschrock 1369c67d9675Seschrock (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1370e9dbad6fSeschrock (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value)); 1371c67d9675Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1372ea8dc4b6Seschrock &zc.zc_guid) == 0); 1373c67d9675Seschrock 137499653d4eSeschrock (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc); 1375c67d9675Seschrock } 1376c67d9675Seschrock 1377c67d9675Seschrock /* 1378c67d9675Seschrock * Given a vdev, return the name to display in iostat. If the vdev has a path, 1379c67d9675Seschrock * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type. 1380c67d9675Seschrock * We also check if this is a whole disk, in which case we strip off the 1381c67d9675Seschrock * trailing 's0' slice name. 1382c67d9675Seschrock * 1383c67d9675Seschrock * This routine is also responsible for identifying when disks have been 1384c67d9675Seschrock * reconfigured in a new location. The kernel will have opened the device by 1385c67d9675Seschrock * devid, but the path will still refer to the old location. To catch this, we 1386c67d9675Seschrock * first do a path -> devid translation (which is fast for the common case). If 1387c67d9675Seschrock * the devid matches, we're done. If not, we do a reverse devid -> path 1388c67d9675Seschrock * translation and issue the appropriate ioctl() to update the path of the vdev. 1389c67d9675Seschrock * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any 1390c67d9675Seschrock * of these checks. 1391c67d9675Seschrock */ 1392c67d9675Seschrock char * 139399653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) 1394c67d9675Seschrock { 1395c67d9675Seschrock char *path, *devid; 1396ea8dc4b6Seschrock uint64_t value; 1397ea8dc4b6Seschrock char buf[64]; 1398c67d9675Seschrock 1399ea8dc4b6Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1400ea8dc4b6Seschrock &value) == 0) { 1401ea8dc4b6Seschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1402ea8dc4b6Seschrock &value) == 0); 14035ad82045Snd (void) snprintf(buf, sizeof (buf), "%llu", 14045ad82045Snd (u_longlong_t)value); 1405ea8dc4b6Seschrock path = buf; 1406ea8dc4b6Seschrock } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { 1407c67d9675Seschrock 1408c67d9675Seschrock if (zhp != NULL && 1409c67d9675Seschrock nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { 1410c67d9675Seschrock /* 1411c67d9675Seschrock * Determine if the current path is correct. 1412c67d9675Seschrock */ 1413c67d9675Seschrock char *newdevid = path_to_devid(path); 1414c67d9675Seschrock 1415c67d9675Seschrock if (newdevid == NULL || 1416c67d9675Seschrock strcmp(devid, newdevid) != 0) { 1417c67d9675Seschrock char *newpath; 1418c67d9675Seschrock 1419c67d9675Seschrock if ((newpath = devid_to_path(devid)) != NULL) { 1420c67d9675Seschrock /* 1421c67d9675Seschrock * Update the path appropriately. 1422c67d9675Seschrock */ 1423c67d9675Seschrock set_path(zhp, nv, newpath); 142499653d4eSeschrock if (nvlist_add_string(nv, 142599653d4eSeschrock ZPOOL_CONFIG_PATH, newpath) == 0) 142699653d4eSeschrock verify(nvlist_lookup_string(nv, 142799653d4eSeschrock ZPOOL_CONFIG_PATH, 142899653d4eSeschrock &path) == 0); 1429c67d9675Seschrock free(newpath); 1430c67d9675Seschrock } 1431c67d9675Seschrock } 1432c67d9675Seschrock 143399653d4eSeschrock if (newdevid) 143499653d4eSeschrock devid_str_free(newdevid); 1435c67d9675Seschrock } 1436c67d9675Seschrock 1437c67d9675Seschrock if (strncmp(path, "/dev/dsk/", 9) == 0) 1438c67d9675Seschrock path += 9; 1439c67d9675Seschrock 1440c67d9675Seschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1441ea8dc4b6Seschrock &value) == 0 && value) { 144299653d4eSeschrock char *tmp = zfs_strdup(hdl, path); 144399653d4eSeschrock if (tmp == NULL) 144499653d4eSeschrock return (NULL); 1445c67d9675Seschrock tmp[strlen(path) - 2] = '\0'; 1446c67d9675Seschrock return (tmp); 1447c67d9675Seschrock } 1448c67d9675Seschrock } else { 1449c67d9675Seschrock verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0); 145099653d4eSeschrock 145199653d4eSeschrock /* 145299653d4eSeschrock * If it's a raidz device, we need to stick in the parity level. 145399653d4eSeschrock */ 145499653d4eSeschrock if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) { 145599653d4eSeschrock verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY, 145699653d4eSeschrock &value) == 0); 145799653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%s%llu", path, 14585ad82045Snd (u_longlong_t)value); 145999653d4eSeschrock path = buf; 146099653d4eSeschrock } 1461c67d9675Seschrock } 1462c67d9675Seschrock 146399653d4eSeschrock return (zfs_strdup(hdl, path)); 1464c67d9675Seschrock } 1465ea8dc4b6Seschrock 1466ea8dc4b6Seschrock static int 1467ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b) 1468ea8dc4b6Seschrock { 1469ea8dc4b6Seschrock return (memcmp(a, b, sizeof (zbookmark_t))); 1470ea8dc4b6Seschrock } 1471ea8dc4b6Seschrock 1472ea8dc4b6Seschrock /* 1473ea8dc4b6Seschrock * Retrieve the persistent error log, uniquify the members, and return to the 1474ea8dc4b6Seschrock * caller. 1475ea8dc4b6Seschrock */ 1476ea8dc4b6Seschrock int 1477ea8dc4b6Seschrock zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem) 1478ea8dc4b6Seschrock { 1479ea8dc4b6Seschrock zfs_cmd_t zc = { 0 }; 1480ea8dc4b6Seschrock uint64_t count; 1481e9dbad6fSeschrock zbookmark_t *zb = NULL; 1482e9dbad6fSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1483ea8dc4b6Seschrock int i, j; 1484ea8dc4b6Seschrock 1485ea8dc4b6Seschrock if (zhp->zpool_error_log != NULL) { 1486ea8dc4b6Seschrock *list = zhp->zpool_error_log; 1487ea8dc4b6Seschrock *nelem = zhp->zpool_error_count; 1488ea8dc4b6Seschrock return (0); 1489ea8dc4b6Seschrock } 1490ea8dc4b6Seschrock 1491ea8dc4b6Seschrock /* 1492ea8dc4b6Seschrock * Retrieve the raw error list from the kernel. If the number of errors 1493ea8dc4b6Seschrock * has increased, allocate more space and continue until we get the 1494ea8dc4b6Seschrock * entire list. 1495ea8dc4b6Seschrock */ 1496ea8dc4b6Seschrock verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT, 1497ea8dc4b6Seschrock &count) == 0); 1498e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl, 14995ad82045Snd count * sizeof (zbookmark_t))) == (uintptr_t)NULL) 150099653d4eSeschrock return (-1); 1501e9dbad6fSeschrock zc.zc_nvlist_dst_size = count; 1502ea8dc4b6Seschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 1503ea8dc4b6Seschrock for (;;) { 150499653d4eSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG, 150599653d4eSeschrock &zc) != 0) { 1506e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 1507ea8dc4b6Seschrock if (errno == ENOMEM) { 1508e9dbad6fSeschrock if ((zc.zc_nvlist_dst = (uintptr_t) 150999653d4eSeschrock zfs_alloc(zhp->zpool_hdl, 15105ad82045Snd zc.zc_nvlist_dst_size)) == (uintptr_t)NULL) 151199653d4eSeschrock return (-1); 1512ea8dc4b6Seschrock } else { 1513ea8dc4b6Seschrock return (-1); 1514ea8dc4b6Seschrock } 1515ea8dc4b6Seschrock } else { 1516ea8dc4b6Seschrock break; 1517ea8dc4b6Seschrock } 1518ea8dc4b6Seschrock } 1519ea8dc4b6Seschrock 1520ea8dc4b6Seschrock /* 1521ea8dc4b6Seschrock * Sort the resulting bookmarks. This is a little confusing due to the 1522ea8dc4b6Seschrock * implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last 1523e9dbad6fSeschrock * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks 1524ea8dc4b6Seschrock * _not_ copied as part of the process. So we point the start of our 1525ea8dc4b6Seschrock * array appropriate and decrement the total number of elements. 1526ea8dc4b6Seschrock */ 1527e9dbad6fSeschrock zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) + 1528e9dbad6fSeschrock zc.zc_nvlist_dst_size; 1529e9dbad6fSeschrock count -= zc.zc_nvlist_dst_size; 1530e9dbad6fSeschrock zc.zc_nvlist_dst = 0ULL; 1531ea8dc4b6Seschrock 1532ea8dc4b6Seschrock qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare); 1533ea8dc4b6Seschrock 1534ea8dc4b6Seschrock /* 1535ea8dc4b6Seschrock * Count the number of unique elements 1536ea8dc4b6Seschrock */ 1537ea8dc4b6Seschrock j = 0; 1538ea8dc4b6Seschrock for (i = 0; i < count; i++) { 1539ea8dc4b6Seschrock if (i > 0 && memcmp(&zb[i - 1], &zb[i], 1540ea8dc4b6Seschrock sizeof (zbookmark_t)) == 0) 1541ea8dc4b6Seschrock continue; 1542ea8dc4b6Seschrock j++; 1543ea8dc4b6Seschrock } 1544ea8dc4b6Seschrock 1545ea8dc4b6Seschrock /* 1546ea8dc4b6Seschrock * If the user has only requested the number of items, return it now 1547ea8dc4b6Seschrock * without bothering with the extra work. 1548ea8dc4b6Seschrock */ 1549ea8dc4b6Seschrock if (list == NULL) { 1550ea8dc4b6Seschrock *nelem = j; 1551e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 1552ea8dc4b6Seschrock return (0); 1553ea8dc4b6Seschrock } 1554ea8dc4b6Seschrock 1555ea8dc4b6Seschrock zhp->zpool_error_count = j; 1556ea8dc4b6Seschrock 1557ea8dc4b6Seschrock /* 1558ea8dc4b6Seschrock * Allocate an array of nvlists to hold the results 1559ea8dc4b6Seschrock */ 156099653d4eSeschrock if ((zhp->zpool_error_log = zfs_alloc(zhp->zpool_hdl, 156199653d4eSeschrock j * sizeof (nvlist_t *))) == NULL) { 1562e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 156399653d4eSeschrock return (-1); 156499653d4eSeschrock } 1565ea8dc4b6Seschrock 1566ea8dc4b6Seschrock /* 1567ea8dc4b6Seschrock * Fill in the results with names from the kernel. 1568ea8dc4b6Seschrock */ 1569ea8dc4b6Seschrock j = 0; 1570ea8dc4b6Seschrock for (i = 0; i < count; i++) { 1571ea8dc4b6Seschrock char buf[64]; 1572ea8dc4b6Seschrock nvlist_t *nv; 1573ea8dc4b6Seschrock 1574ea8dc4b6Seschrock if (i > 0 && memcmp(&zb[i - 1], &zb[i], 1575ea8dc4b6Seschrock sizeof (zbookmark_t)) == 0) 1576ea8dc4b6Seschrock continue; 1577ea8dc4b6Seschrock 1578e9dbad6fSeschrock if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 157999653d4eSeschrock goto nomem; 1580ea8dc4b6Seschrock 1581ea8dc4b6Seschrock zc.zc_bookmark = zb[i]; 1582e9dbad6fSeschrock for (;;) { 1583e9dbad6fSeschrock if (ioctl(zhp->zpool_hdl->libzfs_fd, 1584e9dbad6fSeschrock ZFS_IOC_BOOKMARK_NAME, &zc) != 0) { 1585e9dbad6fSeschrock if (errno == ENOMEM) { 1586e9dbad6fSeschrock if (zcmd_expand_dst_nvlist(hdl, &zc) 1587e9dbad6fSeschrock != 0) { 1588e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1589e9dbad6fSeschrock goto nomem; 1590e9dbad6fSeschrock } 1591e9dbad6fSeschrock 1592e9dbad6fSeschrock continue; 1593e9dbad6fSeschrock } else { 1594e9dbad6fSeschrock if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 1595e9dbad6fSeschrock 0) != 0) 1596e9dbad6fSeschrock goto nomem; 1597e9dbad6fSeschrock 1598e9dbad6fSeschrock zhp->zpool_error_log[j] = nv; 1599e9dbad6fSeschrock (void) snprintf(buf, sizeof (buf), 16005ad82045Snd "%llx", (longlong_t) 16015ad82045Snd zb[i].zb_objset); 1602e9dbad6fSeschrock if (nvlist_add_string(nv, 1603e9dbad6fSeschrock ZPOOL_ERR_DATASET, buf) != 0) 1604e9dbad6fSeschrock goto nomem; 1605e9dbad6fSeschrock (void) snprintf(buf, sizeof (buf), 16065ad82045Snd "%llx", (longlong_t) 16075ad82045Snd zb[i].zb_object); 1608e9dbad6fSeschrock if (nvlist_add_string(nv, 1609e9dbad6fSeschrock ZPOOL_ERR_OBJECT, buf) != 0) 1610e9dbad6fSeschrock goto nomem; 1611e9dbad6fSeschrock (void) snprintf(buf, sizeof (buf), 1612e9dbad6fSeschrock "lvl=%u blkid=%llu", 1613e9dbad6fSeschrock (int)zb[i].zb_level, 1614e9dbad6fSeschrock (long long)zb[i].zb_blkid); 1615e9dbad6fSeschrock if (nvlist_add_string(nv, 1616e9dbad6fSeschrock ZPOOL_ERR_RANGE, buf) != 0) 1617e9dbad6fSeschrock goto nomem; 1618e9dbad6fSeschrock } 1619e9dbad6fSeschrock } else { 1620e9dbad6fSeschrock if (zcmd_read_dst_nvlist(hdl, &zc, 1621e9dbad6fSeschrock &zhp->zpool_error_log[j]) != 0) { 1622e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1623e9dbad6fSeschrock goto nomem; 1624e9dbad6fSeschrock } 1625e9dbad6fSeschrock } 1626e9dbad6fSeschrock 1627e9dbad6fSeschrock break; 1628ea8dc4b6Seschrock } 1629ea8dc4b6Seschrock 1630e9dbad6fSeschrock zcmd_free_nvlists(&zc); 1631e9dbad6fSeschrock 1632ea8dc4b6Seschrock j++; 1633ea8dc4b6Seschrock } 1634ea8dc4b6Seschrock 1635ea8dc4b6Seschrock *list = zhp->zpool_error_log; 1636ea8dc4b6Seschrock *nelem = zhp->zpool_error_count; 1637e9dbad6fSeschrock free(zb); 1638ea8dc4b6Seschrock 1639ea8dc4b6Seschrock return (0); 164099653d4eSeschrock 164199653d4eSeschrock nomem: 1642e9dbad6fSeschrock free(zb); 1643e9dbad6fSeschrock free((void *)(uintptr_t)zc.zc_nvlist_dst); 1644e9dbad6fSeschrock for (i = 0; i < zhp->zpool_error_count; i++) 1645e9dbad6fSeschrock nvlist_free(zhp->zpool_error_log[i]); 164699653d4eSeschrock free(zhp->zpool_error_log); 164799653d4eSeschrock zhp->zpool_error_log = NULL; 164899653d4eSeschrock return (no_memory(zhp->zpool_hdl)); 1649ea8dc4b6Seschrock } 1650eaca9bbdSeschrock 1651eaca9bbdSeschrock /* 1652eaca9bbdSeschrock * Upgrade a ZFS pool to the latest on-disk version. 1653eaca9bbdSeschrock */ 1654eaca9bbdSeschrock int 1655eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp) 1656eaca9bbdSeschrock { 1657eaca9bbdSeschrock zfs_cmd_t zc = { 0 }; 165899653d4eSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 1659eaca9bbdSeschrock 1660eaca9bbdSeschrock (void) strcpy(zc.zc_name, zhp->zpool_name); 166199653d4eSeschrock if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0) 166299653d4eSeschrock return (zpool_standard_error(hdl, errno, 166399653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"), 166499653d4eSeschrock zhp->zpool_name)); 1665eaca9bbdSeschrock 1666eaca9bbdSeschrock return (0); 1667eaca9bbdSeschrock } 1668*06eeb2adSek 1669*06eeb2adSek /* 1670*06eeb2adSek * Log command history. 1671*06eeb2adSek * 1672*06eeb2adSek * 'pool' is B_TRUE if we are logging a command for 'zpool'; B_FALSE 1673*06eeb2adSek * otherwise ('zfs'). 'pool_create' is B_TRUE if we are logging the creation 1674*06eeb2adSek * of the pool; B_FALSE otherwise. 'path' is the pathanme containing the 1675*06eeb2adSek * poolname. 'argc' and 'argv' are used to construct the command string. 1676*06eeb2adSek */ 1677*06eeb2adSek void 1678*06eeb2adSek zpool_log_history(libzfs_handle_t *hdl, int argc, char **argv, const char *path, 1679*06eeb2adSek boolean_t pool, boolean_t pool_create) 1680*06eeb2adSek { 1681*06eeb2adSek char cmd_buf[HIS_MAX_RECORD_LEN]; 1682*06eeb2adSek char *dspath; 1683*06eeb2adSek zfs_cmd_t zc = { 0 }; 1684*06eeb2adSek int i; 1685*06eeb2adSek 1686*06eeb2adSek /* construct the command string */ 1687*06eeb2adSek (void) strcpy(cmd_buf, pool ? "zpool" : "zfs"); 1688*06eeb2adSek for (i = 0; i < argc; i++) { 1689*06eeb2adSek if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN) 1690*06eeb2adSek break; 1691*06eeb2adSek (void) strcat(cmd_buf, " "); 1692*06eeb2adSek (void) strcat(cmd_buf, argv[i]); 1693*06eeb2adSek } 1694*06eeb2adSek 1695*06eeb2adSek /* figure out the poolname */ 1696*06eeb2adSek dspath = strpbrk(path, "/@"); 1697*06eeb2adSek if (dspath == NULL) { 1698*06eeb2adSek (void) strcpy(zc.zc_name, path); 1699*06eeb2adSek } else { 1700*06eeb2adSek (void) strncpy(zc.zc_name, path, dspath - path); 1701*06eeb2adSek zc.zc_name[dspath-path] = '\0'; 1702*06eeb2adSek } 1703*06eeb2adSek 1704*06eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)cmd_buf; 1705*06eeb2adSek zc.zc_history_len = strlen(cmd_buf); 1706*06eeb2adSek 1707*06eeb2adSek /* overloading zc_history_offset */ 1708*06eeb2adSek zc.zc_history_offset = pool_create; 1709*06eeb2adSek 1710*06eeb2adSek (void) ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_LOG_HISTORY, &zc); 1711*06eeb2adSek } 1712*06eeb2adSek 1713*06eeb2adSek /* 1714*06eeb2adSek * Perform ioctl to get some command history of a pool. 1715*06eeb2adSek * 1716*06eeb2adSek * 'buf' is the buffer to fill up to 'len' bytes. 'off' is the 1717*06eeb2adSek * logical offset of the history buffer to start reading from. 1718*06eeb2adSek * 1719*06eeb2adSek * Upon return, 'off' is the next logical offset to read from and 1720*06eeb2adSek * 'len' is the actual amount of bytes read into 'buf'. 1721*06eeb2adSek */ 1722*06eeb2adSek static int 1723*06eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len) 1724*06eeb2adSek { 1725*06eeb2adSek zfs_cmd_t zc = { 0 }; 1726*06eeb2adSek libzfs_handle_t *hdl = zhp->zpool_hdl; 1727*06eeb2adSek 1728*06eeb2adSek (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); 1729*06eeb2adSek 1730*06eeb2adSek zc.zc_history = (uint64_t)(uintptr_t)buf; 1731*06eeb2adSek zc.zc_history_len = *len; 1732*06eeb2adSek zc.zc_history_offset = *off; 1733*06eeb2adSek 1734*06eeb2adSek if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) { 1735*06eeb2adSek switch (errno) { 1736*06eeb2adSek case EPERM: 1737*06eeb2adSek return (zfs_error(hdl, EZFS_PERM, dgettext(TEXT_DOMAIN, 1738*06eeb2adSek "cannot show history for pool '%s'"), 1739*06eeb2adSek zhp->zpool_name)); 1740*06eeb2adSek case ENOENT: 1741*06eeb2adSek return (zfs_error(hdl, EZFS_NOHISTORY, 1742*06eeb2adSek dgettext(TEXT_DOMAIN, "cannot get history for pool " 1743*06eeb2adSek "'%s'"), zhp->zpool_name)); 1744*06eeb2adSek default: 1745*06eeb2adSek return (zpool_standard_error(hdl, errno, 1746*06eeb2adSek dgettext(TEXT_DOMAIN, 1747*06eeb2adSek "cannot get history for '%s'"), zhp->zpool_name)); 1748*06eeb2adSek } 1749*06eeb2adSek } 1750*06eeb2adSek 1751*06eeb2adSek *len = zc.zc_history_len; 1752*06eeb2adSek *off = zc.zc_history_offset; 1753*06eeb2adSek 1754*06eeb2adSek return (0); 1755*06eeb2adSek } 1756*06eeb2adSek 1757*06eeb2adSek /* 1758*06eeb2adSek * Process the buffer of nvlists, unpacking and storing each nvlist record 1759*06eeb2adSek * into 'records'. 'leftover' is set to the number of bytes that weren't 1760*06eeb2adSek * processed as there wasn't a complete record. 1761*06eeb2adSek */ 1762*06eeb2adSek static int 1763*06eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 1764*06eeb2adSek nvlist_t ***records, uint_t *numrecords) 1765*06eeb2adSek { 1766*06eeb2adSek uint64_t reclen; 1767*06eeb2adSek nvlist_t *nv; 1768*06eeb2adSek int i; 1769*06eeb2adSek 1770*06eeb2adSek while (bytes_read > sizeof (reclen)) { 1771*06eeb2adSek 1772*06eeb2adSek /* get length of packed record (stored as little endian) */ 1773*06eeb2adSek for (i = 0, reclen = 0; i < sizeof (reclen); i++) 1774*06eeb2adSek reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 1775*06eeb2adSek 1776*06eeb2adSek if (bytes_read < sizeof (reclen) + reclen) 1777*06eeb2adSek break; 1778*06eeb2adSek 1779*06eeb2adSek /* unpack record */ 1780*06eeb2adSek if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0) 1781*06eeb2adSek return (ENOMEM); 1782*06eeb2adSek bytes_read -= sizeof (reclen) + reclen; 1783*06eeb2adSek buf += sizeof (reclen) + reclen; 1784*06eeb2adSek 1785*06eeb2adSek /* add record to nvlist array */ 1786*06eeb2adSek (*numrecords)++; 1787*06eeb2adSek if (ISP2(*numrecords + 1)) { 1788*06eeb2adSek *records = realloc(*records, 1789*06eeb2adSek *numrecords * 2 * sizeof (nvlist_t *)); 1790*06eeb2adSek } 1791*06eeb2adSek (*records)[*numrecords - 1] = nv; 1792*06eeb2adSek } 1793*06eeb2adSek 1794*06eeb2adSek *leftover = bytes_read; 1795*06eeb2adSek return (0); 1796*06eeb2adSek } 1797*06eeb2adSek 1798*06eeb2adSek #define HIS_BUF_LEN (128*1024) 1799*06eeb2adSek 1800*06eeb2adSek /* 1801*06eeb2adSek * Retrieve the command history of a pool. 1802*06eeb2adSek */ 1803*06eeb2adSek int 1804*06eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) 1805*06eeb2adSek { 1806*06eeb2adSek char buf[HIS_BUF_LEN]; 1807*06eeb2adSek uint64_t off = 0; 1808*06eeb2adSek nvlist_t **records = NULL; 1809*06eeb2adSek uint_t numrecords = 0; 1810*06eeb2adSek int err, i; 1811*06eeb2adSek 1812*06eeb2adSek do { 1813*06eeb2adSek uint64_t bytes_read = sizeof (buf); 1814*06eeb2adSek uint64_t leftover; 1815*06eeb2adSek 1816*06eeb2adSek if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) 1817*06eeb2adSek break; 1818*06eeb2adSek 1819*06eeb2adSek /* if nothing else was read in, we're at EOF, just return */ 1820*06eeb2adSek if (!bytes_read) 1821*06eeb2adSek break; 1822*06eeb2adSek 1823*06eeb2adSek if ((err = zpool_history_unpack(buf, bytes_read, 1824*06eeb2adSek &leftover, &records, &numrecords)) != 0) 1825*06eeb2adSek break; 1826*06eeb2adSek off -= leftover; 1827*06eeb2adSek 1828*06eeb2adSek /* CONSTCOND */ 1829*06eeb2adSek } while (1); 1830*06eeb2adSek 1831*06eeb2adSek if (!err) { 1832*06eeb2adSek verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0); 1833*06eeb2adSek verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD, 1834*06eeb2adSek records, numrecords) == 0); 1835*06eeb2adSek } 1836*06eeb2adSek for (i = 0; i < numrecords; i++) 1837*06eeb2adSek nvlist_free(records[i]); 1838*06eeb2adSek free(records); 1839*06eeb2adSek 1840*06eeb2adSek return (err); 1841*06eeb2adSek } 1842