/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
*/
#include <sys/spa_impl.h>
#include <sys/vdev_impl.h>
#include <sys/zfs_ioctl.h>
#include <sys/systeminfo.h>
#include <sys/zfeature.h>
#ifdef _KERNEL
#endif
/*
* Pool configuration repository.
*
* Pool configuration is stored as a packed nvlist on the filesystem. By
* default, all pools are stored in /etc/zfs/zpool.cache and loaded on boot
* (when the ZFS module is loaded). Pools can also have the 'cachefile'
* property set that allows them to be stored in an alternate location until
* the control of external software.
*
* For each cache file, we have a single nvlist which holds all the
* configuration information. When the module loads, we read this information
* from /etc/zfs/zpool.cache and populate the SPA namespace. This namespace is
* maintained independently in spa.c. Whenever the namespace is modified, or
* the configuration of a pool is changed, we call spa_config_sync(), which
* walks through all the active pools and writes the configuration to disk.
*/
/*
* This can be overridden in userland to preserve an alternate namespace for
* userland pools when doing testing.
*/
/*
* Called when the module is first loaded, this routine loads the configuration
* file into the SPA namespace. It does not actually open or load the pools; it
* only populates the namespace.
*/
void
spa_config_load(void)
{
char *pathname;
/*
* Open the configuration file.
*/
return;
goto out;
/*
* Read the nvlist from the file.
*/
goto out;
/*
* Unpack the nvlist.
*/
goto out;
/*
* Iterate over all elements in the nvlist, creating a new spa_t for
* each one with the specified configuration.
*/
continue;
continue;
}
out:
}
static int
{
char *buf;
char *temp;
int err;
/*
* If the nvlist is empty (NULL), then remove the old cachefile.
*/
return (err);
}
/*
* Pack the configuration into a buffer.
*/
/*
* Write the configuration to disk. We need to do the traditional
* 'write to temporary file, sync, move over original' to make sure we
* always have a consistent view of the data.
*/
if (err == 0) {
if (err == 0)
if (err == 0)
}
return (err);
}
/*
* Synchronize pool configuration to disk. This must be called with the
* namespace lock held. Synchronizing the pool cache is typically done after
* the configuration has been synced to the MOS. This exposes a window where
* the MOS config will have been updated but the cache file has not. If
* the system were to crash at that instant then the cached config may not
* contain the correct information to open the pool and an explicity import
* would be required.
*/
void
{
int error;
return;
/*
* Iterate over all cachefiles for the pool, past or present. When the
* cachefile is changed, the new one is pushed onto this list, allowing
* us to update previous cachefiles that no longer contain this pool.
*/
continue;
/*
* Iterate over all pools, adding any matching pools to 'nvl'.
*/
/*
* Skip over our own pool if we're about to remove
* ourselves from the spa namespace or any pool that
* is readonly. Since we cannot guarantee that a
* readonly pool would successfully import upon reboot,
* we don't allow them to be written to the cache file.
*/
!spa_writeable(spa))
continue;
continue;
}
nvl = fnvlist_alloc();
spa->spa_config);
}
if (error != 0)
}
if (ccw_failure) {
/*
* Keep trying so that configuration data is
* resource issues are resolved.
*/
if (target->spa_ccw_fail_time == 0) {
}
} else {
/*
* Do not rate limit future attempts to update
* the config cache.
*/
target->spa_ccw_fail_time = 0;
}
/*
* Remove any config entries older than the current one.
*/
}
if (postsysevent)
}
/*
* Sigh. Inside a local zone, we don't have access to /etc/zfs/zpool.cache,
* and we don't want to allow the local zone to see all the pools anyway.
* So we have to invent the ZFS_IOC_CONFIG ioctl to grab the configuration
* information for all pool visible within the zone.
*/
nvlist_t *
{
if (*generation == spa_config_generation)
return (NULL);
pools = fnvlist_alloc();
if (INGLOBALZONE(curproc) ||
spa->spa_config);
}
}
return (pools);
}
void
{
}
/*
* Generate the pool's configuration based on the current in-core state.
*
* We infer whether to generate a complete config or just one top-level config
* based on whether vd is the root vdev.
*/
nvlist_t *
{
unsigned long hostid = 0;
}
(SCL_CONFIG | SCL_STATE));
/*
* If txg is -1, report the current value of spa->spa_config_txg.
*/
if (txg == -1ULL)
config = fnvlist_alloc();
spa->spa_comment);
}
#ifdef _KERNEL
#else /* _KERNEL */
/*
* We're emulating the system's hostid in userland, so we can't use
* zone_get_hostid().
*/
#endif /* _KERNEL */
if (hostid != 0) {
}
int config_gen_flags = 0;
if (vd->vdev_isspare) {
ZPOOL_CONFIG_IS_SPARE, 1ULL);
}
if (vd->vdev_islog) {
ZPOOL_CONFIG_IS_LOG, 1ULL);
}
} else {
/*
* Only add the (potentially large) split information
* in the mos config, and not in the vdev labels
*/
}
/*
* Add the top-level config. We even add this on pools which
* don't support holes in the namespace.
*/
/*
* If we're splitting, record the original pool's guid.
*/
ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
}
/*
* Store what's necessary for reading the MOS in the label.
*/
}
if (locked)
return (config);
}
/*
* Update all disk labels, generate a fresh config based on the current
* in-core state, and sync the global config cache (do not sync the config
* cache if this is a booting rootpool).
*/
void
{
int c;
if (what == SPA_CONFIG_UPDATE_POOL) {
} else {
/*
* If we have top-level vdevs that were added but have
* not yet been prepared for allocation, do that now.
* (It's safe now because the config cache is up to date,
* so it will be able to translate the new DVAs.)
* See comments in spa_vdev_add() for full details.
*/
for (c = 0; c < rvd->vdev_children; c++) {
if (tvd->vdev_ms_array == 0)
}
}
/*
* Wait for the mosconfig to be regenerated and synced.
*/
/*
* Update the global config cache to reflect the new mosconfig.
*/
if (!spa->spa_is_root)
if (what == SPA_CONFIG_UPDATE_POOL)
}