spa.c revision 5aeb94743e3be0c51e86f73096334611ae3a058e
/*
* 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.
*/
/*
* This file contains all the routines used when modifying on-disk SPA state.
* This includes opening, importing, destroying, exporting a pool, and syncing a
* pool.
*/
#include <sys/zfs_context.h>
#include <sys/spa_impl.h>
#include <sys/zio_checksum.h>
#include <sys/vdev_impl.h>
#include <sys/metaslab.h>
#include <sys/metaslab_impl.h>
#include <sys/uberblock_impl.h>
#include <sys/dmu_traverse.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_pool.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_prop.h>
#include <sys/dsl_synctask.h>
#include <sys/systeminfo.h>
#include <sys/spa_boot.h>
#include <sys/zfs_ioctl.h>
#include <sys/dsl_scan.h>
#ifdef _KERNEL
#include <sys/bootprops.h>
#endif /* _KERNEL */
#include "zfs_prop.h"
#include "zfs_comutil.h"
typedef enum zti_modes {
zti_mode_fixed, /* value is # of threads (min 1) */
zti_mode_online_percent, /* value is % of online CPUs */
zti_mode_batch, /* cpu-intensive; value is ignored */
zti_mode_null, /* don't create a taskq */
} zti_modes_t;
#define ZTI_FIX(n) { zti_mode_fixed, (n) }
#define ZTI_PCT(n) { zti_mode_online_percent, (n) }
#define ZTI_BATCH { zti_mode_batch, 0 }
#define ZTI_NULL { zti_mode_null, 0 }
typedef struct zio_taskq_info {
static const char *const zio_taskq_types[ZIO_TASKQ_TYPES] = {
"issue", "issue_high", "intr", "intr_high"
};
/*
* Define the taskq threads for the following I/O types:
* NULL, READ, WRITE, FREE, CLAIM, and IOCTL
*/
/* ISSUE ISSUE_HIGH INTR INTR_HIGH */
};
static dsl_syncfunc_t spa_sync_props;
char **ereport);
/*
* This (illegal) pool name is used when temporarily importing a spa_t in order
* to get the vdev stats associated with the imported devices.
*/
#define TRYIMPORT_NAME "$import"
/*
* ==========================================================================
* SPA properties routines
* ==========================================================================
*/
/*
* Add a (source=src, propname=propval) list to an nvlist.
*/
static void
{
else
}
/*
* Get property values from the spa configuration.
*/
static void
{
else
}
0, ZPROP_SRC_LOCAL);
"none", 0, ZPROP_SRC_LOCAL);
}
}
}
/*
* Get zpool property values.
*/
int
{
int err;
/*
* Get properties from the spa config.
*/
/* If no pool property object, no more prop to get. */
return (0);
}
/*
* Get properties from the MOS pool property object.
*/
zap_cursor_advance(&zc)) {
continue;
switch (za.za_integer_length) {
case 8:
/* integer property */
if (za.za_first_integer !=
if (prop == ZPOOL_PROP_BOOTFS) {
dsl_pool_t *dp;
break;
}
strval = kmem_alloc(
KM_SLEEP);
} else {
}
break;
case 1:
/* string property */
if (err) {
break;
}
break;
default:
break;
}
}
out:
nvlist_free(*nvp);
return (err);
}
return (0);
}
/*
* Validate the given pool properties nvlist and modify the list
* for the property values to be set.
*/
static int
{
int error = 0, reset_bootfs = 0;
char *slash;
return (EINVAL);
switch (prop) {
case ZPOOL_PROP_VERSION:
if (!error &&
break;
case ZPOOL_PROP_DELEGATION:
case ZPOOL_PROP_AUTOREPLACE:
case ZPOOL_PROP_LISTSNAPS:
case ZPOOL_PROP_AUTOEXPAND:
break;
case ZPOOL_PROP_BOOTFS:
/*
* If the pool version is less than SPA_VERSION_BOOTFS,
* or the pool is still being created (version == 0),
* the bootfs property cannot be set.
*/
break;
}
/*
* Make sure the vdev config is bootable
*/
break;
}
reset_bootfs = 1;
if (!error) {
break;
}
break;
/* Must be ZPL and not gzip compressed. */
} else {
}
}
break;
case ZPOOL_PROP_FAILUREMODE:
/*
* This is a special case which only occurs when
* the pool has completely failed. This allows
* the user to change the in-core failmode property
* currently be blocked). We do this by returning
* EIO to the caller (spa_prop_set) to trick it
* into thinking we encountered a property validation
* error.
*/
}
break;
case ZPOOL_PROP_CACHEFILE:
break;
if (strval[0] == '\0')
break;
break;
if (strval[0] != '/') {
break;
}
break;
case ZPOOL_PROP_DEDUPDITTO:
else
if (error == 0 &&
break;
}
if (error)
break;
}
if (!error && reset_bootfs) {
if (!error) {
}
}
return (error);
}
void
{
char *cachefile;
&cachefile) != 0)
return;
KM_SLEEP);
if (cachefile[0] == '\0')
else
if (need_sync)
}
int
{
int error;
return (error);
if ((prop = zpool_name_to_prop(
return (EINVAL);
if (prop == ZPOOL_PROP_CACHEFILE ||
prop == ZPOOL_PROP_ALTROOT ||
continue;
break;
}
if (need_sync)
else
return (0);
}
/*
* If the bootfs property value is dsobj, clear it.
*/
void
{
spa->spa_bootfs = 0;
}
}
/*
* ==========================================================================
* ==========================================================================
*/
static int
spa_error_entry_compare(const void *a, const void *b)
{
int ret;
sizeof (zbookmark_t));
if (ret < 0)
return (-1);
else if (ret > 0)
return (1);
else
return (0);
}
/*
* Utility function which retrieves copies of the current logs and
* re-initializes them in the process.
*/
void
{
spa_error_entry_compare, sizeof (spa_error_entry_t),
spa_error_entry_compare, sizeof (spa_error_entry_t),
}
static taskq_t *
{
switch (mode) {
case zti_mode_null:
return (NULL); /* no taskq needed */
case zti_mode_fixed:
break;
case zti_mode_batch:
break;
case zti_mode_online_percent:
break;
default:
panic("unrecognized mode for %s taskq (%u:%u) in "
"spa_activate()",
break;
}
if (batch)
flags |= TASKQ_DC_BATCH;
}
}
static void
{
for (int t = 0; t < ZIO_TYPES; t++) {
for (int q = 0; q < ZIO_TASKQ_TYPES; q++) {
char name[32];
spa->spa_zio_taskq[t][q] =
}
}
}
#ifdef _KERNEL
static void
spa_thread(void *arg)
{
/* bind this thread to the requested psrset */
if (zio_taskq_psrset_bind != PS_NONE) {
pool_lock();
} else {
"Couldn't bind process for zfs pool \"%s\" to "
}
pool_unlock();
}
if (zio_taskq_sysdc) {
}
lwp_exit();
}
#endif
/*
* Activate an uninitialized pool.
*/
static void
{
/* Try to create a covering process */
/* Only create a process if we're going to be around a while. */
NULL, 0) == 0) {
&spa->spa_proc_lock);
}
} else {
#ifdef _KERNEL
"Couldn't create process for zfs pool \"%s\"\n",
#endif
}
}
/* If we didn't create a process, we need to create our taskqs. */
}
spa_error_entry_compare, sizeof (spa_error_entry_t),
spa_error_entry_compare, sizeof (spa_error_entry_t),
}
/*
* Opposite of spa_activate().
*/
static void
{
for (int t = 0; t < ZIO_TYPES; t++) {
for (int q = 0; q < ZIO_TASKQ_TYPES; q++) {
}
}
/*
* If this was part of an import or the open otherwise failed, we may
* still have errors left in the queues. Empty them just in case.
*/
}
}
/*
* We want to make sure spa_thread() has actually exited the ZFS
* module, so that the module can't be unloaded out from underneath
* it.
*/
}
}
/*
* Verify a pool configuration, and construct the vdev tree appropriately. This
* will create all the necessary vdevs in the appropriate layout, with each vdev
* All vdev validation is done by the vdev_alloc() routine.
*/
static int
{
int error;
return (error);
return (0);
return (0);
if (error) {
return (EINVAL);
}
for (int c = 0; c < children; c++) {
atype)) != 0) {
return (error);
}
}
return (0);
}
/*
* Opposite of spa_load().
*/
static void
{
int i;
/*
* Stop async tasks.
*/
/*
* Stop syncing.
*/
if (spa->spa_sync_on) {
}
/*
* Wait for any outstanding async I/O to complete.
*/
}
/*
* Close the dsl pool.
*/
if (spa->spa_dsl_pool) {
}
/*
* Drop and purge level 2 cache
*/
/*
* Close all vdevs.
*/
if (spa->spa_root_vdev)
}
}
}
}
spa->spa_async_suspended = 0;
}
/*
* Load (or re-load) the current list of vdevs describing the active spares for
* this pool. When this is called, we have some form of basic information in
* 'spa_spares.sav_config'. We parse this into vdevs, try to open them, and
* then re-generate a more complete list including status information.
*/
static void
{
int i;
/*
* First, close and free any existing spare vdevs.
*/
/* Undo the call to spa_activate() below */
vdev_close(vd);
}
nspares = 0;
else
if (nspares == 0)
return;
/*
* Construct the array of vdevs, opening them to get status in the
* process. For each spare, there is potentially two different vdev_t
* structures associated with it: one in the list of spares (used only
* for basic validation purposes) and one in the active vdev
* configuration (if it's spared in). During this phase we open and
* validate each vdev on the spare list. If the vdev also exists in the
* active configuration, then we also mark this vdev as an active spare.
*/
KM_SLEEP);
VDEV_ALLOC_SPARE) == 0);
if (!tvd->vdev_isspare)
/*
* We only mark the spare active if we were successfully
* able to load the vdev. Otherwise, importing a pool
* with a bad active spare would result in strange
* behavior, because multiple pool would think the spare
* is actively in use.
*
* There is a vulnerability here to an equally bizarre
* circumstance, where a dead active spare is later
* brought back to life (onlined or otherwise). Given
* the rarity of this scenario, and the extra complexity
* it adds, we ignore the possibility.
*/
if (!vdev_is_dead(tvd))
}
continue;
if (vdev_validate_aux(vd) == 0)
}
/*
* Recompute the stashed list of spares, with status information
* this time.
*/
DATA_TYPE_NVLIST_ARRAY) == 0);
KM_SLEEP);
nvlist_free(spares[i]);
}
/*
* Load (or re-load) the current list of vdevs describing the active l2cache for
* this pool. When this is called, we have some form of basic information in
* 'spa_l2cache.sav_config'. We parse this into vdevs, try to open them, and
* then re-generate a more complete list including status information.
* Devices which are already active have their details maintained, and are
* not re-opened.
*/
static void
{
int i, j, oldnvdevs;
} else {
nl2cache = 0;
}
/*
* Process new nvlist of vdevs.
*/
for (i = 0; i < nl2cache; i++) {
&guid) == 0);
for (j = 0; j < oldnvdevs; j++) {
/*
*/
break;
}
}
/*
* Create new vdev
*/
VDEV_ALLOC_L2CACHE) == 0);
/*
* Commit this vdev as an l2cache device,
* even if it fails to open.
*/
continue;
(void) vdev_validate_aux(vd);
if (!vdev_is_dead(vd))
}
}
/*
* Purge vdevs that were dropped
*/
for (i = 0; i < oldnvdevs; i++) {
(void) vdev_close(vd);
}
}
if (oldvdevs)
goto out;
/*
* Recompute the stashed list of l2cache devices, with status
* information this time.
*/
DATA_TYPE_NVLIST_ARRAY) == 0);
out:
nvlist_free(l2cache[i]);
}
static int
{
int error;
if (error == 0)
return (error);
}
/*
* Checks to see if the given vdev could not be opened, in which case we post a
* sysevent to notify the autoreplace code that the device has been removed.
*/
static void
{
for (int c = 0; c < vd->vdev_children; c++)
}
}
/*
* Validate the current config against the MOS config
*/
static boolean_t
{
/*
* If we're doing a normal import, then build up any additional
* diagnostic information about missing devices in this config.
* We'll pass this up to the user for further processing.
*/
KM_SLEEP);
for (int c = 0; c < rvd->vdev_children; c++) {
B_FALSE, 0);
}
if (idx) {
ZPOOL_CONFIG_MISSING_DEVICES, nv) == 0);
for (int i = 0; i < idx; i++)
nvlist_free(child[i]);
}
}
/*
* Compare the root vdev tree with the information we have
* from the MOS config (mrvd). Check each top-level vdev
* with the corresponding MOS config top-level (mtvd).
*/
for (int c = 0; c < rvd->vdev_children; c++) {
/*
* Resolve any "missing" vdevs in the current configuration.
* If we find that the MOS config has more accurate information
* about the top-level vdev then use that vdev instead.
*/
continue;
/*
* Device specific actions.
*/
if (mtvd->vdev_islog) {
} else {
/*
* XXX - once we have 'readonly' pool
* support we should be able to handle
* missing data devices by transitioning
* the pool to readonly.
*/
continue;
}
/*
* Swap the missing vdev with the data we were
* able to obtain from the MOS config.
*/
} else if (mtvd->vdev_islog) {
/*
* Load the slog device's state from the MOS config
* since it's possible that the label does not
* contain the most up-to-date information.
*/
}
}
/*
* Ensure we were able to validate the config.
*/
}
/*
* Check for missing log devices
*/
static int
{
switch (spa->spa_log_state) {
case SPA_LOG_MISSING:
/* need to recheck in case slog has been restored */
case SPA_LOG_UNKNOWN:
DS_FIND_CHILDREN)) {
return (1);
}
break;
}
return (0);
}
static boolean_t
{
if (!spa_has_slogs(spa))
return (B_FALSE);
for (int c = 0; c < rvd->vdev_children; c++) {
if (tvd->vdev_islog) {
slog_found = B_TRUE;
}
}
return (slog_found);
}
static void
{
for (int c = 0; c < rvd->vdev_children; c++) {
if (tvd->vdev_islog)
}
}
int
{
int error = 0;
NULL, DS_FIND_CHILDREN)) == 0) {
/*
* We successfully offlined the log device, sync out the
* current txg so that the "stubby" block can be removed
* by zil_sync().
*/
}
return (error);
}
static void
{
}
void
{
return;
}
typedef struct spa_load_error {
static void
{
if (error) {
else
}
}
/*ARGSUSED*/
static int
{
}
return (0);
}
static int
{
spa_load_error_t sle = { 0 };
int error;
return (0);
ZPOOL_CONFIG_REWIND_TIME, loss) == 0);
} else {
}
if (error) {
return (error);
}
}
/*
* Find a value in the pool props object.
*/
static void
{
}
/*
* Find a value in the pool directory object.
*/
static int
{
}
static int
{
return (err);
}
/*
* Fix up config after a partly-completed split. This is done with the
* ZPOOL_CONFIG_SPLIT nvlist. Both the splitting pool and the split-off
* pool have that entry in their config, but only the splitting one contains
* a list of all the guids of the vdevs that are being split off.
*
* This function determines what to do with that list: either rejoin
* all the disks to the pool, or complete the splitting process. To attempt
* the rejoin, each disk that is offlined is marked online again, and
* we do a reopen() call. If the vdev label for every disk that was
* marked online indicates it was successfully split off (VDEV_AUX_SPLIT_POOL)
* then we call vdev_split() on each disk, and complete the split.
*
* Otherwise we leave the config alone, with all the vdevs in place in
* the original pool.
*/
static void
{
return;
/* check that the config is complete */
return;
/* attempt to online all the vdevs & validate */
for (i = 0; i < gcount; i++) {
if (glist[i] == 0) /* vdev is hole */
continue;
/*
* Don't bother attempting to reopen the disks;
* just do the split.
*/
} else {
/* attempt to re-online it */
}
}
if (attempt_reopen) {
/* check each device to see what state it's in */
break;
++extracted;
}
}
/*
* If every disk has been moved to the new pool, or if we never
* even attempted to look at them, then we split them off for
* good.
*/
for (i = 0; i < gcount; i++)
vdev_split(vd[i]);
}
}
static int
{
char *ereport = FM_EREPORT_ZFS_POOL;
int error;
return (EINVAL);
/*
* Versioning wasn't explicitly added to the label until later, so if
* it's not present treat it as the initial version.
*/
&spa->spa_config_txg);
spa_guid_exists(pool_guid, 0)) {
} else {
&nvl) == 0) {
KM_SLEEP) == 0);
}
}
if (error) {
}
}
}
return (error);
}
/*
* Load an existing storage pool, using the pool's builtin spa_config as a
* source of configuration information.
*/
static int
char **ereport)
{
int error = 0;
int parse;
/*
* If this is an untrusted config, access the pool in read-only mode.
* This prevents things like resilvering recently removed devices.
*/
if (!mosconfig)
return (EINVAL);
/*
* Create "The Godfather" zio to hold all async IOs
*/
/*
* Parse the configuration into a vdev tree. We explicitly set the
* value that will be returned by spa_version() since parsing the
* configuration requires knowing the version number.
*/
if (error != 0)
return (error);
if (type != SPA_IMPORT_ASSEMBLE) {
}
/*
* Try to open all vdevs, loading each label in the process.
*/
if (error != 0)
return (error);
/*
* We need to validate the vdev labels against the configuration that
* we have in hand, which is dependent on the setting of mosconfig. If
* mosconfig is true then we're validating the vdev labels based on
* that config. Otherwise, we're validating against the cached config
* (zpool.cache) that was read when we loaded the zfs module, and then
* later we will recursively call spa_load() and validate against
* the vdev config.
*
* If we're assembling a new pool that's been split off from an
* existing pool, the labels haven't yet been updated so we skip
* validation for now.
*/
if (type != SPA_IMPORT_ASSEMBLE) {
if (error != 0)
return (error);
return (ENXIO);
}
/*
* Find the best uberblock.
*/
/*
* If we weren't able to find a single valid uberblock, return failure.
*/
/*
* If the pool is newer than the code, we can't open it.
*/
/*
* If the vdev guid sum doesn't match the uberblock, we have an
* incomplete configuration. We first check to see if the pool
* is aware of the complete config (i.e ZPOOL_CONFIG_VDEV_CHILDREN).
* If it is, defer the vdev_guid_sum check till later so we
* can handle missing vdevs.
*/
}
/*
* Initialize internal SPA structures.
*/
if (error)
if (!mosconfig) {
ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
char *hostname;
unsigned long myhostid = 0;
ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
#ifdef _KERNEL
#else /* _KERNEL */
/*
* We're emulating the system's hostid in userland, so
* we can't use zone_get_hostid().
*/
#endif /* _KERNEL */
"loaded as it was last accessed by "
"another system (host: %s hostid: 0x%lx). "
(unsigned long)hostid);
return (EBADF);
}
}
ZPOOL_REWIND_POLICY, &policy) == 0)
ZPOOL_REWIND_POLICY, policy) == 0);
}
if (error != 0)
/*
* Load the bit that tells us to use the new accounting function
* (raid-z deflation). If we have an older pool, this will not
* be present.
*/
/*
* Load the persistent error log. If we have an older pool, this will
* not be present.
*/
&spa->spa_errlog_scrub);
/*
* Load the history object. If we have an older pool, this
* will not be present.
*/
/*
* If we're assembling the pool from the split-off vdevs of
* an existing pool, we don't want to attach the spares & cache
* devices.
*/
/*
* Load any hot spares for this pool.
*/
} else if (error == 0) {
}
/*
* Load any level 2 ARC devices for this pool.
*/
} else if (error == 0) {
}
if (error == 0) {
&spa->spa_dedup_ditto);
}
/*
* If the 'autoreplace' property is set, then post a resource notifying
* the ZFS DE that it should not issue any faults for unopenable
* devices. We also iterate over the vdevs, and post a sysevent for any
* unopenable vdevs so that the normal autoreplace handler can take
* over.
*/
/*
* For the import case, this is done in spa_import(), because
* at this point we're using the spare definitions from
* the MOS config, not necessarily from the userland config.
*/
if (state != SPA_LOAD_IMPORT) {
}
}
/*
* Load the vdev state for all toplevel vdevs.
*/
/*
* Propagate the leaf DTLs we just loaded all the way up the tree.
*/
/*
* Load the DDTs (dedup tables).
*/
if (error != 0)
/*
* Validate the config, using the MOS config to fill in any
* information which might be missing. If we fail to validate
* the config then declare the pool unfit for use. If we're
* assembling a pool from a split, the log is not transferred
* over.
*/
if (type != SPA_IMPORT_ASSEMBLE) {
ENXIO));
}
/*
* Now that we've validate the config, check the state of the
* root vdev. If it can't be opened, it indicates one or
* more toplevel vdevs are faulted.
*/
return (ENXIO);
if (spa_check_logs(spa)) {
}
}
/*
* We've successfully opened the pool, verify that we're ready
* to start pushing transactions.
*/
if (state != SPA_LOAD_TRYIMPORT) {
error));
}
int need_update = B_FALSE;
/*
* Claim log blocks that haven't been committed yet.
* This must all happen in a single txg.
* Note: spa_claim_max_txg is updated by spa_claim_notify(),
* invoked from zil_claim_log_block()'s i/o done callback.
* Price of rollback is that we abandon the log.
*/
spa_first_txg(spa));
/*
* Wait for all claims to sync. We sync up to the highest
* claimed log block birth time so that claimed log blocks
* don't appear to be from the future. spa_claim_max_txg
* will have been set for us by either zil_check_log_chain()
* (invoked from spa_check_logs()) or zil_claim() above.
*/
/*
* If the config cache is stale, or we have uninitialized
* metaslabs (see spa_vdev_add()), then update the config.
*
* If this is a verbatim import, trust the current
* in-core spa_config and update the disk labels.
*/
state == SPA_LOAD_IMPORT ||
state == SPA_LOAD_RECOVER ||
for (int c = 0; c < rvd->vdev_children; c++)
/*
* Update the config cache asychronously in case we're the
* root pool, in which case the config cache isn't writable yet.
*/
if (need_update)
/*
* Check all DTLs to see if anything needs resilvering.
*/
/*
* Delete any inconsistent datasets.
*/
/*
* Clean up any stale temporary dataset userrefs.
*/
}
return (0);
}
static int
{
spa->spa_load_max_txg--;
}
static int
{
int load_error, rewind_error;
} else {
}
if (load_error == 0)
return (0);
if (rewind_flags & ZPOOL_NEVER_REWIND) {
return (load_error);
}
/* Price of rolling back is discarding txgs, including log */
if (state == SPA_LOAD_RECOVER)
/*
* Continue as long as we're finding errors, we're still within
* the acceptable rewind range, and we're still finding uberblocks
*/
}
}
/*
*
* The import case is identical to an open except that the configuration is sent
* down from userland, instead of grabbed from the configuration cache. For the
* case of an open, the pool configuration will exist in the
* POOL_STATE_UNINITIALIZED state.
*
* the same time open the pool, without having to keep around the spa_t in some
* ambiguous state.
*/
static int
{
int error;
/*
* As disgusting as this is, we need to support recursive calls to this
* function because dsl_dir_open() is called during spa_load(), and ends
* up calling spa_open() again. The real fix is to figure out how to
* avoid dsl_dir_open() calling this in the first place.
*/
}
if (locked)
return (ENOENT);
}
&policy);
if (state != SPA_LOAD_RECOVER)
/*
* If vdev_validate() returns failure (indicated by
* EBADF), it indicates that one of the vdevs indicates
* that the pool has been exported or destroyed. If
* this is the case, the config cache is out of sync and
* we should remove the pool from the namespace.
*/
if (locked)
return (ENOENT);
}
if (error) {
/*
* We can't open the pool, but we still have useful
* information: the state of each vdev after the
* attempted vdev_open(). Return this to the user.
*/
KM_SLEEP) == 0);
spa->spa_load_info) == 0);
}
if (locked)
return (error);
}
}
/*
* If we've recovered the pool, pass back any information we
* gathered while doing the load.
*/
if (state == SPA_LOAD_RECOVER) {
spa->spa_load_info) == 0);
}
if (locked) {
spa->spa_last_open_failed = 0;
spa->spa_last_ubsync_txg = 0;
spa->spa_load_txg = 0;
}
return (0);
}
int
{
}
int
{
}
/*
* Lookup the given spa_t, incrementing the inject count in the process,
* preventing it from being exported or destroyed.
*/
spa_t *
spa_inject_addref(char *name)
{
return (NULL);
}
spa->spa_inject_ref++;
return (spa);
}
void
{
spa->spa_inject_ref--;
}
/*
* Add spares device information to the nvlist.
*/
static void
{
return;
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
if (nspares != 0) {
/*
* Go through and find any spares which have since been
* repurposed as an active spare. If this is the case, update
* their status appropriately.
*/
for (i = 0; i < nspares; i++) {
ZPOOL_CONFIG_GUID, &guid) == 0);
}
}
}
}
/*
* Add l2cache device information to the nvlist, including vdev stats.
*/
static void
{
return;
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
if (nl2cache != 0) {
/*
* Update level 2 cache device stats.
*/
for (i = 0; i < nl2cache; i++) {
ZPOOL_CONFIG_GUID, &guid) == 0);
if (guid ==
break;
}
}
== 0);
}
}
}
int
{
int error;
/*
* This still leaves a window of inconsistency where the spares
* or l2cache devices could change and the config would be
* self-inconsistent.
*/
spa_get_errlog_size(spa)) == 0);
if (spa_suspended(spa))
spa->spa_failmode) == 0);
}
}
/*
* We want to get the alternate root even for faulted pools, so we cheat
* and call spa_lookup() directly.
*/
if (altroot) {
if (spa)
else
altroot[0] = '\0';
} else {
}
}
}
return (error);
}
/*
* Validate that the auxiliary device array is well formed. We must have an
* array of nvlists, each which describes a valid leaf vdev. If this is an
* import (mode is VDEV_ALLOC_SPARE), then we allow corrupted spares to be
* specified, as long as they are well-formed.
*/
static int
{
int error;
/*
* It's acceptable to have no devs specified.
*/
return (0);
if (ndev == 0)
return (EINVAL);
/*
* Make sure the pool is formatted with a version that supports this
* device type.
*/
return (ENOTSUP);
/*
* Set the pending device list so we correctly handle device in-use
* checking.
*/
for (i = 0; i < ndev; i++) {
mode)) != 0)
goto out;
goto out;
}
/*
* The L2ARC currently only supports disk devices in
* kernel context. For user-level testing, we allow it.
*/
#ifdef _KERNEL
goto out;
}
#endif
}
if (error &&
goto out;
else
error = 0;
}
out:
sav->sav_npending = 0;
return (error);
}
static int
{
int error;
VDEV_LABEL_SPARE)) != 0) {
return (error);
}
}
static void
const char *config)
{
int i;
/*
* Generate new dev list by concatentating with the
* current dev list.
*/
newdevs = kmem_alloc(sizeof (void *) *
for (i = 0; i < oldndevs; i++)
KM_SLEEP) == 0);
for (i = 0; i < ndevs; i++)
KM_SLEEP) == 0);
DATA_TYPE_NVLIST_ARRAY) == 0);
nvlist_free(newdevs[i]);
} else {
/*
* Generate a new dev list.
*/
KM_SLEEP) == 0);
}
}
/*
* Stop and drop level 2 ARC devices
*/
void
{
int i;
if (vd->vdev_isl2cache)
(void) vdev_close(vd);
}
}
/*
* Pool Creation
*/
int
{
dsl_pool_t *dp;
int error = 0;
/*
* If this pool already exists, return failure.
*/
return (EEXIST);
}
/*
* Allocate a new spa_t structure.
*/
(void) nvlist_lookup_string(props,
return (error);
}
&version) != 0)
/*
* Create "The Godfather" zio to hold all async IOs
*/
/*
* Create the root vdev.
*/
if (error == 0 &&
VDEV_ALLOC_ADD)) == 0) {
for (int c = 0; c < rvd->vdev_children; c++) {
}
}
if (error != 0) {
return (error);
}
/*
* Get the list of spares, if specified.
*/
KM_SLEEP) == 0);
}
/*
* Get the list of level 2 cache devices, if specified.
*/
NV_UNIQUE_NAME, KM_SLEEP) == 0);
}
/*
* Create DDTs (dedup tables).
*/
/*
* Create the pool config object.
*/
}
}
/* Newly created pools with the right version are always deflated. */
if (version >= SPA_VERSION_RAIDZ_DEFLATE) {
}
}
/*
* Create the deferred-free bpobj. Turn off compression
* because sync-to-convergence takes longer if the blocksize
* keeps changing.
*/
}
/*
* Create the pool's history object.
*/
if (version >= SPA_VERSION_ZPOOL_HISTORY)
/*
* Set pool properties.
*/
}
/*
* We explicitly wait for the first transaction to complete so that our
* bean counters are appropriately updated.
*/
return (0);
}
#ifdef _KERNEL
/*
* Get the root pool information from the root disk, then import the root pool
* during the system boot up time.
*/
extern int vdev_disk_read_rootlabel(char *, char *, nvlist_t **);
static nvlist_t *
{
return (NULL);
/*
* Add this top-level vdev to the child array.
*/
&nvtop) == 0);
&pgid) == 0);
/*
* Put this pool's top-level vdevs into a root vdev.
*/
VDEV_TYPE_ROOT) == 0);
&nvtop, 1) == 0);
/*
* Replace the existing vdev_tree with the new root vdev in
* this pool's configuration (remove the old, add the new).
*/
return (config);
}
/*
* Walk the vdev tree and see if we can find a device with "better"
* configuration. A configuration is "better" if the label on that
* device has a more recent txg.
*/
static void
{
for (int c = 0; c < vd->vdev_children; c++)
&label) != 0)
return;
&label_txg) == 0);
/*
* Do we have a better boot device?
*/
}
}
}
/*
* Import a root pool.
*
* The GRUB "findroot" command will return the vdev we should boot.
*
* For Sparc, devpath_list consists the physpath name of the booting device
* no matter the rootpool is a single device pool or a mirrored pool.
* e.g.
*/
int
{
char *pname;
int error;
/*
* Read the label from the boot device and generate a configuration.
*/
/* iscsi boot */
}
}
#endif
devpath);
return (EIO);
}
&pname) == 0);
/*
* Remove the existing root pool from the namespace so that we
* can replace it with the correct config we just read in.
*/
}
/*
* Build up a vdev tree based on the boot device's label config.
*/
&nvtop) == 0);
if (error) {
pname);
return (error);
}
/*
* Get the boot vdev.
*/
(u_longlong_t)guid);
goto out;
}
/*
* Determine if there is a better boot device.
*/
goto out;
}
/*
* If the boot device is part of a spare vdev then ensure that
* we're booting off the active spare.
*/
!bvd->vdev_isspare) {
"try booting from '%s'",
bvd->vdev_parent->
goto out;
}
error = 0;
out:
return (error);
}
#endif
/*
* Import a non-root pool into the system.
*/
int
{
int error;
/*
* If a pool with this name exists, return failure.
*/
return (EEXIST);
}
/*
* Create and initialize the spa structure.
*/
(void) nvlist_lookup_string(props,
(void) nvlist_lookup_uint64(props,
if (readonly)
/*
* Verbatim import - Take a pool and insert it into the namespace
* as if it had been loaded at boot.
*/
return (0);
}
/*
* Don't start async tasks until we know everything is healthy.
*/
/*
* Pass off the heavy lifting to spa_load(). Pass TRUE for mosconfig
* because the user-supplied config is actually the one to trust when
* doing an import.
*/
if (state != SPA_LOAD_RECOVER)
/*
* Propagate anything learned while loading the pool and pass it
* back to caller (i.e. rewind info, missing devices, etc).
*/
spa->spa_load_info) == 0);
/*
* Toss any existing sparelist, as it doesn't have any validity
* anymore, and conflicts with spa_has_spare().
*/
}
}
&nvroot) == 0);
if (error == 0)
if (error == 0)
return (error);
}
/*
* Override any spares and level 2 cache devices as specified by
*/
else
NV_UNIQUE_NAME, KM_SLEEP) == 0);
}
else
NV_UNIQUE_NAME, KM_SLEEP) == 0);
}
/*
* Check for any removed devices.
*/
if (spa->spa_autoreplace) {
}
if (spa_writeable(spa)) {
/*
* Update the config cache to include the newly-imported pool.
*/
}
/*
* It's possible that the pool was expanded while it was exported.
* We kick off an async task to handle this for us.
*/
return (0);
}
nvlist_t *
{
char *poolname;
int error;
return (NULL);
return (NULL);
/*
* Create and initialize the spa structure.
*/
/*
* Pass off the heavy lifting to spa_load().
* Pass TRUE for mosconfig because the user-supplied config
* is actually the one to trust when doing an import.
*/
/*
* If 'tryconfig' was at least parsable, return the current config.
*/
poolname) == 0);
state) == 0);
/*
* If the bootfs property exists on this pool then we
* copy it out so that external consumers can tell which
* pools are bootable.
*/
/*
* We have to play games with the name since the
* pool was opened as TRYIMPORT_NAME.
*/
char *cp;
} else {
}
ZPOOL_CONFIG_BOOTFS, dsname) == 0);
}
}
/*
* Add the list of hot spares and level 2 cache devices.
*/
}
return (config);
}
/*
*
* The act of destroying or exporting a pool is very simple. We make sure there
* is no more pending I/O and any references to the pool are gone. Then, we
* update the pool state and sync all the labels to disk, removing the
* configuration from the cache afterwards. If the 'hardforce' flag is set, then
* we don't sync the labels or remove the configuration cache.
*/
static int
{
if (oldconfig)
if (!(spa_mode_global & FWRITE))
return (EROFS);
return (ENOENT);
}
/*
* Put a hold on the pool, drop the namespace lock, stop async tasks,
* reacquire the namespace lock, and see if we can export.
*/
/*
* The pool will be in core if it's openable,
* in which case we can modify its state.
*/
/*
* Objsets may be open only because they're dirty, so we
* have to force it to sync before checking spa_refcnt.
*/
/*
* A pool cannot be exported or destroyed if there are active
* references. If we are resetting a pool, allow references by
* fault injection handlers.
*/
if (!spa_refcount_zero(spa) ||
(spa->spa_inject_ref != 0 &&
return (EBUSY);
}
/*
* A pool cannot be exported if it has an active shared spare.
* This is to prevent other pools stealing the active spare
* from an exported pool. At user's own will, such pool can
* be forcedly exported.
*/
return (EXDEV);
}
/*
* We want this to be reflected on every label,
* so mark them all dirty. spa_unload() will do the
* final sync that pushes these changes out.
*/
TXG_DEFER_SIZE + 1;
}
}
}
if (new_state != POOL_STATE_UNINITIALIZED) {
if (!hardforce)
}
return (0);
}
/*
* Destroy a storage pool.
*/
int
spa_destroy(char *pool)
{
}
/*
* Export a storage pool.
*/
int
{
}
/*
* Similar to spa_export(), this unloads the spa_t without actually removing it
* from the namespace in any way.
*/
int
{
}
/*
* ==========================================================================
* Device manipulation
* ==========================================================================
*/
/*
* Add a device to a storage pool.
*/
int
{
int error;
VDEV_ALLOC_ADD)) != 0)
&nspares) != 0)
nspares = 0;
&nl2cache) != 0)
nl2cache = 0;
if (vd->vdev_children != 0 &&
/*
* We must validate the spares and l2cache devices after checking the
* children. Otherwise, vdev_inuse() will blindly overwrite the spare.
*/
/*
* Transfer each new top-level vdev from vd to rvd.
*/
for (int c = 0; c < vd->vdev_children; c++) {
/*
* Set the vdev id to the first hole, if one exists.
*/
break;
}
}
}
if (nspares != 0) {
}
if (nl2cache != 0) {
}
/*
* We have to be careful when adding new vdevs to an existing pool.
* If other threads start allocating from these vdevs before we
* sync the config cache, and we lose power, then upon reboot we may
* fail to open the pool because there are DVAs that the config cache
* can't translate. Therefore, we first add the vdevs without
* initializing metaslabs; sync the config cache (via spa_vdev_exit());
* and then let spa_config_update() initialize the new metaslabs.
*
* spa_load() checks for added-but-not-initialized vdevs, so that
* if we lose power at any point in this sequence, the remaining
* steps will be completed the next time we load the pool.
*/
return (0);
}
/*
* Attach a device to a mirror. The arguments are the path to any device
* in the mirror, and the nvroot for the new device. If the path specifies
* a device that is not mirrored, we automatically insert the mirror vdev.
*
* If 'replacing' is specified, the new device is intended to replace the
* existing device; in this case the two devices are made into their own
* mirror using the 'replacing' vdev, which is functionally identical to
* the mirror vdev (it actually reuses all the same ops) but has a few
* extra rules: you can't attach to it after it's been created, and upon
* completion of resilvering, the first disk (the one being replaced)
* is automatically detached.
*/
int
{
int newvd_isspare;
int error;
VDEV_ALLOC_ADD)) != 0)
/*
* Spares can't replace logs
*/
if (!replacing) {
/*
* For attach, the only allowable parent is a mirror or the root
* vdev.
*/
pvops = &vdev_mirror_ops;
} else {
/*
* Active hot spares can only be replaced by inactive hot
* spares.
*/
oldvd->vdev_isspare &&
/*
* If the source is a hot spare, and the parent isn't already a
* spare, then we want to create a new hot spare. Otherwise, we
* want to create a replacing vdev. The user is not allowed to
* attach to a spared vdev child unless the 'isspare' state is
* the same (spare replaces spare, non-spare replaces
* non-spare).
*/
}
if (newvd->vdev_isspare)
pvops = &vdev_spare_ops;
else
}
/*
* Make sure the new device is big enough.
*/
/*
* The new device cannot have a higher alignment requirement
* than the top-level vdev.
*/
/*
* If this is an in-place replacement, update oldvd's path and devid
* to make it distinguishable from newvd, and unopenable from now on.
*/
KM_SLEEP);
}
}
/* mark the device being resilvered */
/*
* If the parent is not a mirror, or if we're replacing, insert the new
*/
/*
* Extract the new device from its root and add it to pvd.
*/
/*
* Set newvd's DTL to [TXG_INITIAL, dtl_max_txg) so that we account
* for any dmu_sync-ed blocks. It will propagate upward when
* spa_vdev_exit() calls vdev_dtl_reassess().
*/
if (newvd->vdev_isspare) {
}
/*
* Mark newvd's DTL dirty in this txg.
*/
/*
* Restart the resilver
*/
/*
* Commit the config
*/
"%s vdev=%s %s vdev=%s",
if (spa->spa_bootfs)
return (0);
}
/*
* Detach a device from a mirror or replacing vdev.
* If 'replace_done' is specified, only detach if the parent
* is a replacing vdev.
*/
int
{
int error;
char *vdpath;
/*
* Consider M(A,R(B,C)) -- that is, a mirror of A with a replacing
* vdev that's replacing B with C. The user's intent in replacing
* is to go from M(A,B) to M(A,C). If the user decides to cancel
* the replace by detaching C, the expected behavior is to end up
* M(A,B). But suppose that right after deciding to detach C,
* the replacement of B completes. We would have M(A,C), and then
* ask to detach C, which would leave us with just A -- not what
* the user wanted. To prevent this, we make sure that the
* that C's parent is still the replacing vdev R.
*/
/*
* Only 'replacing' or 'spare' vdevs can be replaced.
*/
/*
* Only mirror, replacing, and spare vdevs support detach.
*/
/*
* If this device has the only valid copy of some data,
* we cannot safely detach it.
*/
if (vdev_dtl_required(vd))
/*
* If we are detaching the second disk from a replacing vdev, then
* check to see if we changed the original vdev's path to have "/old"
* at the end in spa_vdev_attach(). If so, undo that change now.
*/
for (int c = 0; c < pvd->vdev_children; c++) {
continue;
break;
}
}
}
/*
* If we are detaching the original disk from a spare, then it implies
* that the spare should become a real disk, and be removed from the
* active spare list for the pool.
*/
/*
* Erase the disk labels so the disk can be used for other things.
* This must be done after all other error cases are handled,
* but before we disembowel vd (so we can still do I/O to it).
* But if we can't do it, don't treat the error as fatal --
* it may be that the unwritability of the disk is the reason
* it's being detached!
*/
/*
* Remove vd from its parent and compact the parent's children.
*/
/*
* Remember one of the remaining children so we can get tvd below.
*/
/*
* If we need to remove the remaining child from the list of hot spares,
* do it now, marking the vdev as no longer a spare in the process.
* We must do this before vdev_remove_parent(), because that can
* change the GUID if it creates a new toplevel GUID. For a similar
* reason, we must remove the spare now, in the same txg as the detach;
* otherwise someone could attach a new sibling, change the GUID, and
* the subsequent attempt to spa_vdev_remove(unspare_guid) would fail.
*/
if (unspare) {
}
/*
* the parent is no longer needed. Remove it from the tree.
*/
}
/*
* We don't set tvd until now because the parent we just removed
* may have been the previous top-level vdev.
*/
/*
* Reevaluate the parent vdev state.
*/
/*
* If the 'autoexpand' property is set on the pool then automatically
* try to expand the size of the pool. For example if the device we
* just detached was smaller than the others, it may be possible to
* add metaslabs (i.e. grow the pool). We need to reopen the vdev
* first so that we can obtain the updated sizes of the leaf vdevs.
*/
if (spa->spa_autoexpand) {
}
/*
* Mark vd's DTL as dirty in this txg. vdev_dtl_sync() will see that
* vd->vdev_detached is set and free vd's DTL object in syncing context.
* But first make sure we're not on any *other* txg's DTL list, to
* prevent vd from being accessed after it's freed.
*/
for (int t = 0; t < TXG_SIZE; t++)
/* hang on to the spa before we release the lock */
"vdev=%s", vdpath);
/*
* If this was the removal of the original device in a hot spare vdev,
* then we want to go through and remove the device from the hot spare
* list of every other pool.
*/
if (unspare) {
continue;
}
/* search the rest of the vdevs for spares to remove */
}
/* all done with the spa; OK to release */
return (error);
}
/*
* Split a set of devices from their mirrors, and create a new pool from them.
*/
int
{
int error = 0;
/* clear the log and flush everything up to now */
if (activate_slog)
if (error != 0)
/* check new spa name before going any further */
/*
* scan through all the children to ensure they're all mirrors
*/
&children) != 0)
/* first, check to ensure we've got the right child count */
lastlog = 0;
for (c = 0; c < rvd->vdev_children; c++) {
/* don't count the holes & logs as children */
if (lastlog == 0)
lastlog = c;
continue;
}
lastlog = 0;
}
/* next, ensure no spare or cache devices are part of the split */
/* then, loop over each vdev and validate it */
for (c = 0; c < children; c++) {
&is_hole);
if (is_hole != 0) {
continue;
} else {
break;
}
}
/* which disk is going to be split? */
&glist[c]) != 0) {
break;
}
/* look it up in the spa */
break;
}
/* make sure there's nothing stopping the split */
vml[c]->vdev_islog ||
vml[c]->vdev_ishole ||
vml[c]->vdev_isspare ||
vml[c]->vdev_isl2cache ||
!vdev_writeable(vml[c]) ||
vml[c]->vdev_children != 0 ||
break;
}
if (vdev_dtl_required(vml[c])) {
break;
}
/* we need certain info from the top level */
}
if (error != 0) {
}
/* stop writers from using the disks */
for (c = 0; c < children; c++) {
}
/*
* Temporarily record the splitting vdevs in the spa config. This
* will disappear once the config is regenerated.
*/
nvl) == 0);
/* configure and create the new pool */
spa_version(spa)) == 0);
spa->spa_config_txg) == 0);
spa_generate_guid(NULL)) == 0);
(void) nvlist_lookup_string(props,
/* add the new pool to the namespace */
/* release the spa config lock, retaining the namespace lock */
/* create the new pool from the disks of the original pool */
if (error)
goto out;
/* if that worked, generate a real config for the new pool */
NV_UNIQUE_NAME, KM_SLEEP) == 0);
B_TRUE));
}
/* set the props */
if (error)
goto out;
}
/* flush everything */
/* finally, update the original pool's config */
if (error != 0)
for (c = 0; c < children; c++) {
vdev_split(vml[c]);
if (error == 0)
}
}
if (error == 0)
/* split is complete; log a history record */
/* if we're not going to mount the filesystems in userland, export */
if (exp)
return (error);
out:
/* re-online all offlined disks */
for (c = 0; c < children; c++) {
}
return (error);
}
static nvlist_t *
{
for (int i = 0; i < count; i++) {
&guid) == 0);
if (guid == target_guid)
return (nvpp[i]);
}
return (NULL);
}
static void
{
if (count > 1)
for (int i = 0, j = 0; i < count; i++) {
if (dev[i] == dev_to_remove)
continue;
}
for (int i = 0; i < count - 1; i++)
nvlist_free(newdev[i]);
if (count > 1)
}
/*
* Evacuate the device.
*/
static int
{
int error = 0;
/*
* Evacuate the device. We don't hold the config lock as writer
* since we need to do I/O but we do keep the
* spa_namespace_lock held. Once this completes the device
* should no longer have any blocks allocated on it.
*/
if (vd->vdev_islog) {
} else {
}
if (error)
return (error);
/*
* The evacuation succeeded. Remove any remaining MOS metadata
* associated with this vdev, and wait for these changes to sync.
*/
return (0);
}
/*
* Complete the removal by cleaning up the namespace.
*/
static void
{
/*
* Only remove any devices which are empty.
*/
return;
if (last_vdev) {
} else {
}
/*
* Reassess the health of our root vdev.
*/
}
/*
* Remove a device from the pool -
*
* Removing a device from the vdev namespace requires several steps
* and can take a significant amount of time. As a result we use
* grab and release the spa_config_lock while still holding the namespace
* lock. During each step the configuration is synced out.
*/
/*
* Remove a device from the pool. Currently, this supports removing only hot
* spares, slogs, and level 2 ARC devices.
*/
int
{
int error = 0;
if (!locked)
/*
* Only remove the hot spare if it's not currently in use
* in this pool.
*/
} else {
}
/*
* Cache devices can always be removed.
*/
/*
* XXX - Once we have bp-rewrite this should
* become the common case.
*/
/*
* Stop allocating from this vdev.
*/
/*
* Wait for the youngest allocations and frees to sync,
* and then wait for the deferral of those frees to finish.
*/
/*
* Attempt to evacuate the vdev.
*/
/*
* If we couldn't evacuate the vdev, unwind.
*/
if (error) {
}
/*
* Clean up the vdev namespace.
*/
/*
* Normal vdevs cannot be removed (yet).
*/
} else {
/*
* There is no vdev of any kind with the specified guid.
*/
}
if (!locked)
return (error);
}
/*
* Find any device that's done replacing, or a vdev marked 'unspare' that's
* current spared, so we can detach it.
*/
static vdev_t *
{
for (int c = 0; c < vd->vdev_children; c++) {
return (oldvd);
}
/*
* Check for a completed replacement. We always consider the first
* vdev in the list to be the oldest vdev, and the last one to be
* the newest (see spa_vdev_attach() for how that works). In
* the case where the newest vdev is faulted, we will not automatically
* remove it after a resilver completes. This is OK as it will require
* user intervention to determine which disk the admin wishes to keep.
*/
return (oldvd);
}
/*
* Check for a completed resilver with the 'unspare' flag set.
*/
if (last->vdev_unspare) {
} else if (first->vdev_unspare) {
} else {
}
return (oldvd);
/*
* If there are more than two spares attached to a disk,
* and those spares are not required, then we want to
* attempt to free them up now so that they can be used
* by other pools. Once we're back down to a single
* disk+spare, we stop removing them.
*/
return (newvd);
}
}
return (NULL);
}
static void
{
sguid = 0;
/*
* If we have just finished replacing a hot spared device, then
* we need to detach the parent's first child (the original hot
* spare) as well.
*/
}
return;
return;
}
}
/*
* Update the stored path or FRU for this vdev.
*/
int
{
if (ispath) {
}
} else {
}
}
}
int
{
}
int
{
}
/*
* ==========================================================================
* SPA Scanning
* ==========================================================================
*/
int
{
return (EBUSY);
}
int
{
return (ENOTSUP);
/*
* If a resilver was requested, but there is no DTL on a
* writeable leaf device, we have nothing to do.
*/
if (func == POOL_SCAN_RESILVER &&
return (0);
}
}
/*
* ==========================================================================
* SPA async task processing
* ==========================================================================
*/
static void
{
if (vd->vdev_remove_wanted) {
/*
* We want to clear the stats, but we don't want to do a full
* vdev_clear() as that will cause us to throw away
* device, all of which is a waste.
*/
}
for (int c = 0; c < vd->vdev_children; c++)
}
static void
{
if (vd->vdev_probe_wanted) {
}
for (int c = 0; c < vd->vdev_children; c++)
}
static void
{
char *physpath;
if (!spa->spa_autoexpand)
return;
for (int c = 0; c < vd->vdev_children; c++) {
}
return;
}
static void
{
int tasks;
spa->spa_async_tasks = 0;
/*
* See if the config needs to be updated.
*/
if (tasks & SPA_ASYNC_CONFIG_UPDATE) {
/*
* If the pool grew as a result of the config update,
* then log an internal history event.
*/
"pool '%s' size: %llu(+%llu)",
}
}
/*
* See if any devices need to be marked REMOVED.
*/
if (tasks & SPA_ASYNC_REMOVE) {
}
}
/*
* See if any devices need to be probed.
*/
if (tasks & SPA_ASYNC_PROBE) {
}
/*
* If any devices are done replacing, detach them.
*/
if (tasks & SPA_ASYNC_RESILVER_DONE)
/*
* Kick off a resilver.
*/
if (tasks & SPA_ASYNC_RESILVER)
/*
* Let the world know that we're done.
*/
thread_exit();
}
void
{
}
void
{
}
static void
{
}
void
{
}
/*
* ==========================================================================
* SPA syncing routines
* ==========================================================================
*/
static int
{
return (0);
}
static int
{
return (0);
}
static void
{
/*
* Write full (SPA_CONFIG_BLOCKSIZE) blocks of configuration
* information. This avoids the dbuf_will_dirty() path and
* saves us a pre-read to get data we don't actually care about.
*/
KM_SLEEP) == 0);
}
static void
{
int i;
return;
/*
* Update the MOS nvlist describing the list of available devices.
* spa_validate_aux() will have already made sure this nvlist is
* valid and the vdevs are labeled appropriately.
*/
if (sav->sav_object == 0) {
}
} else {
nvlist_free(list[i]);
}
}
static void
{
return;
if (spa->spa_config_syncing)
}
/*
* Set zpool properties.
*/
static void
{
char *strval;
const char *propname;
case ZPOOL_PROP_VERSION:
/*
* Only set version for non-zpool-creation cases
* for version setting.
*/
&intval) == 0);
}
break;
case ZPOOL_PROP_ALTROOT:
/*
* 'altroot' is a non-persistent property. It should
* have been set temporarily at creation or import time.
*/
break;
case ZPOOL_PROP_READONLY:
case ZPOOL_PROP_CACHEFILE:
/*
* 'readonly' and 'cachefile' are also non-persisitent
* properties.
*/
break;
default:
/*
* Set pool property values in the poolprops mos object.
*/
if (spa->spa_pool_props_object == 0) {
DMU_OT_NONE, 0, tx)) > 0);
== 0);
}
/* normalize the property name */
if (proptype == PROP_TYPE_INDEX) {
const char *unused;
}
} else {
ASSERT(0); /* not allowed */
}
switch (prop) {
case ZPOOL_PROP_DELEGATION:
break;
case ZPOOL_PROP_BOOTFS:
break;
case ZPOOL_PROP_FAILUREMODE:
break;
case ZPOOL_PROP_AUTOEXPAND:
break;
case ZPOOL_PROP_DEDUPDITTO:
break;
default:
break;
}
}
/* log internal history if this is not a zpool create */
}
}
}
/*
* Perform one-time upgrade on-disk changes. spa_version() does not
* reflect the new version this txg, so there must be no changes this
* txg to anything that the upgrade code depends on after it executes.
* Therefore this must be called after dsl_pool_sync() does the sync
* tasks.
*/
static void
{
/* Keeping the origin open increases spa_minref */
}
}
/* Keeping the freedir open increases spa_minref */
}
}
/*
* Sync the specified transaction group. New blocks may be dirtied as
* part of the process, so we iterate until it converges.
*/
void
{
int error;
/*
* Lock out configuration changes.
*/
spa->spa_sync_pass = 0;
/*
* If there are any pending vdev state changes, convert them
* into config changes that go out with this transaction group.
*/
/*
* We need the write lock here because, for aux vdevs,
* calling vdev_config_dirty() modifies sav_config.
* This is ugly and will become unnecessary when we
* eliminate the aux vdev wart by integrating all vdevs
* into the root vdev tree.
*/
}
}
/*
* If we are upgrading to SPA_VERSION_RAIDZ_DEFLATE this txg,
* set spa_deflate if we have no raid-z vdevs.
*/
int i;
for (i = 0; i < rvd->vdev_children; i++) {
break;
}
if (i == rvd->vdev_children) {
}
}
/*
* If anything has changed in this txg, or if someone is waiting
* for this txg to sync (eg, spa_vdev_remove()), push the
* deferred frees from the previous txg. If not, leave them
* alone so that we don't generate work on an otherwise idle
* system.
*/
}
/*
* Iterate to convergence.
*/
do {
if (pass <= SYNC_PASS_DEFERRED_FREE) {
} else {
}
if (pass == 1)
/*
* Rewrite the vdev configuration (which includes the uberblock)
* to commit the transaction group.
*
* If there are no dirty vdevs, we sync the uberblock to a few
* random top-level vdevs that are known to be visible in the
* config cache (see spa_vdev_add() for a complete description).
* If there *are* dirty vdevs, sync the uberblock to all vdevs.
*/
for (;;) {
/*
* while we're attempting to write the vdev labels.
*/
int svdcount = 0;
for (int c = 0; c < children; c++) {
continue;
if (svdcount == SPA_DVAS_PER_BP)
break;
}
if (error != 0)
B_TRUE);
} else {
if (error != 0)
}
if (error == 0)
break;
}
/*
* Clear the dirty config list.
*/
/*
* Now that the new config has synced transactionally,
* let it become visible to the config cache.
*/
}
/*
* Update usable space statistics.
*/
/*
* It had better be the case that we didn't dirty anything
* since vdev_config_sync().
*/
spa->spa_sync_pass = 0;
/*
* If any async tasks have been requested, kick them off.
*/
}
/*
* Sync all pools. We don't want to hold the namespace lock across these
* operations, so we take a reference on the spa_t and drop the lock during the
* sync.
*/
void
spa_sync_allpools(void)
{
continue;
}
}
/*
* ==========================================================================
* Miscellaneous routines
* ==========================================================================
*/
/*
* Remove all pools in the system.
*/
void
spa_evict_all(void)
{
/*
* Remove all cached state. All pools should be closed now,
* so every spa in the AVL tree should be unreferenced.
*/
/*
* Stop async tasks. The async thread may need to detach
* a device that's been replaced, which requires grabbing
* spa_namespace_lock, so we must drop it here.
*/
}
}
}
vdev_t *
{
int i;
return (vd);
if (aux) {
return (vd);
}
return (vd);
}
}
return (NULL);
}
void
{
/*
* This should only be called for a non-faulted pool, and since a
* future version would result in an unopenable pool, this shouldn't be
* possible.
*/
}
{
int i;
return (B_TRUE);
for (i = 0; i < sav->sav_npending; i++) {
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Check if a pool has an active shared spare device.
* Note: reference count of an active spare is 2, as a spare and as a replace
*/
static boolean_t
{
int i, refcnt;
refcnt > 2)
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Post a sysevent corresponding to the given event. The 'name' must be one of
* the event definitions in sys/sysevent/eventdefs.h. The payload will be
* filled in from the spa and (optionally) the vdev. This doesn't do anything
* in the userland libzpool, as we don't want consumers to misinterpret ztest
* or zdb as real changes.
*/
void
{
#ifdef _KERNEL
sysevent_t *ev;
SE_SLEEP);
goto done;
goto done;
if (vd) {
SE_SLEEP) != 0)
goto done;
goto done;
}
}
goto done;
done:
if (attr)
#endif
}