1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 212082Seschrock 22789Sahrens /* 238662SJordan.Vaughan@Sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #include <sys/spa.h> 28789Sahrens #include <sys/spa_impl.h> 29789Sahrens #include <sys/nvpair.h> 30789Sahrens #include <sys/uio.h> 31789Sahrens #include <sys/fs/zfs.h> 32789Sahrens #include <sys/vdev_impl.h> 33789Sahrens #include <sys/zfs_ioctl.h> 343975Sek110237 #include <sys/utsname.h> 353975Sek110237 #include <sys/systeminfo.h> 363975Sek110237 #include <sys/sunddi.h> 371544Seschrock #ifdef _KERNEL 381544Seschrock #include <sys/kobj.h> 398662SJordan.Vaughan@Sun.com #include <sys/zone.h> 401544Seschrock #endif 411544Seschrock 42789Sahrens /* 43789Sahrens * Pool configuration repository. 44789Sahrens * 455363Seschrock * Pool configuration is stored as a packed nvlist on the filesystem. By 465363Seschrock * default, all pools are stored in /etc/zfs/zpool.cache and loaded on boot 475363Seschrock * (when the ZFS module is loaded). Pools can also have the 'cachefile' 485363Seschrock * property set that allows them to be stored in an alternate location until 495363Seschrock * the control of external software. 50789Sahrens * 515363Seschrock * For each cache file, we have a single nvlist which holds all the 525363Seschrock * configuration information. When the module loads, we read this information 535363Seschrock * from /etc/zfs/zpool.cache and populate the SPA namespace. This namespace is 545363Seschrock * maintained independently in spa.c. Whenever the namespace is modified, or 555363Seschrock * the configuration of a pool is changed, we call spa_config_sync(), which 565363Seschrock * walks through all the active pools and writes the configuration to disk. 57789Sahrens */ 58789Sahrens 59789Sahrens static uint64_t spa_config_generation = 1; 60789Sahrens 61789Sahrens /* 62789Sahrens * This can be overridden in userland to preserve an alternate namespace for 63789Sahrens * userland pools when doing testing. 64789Sahrens */ 656643Seschrock const char *spa_config_path = ZPOOL_CACHE; 66789Sahrens 67789Sahrens /* 68789Sahrens * Called when the module is first loaded, this routine loads the configuration 69789Sahrens * file into the SPA namespace. It does not actually open or load the pools; it 70789Sahrens * only populates the namespace. 71789Sahrens */ 72789Sahrens void 73789Sahrens spa_config_load(void) 74789Sahrens { 75789Sahrens void *buf = NULL; 76789Sahrens nvlist_t *nvlist, *child; 77789Sahrens nvpair_t *nvpair; 78789Sahrens spa_t *spa; 797754SJeff.Bonwick@Sun.COM char *pathname; 801544Seschrock struct _buf *file; 813912Slling uint64_t fsize; 82789Sahrens 83789Sahrens /* 84789Sahrens * Open the configuration file. 85789Sahrens */ 867754SJeff.Bonwick@Sun.COM pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 877754SJeff.Bonwick@Sun.COM 887754SJeff.Bonwick@Sun.COM (void) snprintf(pathname, MAXPATHLEN, "%s%s", 896643Seschrock (rootdir != NULL) ? "./" : "", spa_config_path); 901544Seschrock 911544Seschrock file = kobj_open_file(pathname); 927754SJeff.Bonwick@Sun.COM 937754SJeff.Bonwick@Sun.COM kmem_free(pathname, MAXPATHLEN); 947754SJeff.Bonwick@Sun.COM 951544Seschrock if (file == (struct _buf *)-1) 96789Sahrens return; 97789Sahrens 983912Slling if (kobj_get_filesize(file, &fsize) != 0) 991544Seschrock goto out; 1001544Seschrock 1013912Slling buf = kmem_alloc(fsize, KM_SLEEP); 1021544Seschrock 103789Sahrens /* 104789Sahrens * Read the nvlist from the file. 105789Sahrens */ 1063912Slling if (kobj_read_file(file, buf, fsize, 0) < 0) 107789Sahrens goto out; 108789Sahrens 109789Sahrens /* 110789Sahrens * Unpack the nvlist. 111789Sahrens */ 1123912Slling if (nvlist_unpack(buf, fsize, &nvlist, KM_SLEEP) != 0) 113789Sahrens goto out; 114789Sahrens 115789Sahrens /* 116789Sahrens * Iterate over all elements in the nvlist, creating a new spa_t for 117789Sahrens * each one with the specified configuration. 118789Sahrens */ 119789Sahrens mutex_enter(&spa_namespace_lock); 120789Sahrens nvpair = NULL; 121789Sahrens while ((nvpair = nvlist_next_nvpair(nvlist, nvpair)) != NULL) { 122789Sahrens 123789Sahrens if (nvpair_type(nvpair) != DATA_TYPE_NVLIST) 124789Sahrens continue; 125789Sahrens 126789Sahrens VERIFY(nvpair_value_nvlist(nvpair, &child) == 0); 127789Sahrens 128789Sahrens if (spa_lookup(nvpair_name(nvpair)) != NULL) 129789Sahrens continue; 1301635Sbonwick spa = spa_add(nvpair_name(nvpair), NULL); 131789Sahrens 132789Sahrens /* 133789Sahrens * We blindly duplicate the configuration here. If it's 134789Sahrens * invalid, we will catch it when the pool is first opened. 135789Sahrens */ 136789Sahrens VERIFY(nvlist_dup(child, &spa->spa_config, 0) == 0); 137789Sahrens } 138789Sahrens mutex_exit(&spa_namespace_lock); 139789Sahrens 140789Sahrens nvlist_free(nvlist); 141789Sahrens 142789Sahrens out: 143789Sahrens if (buf != NULL) 1443912Slling kmem_free(buf, fsize); 145789Sahrens 1461544Seschrock kobj_close_file(file); 147789Sahrens } 148789Sahrens 1496643Seschrock static void 1506643Seschrock spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) 1515363Seschrock { 152789Sahrens size_t buflen; 153789Sahrens char *buf; 154789Sahrens vnode_t *vp; 155789Sahrens int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; 1567754SJeff.Bonwick@Sun.COM char *temp; 1576643Seschrock 1586643Seschrock /* 1596643Seschrock * If the nvlist is empty (NULL), then remove the old cachefile. 1606643Seschrock */ 1616643Seschrock if (nvl == NULL) { 1626643Seschrock (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); 1636643Seschrock return; 1646643Seschrock } 165789Sahrens 166789Sahrens /* 167789Sahrens * Pack the configuration into a buffer. 168789Sahrens */ 1696643Seschrock VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); 170789Sahrens 171789Sahrens buf = kmem_alloc(buflen, KM_SLEEP); 1727754SJeff.Bonwick@Sun.COM temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 173789Sahrens 1746643Seschrock VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, 1751544Seschrock KM_SLEEP) == 0); 176789Sahrens 177789Sahrens /* 178789Sahrens * Write the configuration to disk. We need to do the traditional 179789Sahrens * 'write to temporary file, sync, move over original' to make sure we 180789Sahrens * always have a consistent view of the data. 181789Sahrens */ 1827754SJeff.Bonwick@Sun.COM (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); 183789Sahrens 1847754SJeff.Bonwick@Sun.COM if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) { 1857754SJeff.Bonwick@Sun.COM if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 1867754SJeff.Bonwick@Sun.COM 0, RLIM64_INFINITY, kcred, NULL) == 0 && 1877754SJeff.Bonwick@Sun.COM VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { 1887754SJeff.Bonwick@Sun.COM (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE); 1897754SJeff.Bonwick@Sun.COM } 1907754SJeff.Bonwick@Sun.COM (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); 1917754SJeff.Bonwick@Sun.COM VN_RELE(vp); 192789Sahrens } 193789Sahrens 1947754SJeff.Bonwick@Sun.COM (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); 195789Sahrens 1965363Seschrock kmem_free(buf, buflen); 1977754SJeff.Bonwick@Sun.COM kmem_free(temp, MAXPATHLEN); 1985363Seschrock } 1995363Seschrock 2005363Seschrock /* 2016643Seschrock * Synchronize pool configuration to disk. This must be called with the 2026643Seschrock * namespace lock held. 2035363Seschrock */ 2045363Seschrock void 2056643Seschrock spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent) 2065363Seschrock { 2076643Seschrock spa_config_dirent_t *dp, *tdp; 2086643Seschrock nvlist_t *nvl; 2095363Seschrock 2105363Seschrock ASSERT(MUTEX_HELD(&spa_namespace_lock)); 211789Sahrens 2128225SGeorge.Wilson@Sun.COM if (rootdir == NULL) 2138225SGeorge.Wilson@Sun.COM return; 2148225SGeorge.Wilson@Sun.COM 2156643Seschrock /* 2166643Seschrock * Iterate over all cachefiles for the pool, past or present. When the 2176643Seschrock * cachefile is changed, the new one is pushed onto this list, allowing 2186643Seschrock * us to update previous cachefiles that no longer contain this pool. 2196643Seschrock */ 2206643Seschrock for (dp = list_head(&target->spa_config_list); dp != NULL; 2216643Seschrock dp = list_next(&target->spa_config_list, dp)) { 2227754SJeff.Bonwick@Sun.COM spa_t *spa = NULL; 2236643Seschrock if (dp->scd_path == NULL) 2246643Seschrock continue; 2256643Seschrock 2266643Seschrock /* 2276643Seschrock * Iterate over all pools, adding any matching pools to 'nvl'. 2286643Seschrock */ 2296643Seschrock nvl = NULL; 2306643Seschrock while ((spa = spa_next(spa)) != NULL) { 2316643Seschrock if (spa == target && removing) 2326643Seschrock continue; 2336643Seschrock 2347754SJeff.Bonwick@Sun.COM mutex_enter(&spa->spa_props_lock); 2356643Seschrock tdp = list_head(&spa->spa_config_list); 2367754SJeff.Bonwick@Sun.COM if (spa->spa_config == NULL || 2377754SJeff.Bonwick@Sun.COM tdp->scd_path == NULL || 2387754SJeff.Bonwick@Sun.COM strcmp(tdp->scd_path, dp->scd_path) != 0) { 2397754SJeff.Bonwick@Sun.COM mutex_exit(&spa->spa_props_lock); 2406643Seschrock continue; 2417754SJeff.Bonwick@Sun.COM } 2426643Seschrock 2436643Seschrock if (nvl == NULL) 2446643Seschrock VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, 2456643Seschrock KM_SLEEP) == 0); 2466643Seschrock 2476643Seschrock VERIFY(nvlist_add_nvlist(nvl, spa->spa_name, 2486643Seschrock spa->spa_config) == 0); 2497754SJeff.Bonwick@Sun.COM mutex_exit(&spa->spa_props_lock); 2506643Seschrock } 2516643Seschrock 2526643Seschrock spa_config_write(dp, nvl); 2536643Seschrock nvlist_free(nvl); 2546643Seschrock } 2555363Seschrock 2565363Seschrock /* 2576643Seschrock * Remove any config entries older than the current one. 2585363Seschrock */ 2596643Seschrock dp = list_head(&target->spa_config_list); 2606643Seschrock while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) { 2616643Seschrock list_remove(&target->spa_config_list, tdp); 2626643Seschrock if (tdp->scd_path != NULL) 2636643Seschrock spa_strfree(tdp->scd_path); 2646643Seschrock kmem_free(tdp, sizeof (spa_config_dirent_t)); 2655363Seschrock } 2665363Seschrock 2675363Seschrock spa_config_generation++; 2686643Seschrock 2696643Seschrock if (postsysevent) 2706643Seschrock spa_event_notify(target, NULL, ESC_ZFS_CONFIG_SYNC); 271789Sahrens } 272789Sahrens 273789Sahrens /* 2741635Sbonwick * Sigh. Inside a local zone, we don't have access to /etc/zfs/zpool.cache, 275789Sahrens * and we don't want to allow the local zone to see all the pools anyway. 276789Sahrens * So we have to invent the ZFS_IOC_CONFIG ioctl to grab the configuration 277789Sahrens * information for all pool visible within the zone. 278789Sahrens */ 279789Sahrens nvlist_t * 280789Sahrens spa_all_configs(uint64_t *generation) 281789Sahrens { 282789Sahrens nvlist_t *pools; 2837754SJeff.Bonwick@Sun.COM spa_t *spa = NULL; 284789Sahrens 285789Sahrens if (*generation == spa_config_generation) 286789Sahrens return (NULL); 287789Sahrens 2881544Seschrock VERIFY(nvlist_alloc(&pools, NV_UNIQUE_NAME, KM_SLEEP) == 0); 289789Sahrens 290789Sahrens mutex_enter(&spa_namespace_lock); 291789Sahrens while ((spa = spa_next(spa)) != NULL) { 292789Sahrens if (INGLOBALZONE(curproc) || 293789Sahrens zone_dataset_visible(spa_name(spa), NULL)) { 2947754SJeff.Bonwick@Sun.COM mutex_enter(&spa->spa_props_lock); 295789Sahrens VERIFY(nvlist_add_nvlist(pools, spa_name(spa), 296789Sahrens spa->spa_config) == 0); 2977754SJeff.Bonwick@Sun.COM mutex_exit(&spa->spa_props_lock); 298789Sahrens } 299789Sahrens } 3007754SJeff.Bonwick@Sun.COM *generation = spa_config_generation; 301789Sahrens mutex_exit(&spa_namespace_lock); 302789Sahrens 303789Sahrens return (pools); 304789Sahrens } 305789Sahrens 306789Sahrens void 307789Sahrens spa_config_set(spa_t *spa, nvlist_t *config) 308789Sahrens { 3097754SJeff.Bonwick@Sun.COM mutex_enter(&spa->spa_props_lock); 310789Sahrens if (spa->spa_config != NULL) 311789Sahrens nvlist_free(spa->spa_config); 312789Sahrens spa->spa_config = config; 3137754SJeff.Bonwick@Sun.COM mutex_exit(&spa->spa_props_lock); 314789Sahrens } 315789Sahrens 316789Sahrens /* 317789Sahrens * Generate the pool's configuration based on the current in-core state. 318789Sahrens * We infer whether to generate a complete config or just one top-level config 319789Sahrens * based on whether vd is the root vdev. 320789Sahrens */ 321789Sahrens nvlist_t * 322789Sahrens spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats) 323789Sahrens { 324789Sahrens nvlist_t *config, *nvroot; 325789Sahrens vdev_t *rvd = spa->spa_root_vdev; 3263975Sek110237 unsigned long hostid = 0; 3277754SJeff.Bonwick@Sun.COM boolean_t locked = B_FALSE; 328789Sahrens 3297754SJeff.Bonwick@Sun.COM if (vd == NULL) { 3307754SJeff.Bonwick@Sun.COM vd = rvd; 3317754SJeff.Bonwick@Sun.COM locked = B_TRUE; 3327754SJeff.Bonwick@Sun.COM spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER); 3337754SJeff.Bonwick@Sun.COM } 3341635Sbonwick 3357754SJeff.Bonwick@Sun.COM ASSERT(spa_config_held(spa, SCL_CONFIG | SCL_STATE, RW_READER) == 3367754SJeff.Bonwick@Sun.COM (SCL_CONFIG | SCL_STATE)); 337789Sahrens 338789Sahrens /* 339789Sahrens * If txg is -1, report the current value of spa->spa_config_txg. 340789Sahrens */ 341789Sahrens if (txg == -1ULL) 342789Sahrens txg = spa->spa_config_txg; 343789Sahrens 3441544Seschrock VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0); 345789Sahrens 346789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION, 3472082Seschrock spa_version(spa)) == 0); 348789Sahrens VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, 349789Sahrens spa_name(spa)) == 0); 350789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, 351789Sahrens spa_state(spa)) == 0); 352789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, 353789Sahrens txg) == 0); 354789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, 355789Sahrens spa_guid(spa)) == 0); 3568662SJordan.Vaughan@Sun.com #ifdef _KERNEL 3578662SJordan.Vaughan@Sun.com hostid = zone_get_hostid(NULL); 3588662SJordan.Vaughan@Sun.com #else /* _KERNEL */ 3598662SJordan.Vaughan@Sun.com /* 3608662SJordan.Vaughan@Sun.com * We're emulating the system's hostid in userland, so we can't use 3618662SJordan.Vaughan@Sun.com * zone_get_hostid(). 3628662SJordan.Vaughan@Sun.com */ 3633975Sek110237 (void) ddi_strtoul(hw_serial, NULL, 10, &hostid); 3648662SJordan.Vaughan@Sun.com #endif /* _KERNEL */ 3654178Slling if (hostid != 0) { 3664178Slling VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID, 3674527Sperrin hostid) == 0); 3684178Slling } 3693975Sek110237 VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME, 3703975Sek110237 utsname.nodename) == 0); 371789Sahrens 372789Sahrens if (vd != rvd) { 373789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID, 374789Sahrens vd->vdev_top->vdev_guid) == 0); 375789Sahrens VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_GUID, 376789Sahrens vd->vdev_guid) == 0); 3772082Seschrock if (vd->vdev_isspare) 3782082Seschrock VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE, 3792082Seschrock 1ULL) == 0); 3804527Sperrin if (vd->vdev_islog) 3814527Sperrin VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG, 3824527Sperrin 1ULL) == 0); 383789Sahrens vd = vd->vdev_top; /* label contains top config */ 384789Sahrens } 385789Sahrens 3865450Sbrendan nvroot = vdev_config_generate(spa, vd, getstats, B_FALSE, B_FALSE); 387789Sahrens VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0); 388789Sahrens nvlist_free(nvroot); 389789Sahrens 3907754SJeff.Bonwick@Sun.COM if (locked) 3917754SJeff.Bonwick@Sun.COM spa_config_exit(spa, SCL_CONFIG | SCL_STATE, FTAG); 3927754SJeff.Bonwick@Sun.COM 393789Sahrens return (config); 394789Sahrens } 3951635Sbonwick 3961635Sbonwick /* 3976423Sgw25295 * For a pool that's not currently a booting rootpool, update all disk labels, 3986423Sgw25295 * generate a fresh config based on the current in-core state, and sync the 3996423Sgw25295 * global config cache. 4001635Sbonwick */ 4011635Sbonwick void 4021635Sbonwick spa_config_update(spa_t *spa, int what) 4031635Sbonwick { 4046423Sgw25295 spa_config_update_common(spa, what, FALSE); 4056423Sgw25295 } 4066423Sgw25295 4076423Sgw25295 /* 4086423Sgw25295 * Update all disk labels, generate a fresh config based on the current 4096423Sgw25295 * in-core state, and sync the global config cache (do not sync the config 4106423Sgw25295 * cache if this is a booting rootpool). 4116423Sgw25295 */ 4126423Sgw25295 void 4136423Sgw25295 spa_config_update_common(spa_t *spa, int what, boolean_t isroot) 4146423Sgw25295 { 4151635Sbonwick vdev_t *rvd = spa->spa_root_vdev; 4161635Sbonwick uint64_t txg; 4171635Sbonwick int c; 4181635Sbonwick 4191635Sbonwick ASSERT(MUTEX_HELD(&spa_namespace_lock)); 4201635Sbonwick 4217754SJeff.Bonwick@Sun.COM spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER); 4221635Sbonwick txg = spa_last_synced_txg(spa) + 1; 4231635Sbonwick if (what == SPA_CONFIG_UPDATE_POOL) { 4241635Sbonwick vdev_config_dirty(rvd); 4251635Sbonwick } else { 4261635Sbonwick /* 4271635Sbonwick * If we have top-level vdevs that were added but have 4281635Sbonwick * not yet been prepared for allocation, do that now. 4291635Sbonwick * (It's safe now because the config cache is up to date, 4301635Sbonwick * so it will be able to translate the new DVAs.) 4311635Sbonwick * See comments in spa_vdev_add() for full details. 4321635Sbonwick */ 4331635Sbonwick for (c = 0; c < rvd->vdev_children; c++) { 4341635Sbonwick vdev_t *tvd = rvd->vdev_child[c]; 435*9816SGeorge.Wilson@Sun.COM if (tvd->vdev_ms_array == 0) 436*9816SGeorge.Wilson@Sun.COM vdev_metaslab_set_size(tvd); 437*9816SGeorge.Wilson@Sun.COM vdev_expand(tvd, txg); 4381635Sbonwick } 4391635Sbonwick } 4407754SJeff.Bonwick@Sun.COM spa_config_exit(spa, SCL_ALL, FTAG); 4411635Sbonwick 4421635Sbonwick /* 4431635Sbonwick * Wait for the mosconfig to be regenerated and synced. 4441635Sbonwick */ 4451635Sbonwick txg_wait_synced(spa->spa_dsl_pool, txg); 4461635Sbonwick 4471635Sbonwick /* 4481635Sbonwick * Update the global config cache to reflect the new mosconfig. 4491635Sbonwick */ 4506423Sgw25295 if (!isroot) 4516643Seschrock spa_config_sync(spa, B_FALSE, what != SPA_CONFIG_UPDATE_POOL); 4521635Sbonwick 4531635Sbonwick if (what == SPA_CONFIG_UPDATE_POOL) 4546423Sgw25295 spa_config_update_common(spa, SPA_CONFIG_UPDATE_VDEVS, isroot); 4551635Sbonwick } 456