summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/truss/codes.c2
-rw-r--r--usr/src/cmd/zdb/zdb.c2
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c443
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h3
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa_impl.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/vdev_impl.h1
-rw-r--r--usr/src/uts/common/fs/zfs/vdev.c22
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_label.c4
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_fm.c56
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c21
-rw-r--r--usr/src/uts/common/sys/fm/fs/zfs.h5
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h2
-rw-r--r--usr/src/uts/common/sys/sysevent/eventdefs.h1
13 files changed, 307 insertions, 256 deletions
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 580c507218..aa9b9ed7bd 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -1021,6 +1021,8 @@ const struct ioc {
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_VDEV_SETPATH, "ZFS_IOC_VDEV_SETPATH",
"zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_VDEV_SETFRU, "ZFS_IOC_VDEV_SETFRU",
+ "zfs_cmd_t" },
{ (uint_t)ZFS_IOC_OBJSET_STATS, "ZFS_IOC_OBJSET_STATS",
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_OBJSET_ZPLPROPS, "ZFS_IOC_OBJSET_ZPLPROPS",
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c
index afbe53bac2..241a7004f9 100644
--- a/usr/src/cmd/zdb/zdb.c
+++ b/usr/src/cmd/zdb/zdb.c
@@ -2420,7 +2420,7 @@ main(int argc, char **argv)
}
if (error == 0)
- error = spa_import_faulted(argv[0],
+ error = spa_import_verbatim(argv[0],
exported_conf, nvl);
nvlist_free(nvl);
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 62a4f97bf6..79f4bc91aa 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -828,6 +828,7 @@ spa_load_spares(spa_t *spa)
}
vd->vdev_top = vd;
+ vd->vdev_aux = &spa->spa_spares;
if (vdev_open(vd) != 0)
continue;
@@ -1657,6 +1658,8 @@ spa_add_spares(spa_t *spa, nvlist_t *config)
uint_t vsc;
uint64_t pool;
+ ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
+
if (spa->spa_spares.sav_count == 0)
return;
@@ -1704,11 +1707,11 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config)
vdev_stat_t *vs;
uint_t vsc;
+ ASSERT(spa_config_held(spa, SCL_CONFIG, RW_READER));
+
if (spa->spa_l2cache.sav_count == 0)
return;
- spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
-
VERIFY(nvlist_lookup_nvlist(config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
VERIFY(nvlist_lookup_nvlist_array(spa->spa_l2cache.sav_config,
@@ -1742,8 +1745,6 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config)
vdev_get_stats(vd, vs);
}
}
-
- spa_config_exit(spa, SCL_CONFIG, FTAG);
}
int
@@ -1755,16 +1756,27 @@ spa_get_stats(const char *name, nvlist_t **config, char *altroot, size_t buflen)
*config = NULL;
error = spa_open_common(name, &spa, FTAG, config);
- if (spa && *config != NULL) {
- VERIFY(nvlist_add_uint64(*config, ZPOOL_CONFIG_ERRCOUNT,
- spa_get_errlog_size(spa)) == 0);
+ if (spa != NULL) {
+ /*
+ * This still leaves a window of inconsistency where the spares
+ * or l2cache devices could change and the config would be
+ * self-inconsistent.
+ */
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
- if (spa_suspended(spa))
+ if (*config != NULL) {
VERIFY(nvlist_add_uint64(*config,
- ZPOOL_CONFIG_SUSPENDED, spa->spa_failmode) == 0);
+ ZPOOL_CONFIG_ERRCOUNT,
+ spa_get_errlog_size(spa)) == 0);
- spa_add_spares(spa, *config);
- spa_add_l2cache(spa, *config);
+ if (spa_suspended(spa))
+ VERIFY(nvlist_add_uint64(*config,
+ ZPOOL_CONFIG_SUSPENDED,
+ spa->spa_failmode) == 0);
+
+ spa_add_spares(spa, *config);
+ spa_add_l2cache(spa, *config);
+ }
}
/*
@@ -1786,8 +1798,10 @@ spa_get_stats(const char *name, nvlist_t **config, char *altroot, size_t buflen)
}
}
- if (spa != NULL)
+ if (spa != NULL) {
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
spa_close(spa, FTAG);
+ }
return (error);
}
@@ -2174,161 +2188,6 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
return (0);
}
-/*
- * Import the given pool into the system. We set up the necessary spa_t and
- * then call spa_load() to do the dirty work.
- */
-static int
-spa_import_common(const char *pool, nvlist_t *config, nvlist_t *props,
- boolean_t isroot, boolean_t allowfaulted)
-{
- spa_t *spa;
- char *altroot = NULL;
- int error, loaderr;
- nvlist_t *nvroot;
- nvlist_t **spares, **l2cache;
- uint_t nspares, nl2cache;
-
- /*
- * If a pool with this name exists, return failure.
- */
- mutex_enter(&spa_namespace_lock);
- if ((spa = spa_lookup(pool)) != NULL) {
- if (isroot) {
- /*
- * Remove the existing root pool from the
- * namespace so that we can replace it with
- * the correct config we just read in.
- */
- ASSERT(spa->spa_state == POOL_STATE_UNINITIALIZED);
- spa_remove(spa);
- } else {
- mutex_exit(&spa_namespace_lock);
- return (EEXIST);
- }
- }
-
- /*
- * Create and initialize the spa structure.
- */
- (void) nvlist_lookup_string(props,
- zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
- spa = spa_add(pool, altroot);
- spa_activate(spa, spa_mode_global);
-
- if (allowfaulted)
- spa->spa_import_faulted = B_TRUE;
- spa->spa_is_root = isroot;
-
- /*
- * Pass off the heavy lifting to spa_load().
- * Pass TRUE for mosconfig (unless this is a root pool) because
- * the user-supplied config is actually the one to trust when
- * doing an import.
- */
- loaderr = error = spa_load(spa, config, SPA_LOAD_IMPORT, !isroot);
-
- spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
- /*
- * Toss any existing sparelist, as it doesn't have any validity anymore,
- * and conflicts with spa_has_spare().
- */
- if (!isroot && spa->spa_spares.sav_config) {
- nvlist_free(spa->spa_spares.sav_config);
- spa->spa_spares.sav_config = NULL;
- spa_load_spares(spa);
- }
- if (!isroot && spa->spa_l2cache.sav_config) {
- nvlist_free(spa->spa_l2cache.sav_config);
- spa->spa_l2cache.sav_config = NULL;
- spa_load_l2cache(spa);
- }
-
- VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
- &nvroot) == 0);
- if (error == 0)
- error = spa_validate_aux(spa, nvroot, -1ULL, VDEV_ALLOC_SPARE);
- if (error == 0)
- error = spa_validate_aux(spa, nvroot, -1ULL,
- VDEV_ALLOC_L2CACHE);
- spa_config_exit(spa, SCL_ALL, FTAG);
-
- if (props != NULL)
- spa_configfile_set(spa, props, B_FALSE);
-
- if (error != 0 || (props && spa_writeable(spa) &&
- (error = spa_prop_set(spa, props)))) {
- if (loaderr != 0 && loaderr != EINVAL && allowfaulted) {
- /*
- * If we failed to load the pool, but 'allowfaulted' is
- * set, then manually set the config as if the config
- * passed in was specified in the cache file.
- */
- error = 0;
- spa->spa_import_faulted = B_FALSE;
- if (spa->spa_config == NULL)
- spa->spa_config = spa_config_generate(spa,
- NULL, -1ULL, B_TRUE);
- spa_unload(spa);
- spa_deactivate(spa);
- spa_config_sync(spa, B_FALSE, B_TRUE);
- } else {
- spa_unload(spa);
- spa_deactivate(spa);
- spa_remove(spa);
- }
- mutex_exit(&spa_namespace_lock);
- return (error);
- }
-
- /*
- * Override any spares and level 2 cache devices as specified by
- * the user, as these may have correct device names/devids, etc.
- */
- if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
- &spares, &nspares) == 0) {
- if (spa->spa_spares.sav_config)
- VERIFY(nvlist_remove(spa->spa_spares.sav_config,
- ZPOOL_CONFIG_SPARES, DATA_TYPE_NVLIST_ARRAY) == 0);
- else
- VERIFY(nvlist_alloc(&spa->spa_spares.sav_config,
- NV_UNIQUE_NAME, KM_SLEEP) == 0);
- VERIFY(nvlist_add_nvlist_array(spa->spa_spares.sav_config,
- ZPOOL_CONFIG_SPARES, spares, nspares) == 0);
- spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
- spa_load_spares(spa);
- spa_config_exit(spa, SCL_ALL, FTAG);
- spa->spa_spares.sav_sync = B_TRUE;
- }
- if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
- &l2cache, &nl2cache) == 0) {
- if (spa->spa_l2cache.sav_config)
- VERIFY(nvlist_remove(spa->spa_l2cache.sav_config,
- ZPOOL_CONFIG_L2CACHE, DATA_TYPE_NVLIST_ARRAY) == 0);
- else
- VERIFY(nvlist_alloc(&spa->spa_l2cache.sav_config,
- NV_UNIQUE_NAME, KM_SLEEP) == 0);
- VERIFY(nvlist_add_nvlist_array(spa->spa_l2cache.sav_config,
- ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache) == 0);
- spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
- spa_load_l2cache(spa);
- spa_config_exit(spa, SCL_ALL, FTAG);
- spa->spa_l2cache.sav_sync = B_TRUE;
- }
-
- if (spa_writeable(spa)) {
- /*
- * Update the config cache to include the newly-imported pool.
- */
- spa_config_update_common(spa, SPA_CONFIG_UPDATE_POOL, isroot);
- }
-
- spa->spa_import_faulted = B_FALSE;
- mutex_exit(&spa_namespace_lock);
-
- return (0);
-}
-
#ifdef _KERNEL
/*
* Build a "root" vdev for a top level vdev read in from a rootpool
@@ -2506,6 +2365,7 @@ spa_import_rootpool(char *devpath, char *devid)
nvlist_t *conf = NULL;
char *pname;
int error;
+ spa_t *spa;
/*
* Get the vdev pathname and configuation from the most
@@ -2521,17 +2381,23 @@ spa_import_rootpool(char *devpath, char *devid)
VERIFY(nvlist_lookup_string(conf, ZPOOL_CONFIG_POOL_NAME, &pname) == 0);
- /*
- * We specify 'allowfaulted' for this to be treated like spa_open()
- * instead of spa_import(). This prevents us from marking vdevs as
- * persistently unavailable, and generates FMA ereports as if it were a
- * pool open, not import.
- */
- error = spa_import_common(pname, conf, NULL, B_TRUE, B_TRUE);
- ASSERT(error != EEXIST);
+ mutex_enter(&spa_namespace_lock);
+ if ((spa = spa_lookup(pname)) != NULL) {
+ /*
+ * Remove the existing root pool from the namespace so that we
+ * can replace it with the correct config we just read in.
+ */
+ spa_remove(spa);
+ }
+
+ spa = spa_add(pname, NULL);
+
+ spa->spa_is_root = B_TRUE;
+ VERIFY(nvlist_dup(conf, &spa->spa_config, 0) == 0);
+ mutex_exit(&spa_namespace_lock);
nvlist_free(conf);
- return (error);
+ return (0);
msg_out:
cmn_err(CE_NOTE, "\n"
@@ -2546,18 +2412,157 @@ msg_out:
#endif
/*
- * Import a non-root pool into the system.
+ * Take a pool and insert it into the namespace as if it had been loaded at
+ * boot.
*/
int
-spa_import(const char *pool, nvlist_t *config, nvlist_t *props)
+spa_import_verbatim(const char *pool, nvlist_t *config, nvlist_t *props)
{
- return (spa_import_common(pool, config, props, B_FALSE, B_FALSE));
+ spa_t *spa;
+ char *altroot = NULL;
+
+ mutex_enter(&spa_namespace_lock);
+ if (spa_lookup(pool) != NULL) {
+ mutex_exit(&spa_namespace_lock);
+ return (EEXIST);
+ }
+
+ (void) nvlist_lookup_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
+ spa = spa_add(pool, altroot);
+
+ VERIFY(nvlist_dup(config, &spa->spa_config, 0) == 0);
+
+ if (props != NULL)
+ spa_configfile_set(spa, props, B_FALSE);
+
+ spa_config_sync(spa, B_FALSE, B_TRUE);
+
+ mutex_exit(&spa_namespace_lock);
+
+ return (0);
}
+/*
+ * Import a non-root pool into the system.
+ */
int
-spa_import_faulted(const char *pool, nvlist_t *config, nvlist_t *props)
+spa_import(const char *pool, nvlist_t *config, nvlist_t *props)
{
- return (spa_import_common(pool, config, props, B_FALSE, B_TRUE));
+ spa_t *spa;
+ char *altroot = NULL;
+ int error;
+ nvlist_t *nvroot;
+ nvlist_t **spares, **l2cache;
+ uint_t nspares, nl2cache;
+
+ /*
+ * If a pool with this name exists, return failure.
+ */
+ mutex_enter(&spa_namespace_lock);
+ if ((spa = spa_lookup(pool)) != NULL) {
+ mutex_exit(&spa_namespace_lock);
+ return (EEXIST);
+ }
+
+ /*
+ * Create and initialize the spa structure.
+ */
+ (void) nvlist_lookup_string(props,
+ zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
+ spa = spa_add(pool, altroot);
+ spa_activate(spa, spa_mode_global);
+
+ /*
+ * 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.
+ */
+ error = spa_load(spa, config, SPA_LOAD_IMPORT, B_TRUE);
+
+ spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+ /*
+ * Toss any existing sparelist, as it doesn't have any validity
+ * anymore, and conflicts with spa_has_spare().
+ */
+ if (spa->spa_spares.sav_config) {
+ nvlist_free(spa->spa_spares.sav_config);
+ spa->spa_spares.sav_config = NULL;
+ spa_load_spares(spa);
+ }
+ if (spa->spa_l2cache.sav_config) {
+ nvlist_free(spa->spa_l2cache.sav_config);
+ spa->spa_l2cache.sav_config = NULL;
+ spa_load_l2cache(spa);
+ }
+
+ VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ if (error == 0)
+ error = spa_validate_aux(spa, nvroot, -1ULL,
+ VDEV_ALLOC_SPARE);
+ if (error == 0)
+ error = spa_validate_aux(spa, nvroot, -1ULL,
+ VDEV_ALLOC_L2CACHE);
+ spa_config_exit(spa, SCL_ALL, FTAG);
+
+ if (props != NULL)
+ spa_configfile_set(spa, props, B_FALSE);
+
+ if (error != 0 || (props && spa_writeable(spa) &&
+ (error = spa_prop_set(spa, props)))) {
+ spa_unload(spa);
+ spa_deactivate(spa);
+ spa_remove(spa);
+ mutex_exit(&spa_namespace_lock);
+ return (error);
+ }
+
+ /*
+ * Override any spares and level 2 cache devices as specified by
+ * the user, as these may have correct device names/devids, etc.
+ */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ if (spa->spa_spares.sav_config)
+ VERIFY(nvlist_remove(spa->spa_spares.sav_config,
+ ZPOOL_CONFIG_SPARES, DATA_TYPE_NVLIST_ARRAY) == 0);
+ else
+ VERIFY(nvlist_alloc(&spa->spa_spares.sav_config,
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ VERIFY(nvlist_add_nvlist_array(spa->spa_spares.sav_config,
+ ZPOOL_CONFIG_SPARES, spares, nspares) == 0);
+ spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+ spa_load_spares(spa);
+ spa_config_exit(spa, SCL_ALL, FTAG);
+ spa->spa_spares.sav_sync = B_TRUE;
+ }
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0) {
+ if (spa->spa_l2cache.sav_config)
+ VERIFY(nvlist_remove(spa->spa_l2cache.sav_config,
+ ZPOOL_CONFIG_L2CACHE, DATA_TYPE_NVLIST_ARRAY) == 0);
+ else
+ VERIFY(nvlist_alloc(&spa->spa_l2cache.sav_config,
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ VERIFY(nvlist_add_nvlist_array(spa->spa_l2cache.sav_config,
+ ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache) == 0);
+ spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
+ spa_load_l2cache(spa);
+ spa_config_exit(spa, SCL_ALL, FTAG);
+ spa->spa_l2cache.sav_sync = B_TRUE;
+ }
+
+ if (spa_writeable(spa)) {
+ /*
+ * Update the config cache to include the newly-imported pool.
+ */
+ spa_config_update_common(spa, SPA_CONFIG_UPDATE_POOL, B_FALSE);
+ }
+
+ mutex_exit(&spa_namespace_lock);
+
+ return (0);
}
@@ -2643,8 +2648,10 @@ spa_tryimport(nvlist_t *tryconfig)
/*
* Add the list of hot spares and level 2 cache devices.
*/
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
spa_add_spares(spa, config);
spa_add_l2cache(spa, config);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
}
spa_unload(spa);
@@ -3058,8 +3065,11 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
vdev_dtl_dirty(newvd, DTL_MISSING,
TXG_INITIAL, open_txg - TXG_INITIAL + 1);
- if (newvd->vdev_isspare)
+ if (newvd->vdev_isspare) {
spa_spare_activate(newvd);
+ spa_event_notify(spa, newvd, ESC_ZFS_VDEV_SPARE);
+ }
+
oldvdpath = spa_strdup(oldvd->vdev_path);
newvdpath = spa_strdup(newvd->vdev_path);
newvd_isspare = newvd->vdev_isspare;
@@ -3494,59 +3504,50 @@ spa_vdev_resilver_done(spa_t *spa)
}
/*
- * Update the stored path for this vdev. Dirty the vdev configuration, relying
- * on spa_vdev_enter/exit() to synchronize the labels and cache.
+ * Update the stored path or FRU for this vdev. Dirty the vdev configuration,
+ * relying on spa_vdev_enter/exit() to synchronize the labels and cache.
*/
int
-spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath)
+spa_vdev_set_common(spa_t *spa, uint64_t guid, const char *value,
+ boolean_t ispath)
{
vdev_t *vd;
uint64_t txg;
txg = spa_vdev_enter(spa);
- if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL) {
- /*
- * Determine if this is a reference to a hot spare device. If
- * it is, update the path manually as there is no associated
- * vdev_t that can be synced to disk.
- */
- nvlist_t **spares;
- uint_t i, nspares;
-
- if (spa->spa_spares.sav_config != NULL) {
- VERIFY(nvlist_lookup_nvlist_array(
- spa->spa_spares.sav_config, ZPOOL_CONFIG_SPARES,
- &spares, &nspares) == 0);
- for (i = 0; i < nspares; i++) {
- uint64_t theguid;
- VERIFY(nvlist_lookup_uint64(spares[i],
- ZPOOL_CONFIG_GUID, &theguid) == 0);
- if (theguid == guid) {
- VERIFY(nvlist_add_string(spares[i],
- ZPOOL_CONFIG_PATH, newpath) == 0);
- spa_load_spares(spa);
- spa->spa_spares.sav_sync = B_TRUE;
- return (spa_vdev_exit(spa, NULL, txg,
- 0));
- }
- }
- }
-
+ if ((vd = spa_lookup_by_guid(spa, guid, B_TRUE)) == NULL)
return (spa_vdev_exit(spa, NULL, txg, ENOENT));
- }
if (!vd->vdev_ops->vdev_op_leaf)
return (spa_vdev_exit(spa, NULL, txg, ENOTSUP));
- spa_strfree(vd->vdev_path);
- vd->vdev_path = spa_strdup(newpath);
+ if (ispath) {
+ spa_strfree(vd->vdev_path);
+ vd->vdev_path = spa_strdup(value);
+ } else {
+ if (vd->vdev_fru != NULL)
+ spa_strfree(vd->vdev_fru);
+ vd->vdev_fru = spa_strdup(value);
+ }
vdev_config_dirty(vd->vdev_top);
return (spa_vdev_exit(spa, NULL, txg, 0));
}
+int
+spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath)
+{
+ return (spa_vdev_set_common(spa, guid, newpath, B_TRUE));
+}
+
+int
+spa_vdev_setfru(spa_t *spa, uint64_t guid, const char *newfru)
+{
+ return (spa_vdev_set_common(spa, guid, newfru, B_FALSE));
+}
+
/*
* ==========================================================================
* SPA Scrubbing
@@ -4258,7 +4259,7 @@ spa_evict_all(void)
}
vdev_t *
-spa_lookup_by_guid(spa_t *spa, uint64_t guid, boolean_t l2cache)
+spa_lookup_by_guid(spa_t *spa, uint64_t guid, boolean_t aux)
{
vdev_t *vd;
int i;
@@ -4266,12 +4267,18 @@ spa_lookup_by_guid(spa_t *spa, uint64_t guid, boolean_t l2cache)
if ((vd = vdev_lookup_by_guid(spa->spa_root_vdev, guid)) != NULL)
return (vd);
- if (l2cache) {
+ if (aux) {
for (i = 0; i < spa->spa_l2cache.sav_count; i++) {
vd = spa->spa_l2cache.sav_vdevs[i];
if (vd->vdev_guid == guid)
return (vd);
}
+
+ for (i = 0; i < spa->spa_spares.sav_count; i++) {
+ vd = spa->spa_spares.sav_vdevs[i];
+ if (vd->vdev_guid == guid)
+ return (vd);
+ }
}
return (NULL);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index 029123dfe6..fff55f90a2 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -329,7 +329,7 @@ extern int spa_check_rootconf(char *devpath, char *devid,
extern boolean_t spa_rootdev_validate(nvlist_t *nv);
extern int spa_import_rootpool(char *devpath, char *devid);
extern int spa_import(const char *pool, nvlist_t *config, nvlist_t *props);
-extern int spa_import_faulted(const char *, nvlist_t *, nvlist_t *);
+extern int spa_import_verbatim(const char *, nvlist_t *, nvlist_t *);
extern nvlist_t *spa_tryimport(nvlist_t *tryconfig);
extern int spa_destroy(char *pool);
extern int spa_export(char *pool, nvlist_t **oldconfig, boolean_t force,
@@ -356,6 +356,7 @@ extern int spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid,
int replace_done);
extern int spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare);
extern int spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath);
+extern int spa_vdev_setfru(spa_t *spa, uint64_t guid, const char *newfru);
/* spare state (which is global across all pools) */
extern void spa_spare_add(vdev_t *vd);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
index 843202eb6c..543a91df27 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
@@ -165,7 +165,6 @@ struct spa {
kmutex_t spa_suspend_lock; /* protects suspend_zio_root */
kcondvar_t spa_suspend_cv; /* notification of resume */
uint8_t spa_suspended; /* pool is suspended */
- boolean_t spa_import_faulted; /* allow faulted vdevs */
boolean_t spa_is_root; /* pool is root */
int spa_minref; /* num refs when first opened */
int spa_mode; /* FREAD | FWRITE */
diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
index a6c144be7f..32a83b801b 100644
--- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
@@ -159,6 +159,7 @@ struct vdev {
char *vdev_path; /* vdev path (if any) */
char *vdev_devid; /* vdev devid (if any) */
char *vdev_physpath; /* vdev device path (if any) */
+ char *vdev_fru; /* physical FRU location */
uint64_t vdev_not_present; /* not present during import */
uint64_t vdev_unspare; /* unspare when resilvering done */
hrtime_t vdev_last_try; /* last reopen time */
diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c
index c9879ccdfe..164883d268 100644
--- a/usr/src/uts/common/fs/zfs/vdev.c
+++ b/usr/src/uts/common/fs/zfs/vdev.c
@@ -435,6 +435,8 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PHYS_PATH,
&vd->vdev_physpath) == 0)
vd->vdev_physpath = spa_strdup(vd->vdev_physpath);
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_FRU, &vd->vdev_fru) == 0)
+ vd->vdev_fru = spa_strdup(vd->vdev_fru);
/*
* Set the whole_disk property. If it's not specified, leave the value
@@ -448,9 +450,8 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
* Look for the 'not present' flag. This will only be set if the device
* was not present at the time of import.
*/
- if (!spa->spa_import_faulted)
- (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
- &vd->vdev_not_present);
+ (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
+ &vd->vdev_not_present);
/*
* Get the alignment requirement.
@@ -560,6 +561,8 @@ vdev_free(vdev_t *vd)
spa_strfree(vd->vdev_devid);
if (vd->vdev_physpath)
spa_strfree(vd->vdev_physpath);
+ if (vd->vdev_fru)
+ spa_strfree(vd->vdev_fru);
if (vd->vdev_isspare)
spa_spare_remove(vd);
@@ -1257,6 +1260,7 @@ vdev_reopen(vdev_t *vd)
if (vd->vdev_aux) {
(void) vdev_validate_aux(vd);
if (vdev_readable(vd) && vdev_writeable(vd) &&
+ vd->vdev_aux == &spa->spa_l2cache &&
!l2arc_vdev_present(vd)) {
uint64_t size = vdev_get_rsize(vd);
l2arc_add_vdev(spa, vd,
@@ -2293,8 +2297,8 @@ vdev_config_dirty(vdev_t *vd)
int c;
/*
- * If this is an aux vdev (as with l2cache devices), then we update the
- * vdev config manually and set the sync flag.
+ * If this is an aux vdev (as with l2cache and spare devices), then we
+ * update the vdev config manually and set the sync flag.
*/
if (vd->vdev_aux != NULL) {
spa_aux_vdev_t *sav = vd->vdev_aux;
@@ -2316,8 +2320,11 @@ vdev_config_dirty(vdev_t *vd)
sav->sav_sync = B_TRUE;
- VERIFY(nvlist_lookup_nvlist_array(sav->sav_config,
- ZPOOL_CONFIG_L2CACHE, &aux, &naux) == 0);
+ if (nvlist_lookup_nvlist_array(sav->sav_config,
+ ZPOOL_CONFIG_L2CACHE, &aux, &naux) != 0) {
+ VERIFY(nvlist_lookup_nvlist_array(sav->sav_config,
+ ZPOOL_CONFIG_SPARES, &aux, &naux) == 0);
+ }
ASSERT(c < naux);
@@ -2523,7 +2530,6 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
* an error.
*/
if (spa->spa_load_state == SPA_LOAD_IMPORT &&
- !spa->spa_import_faulted &&
vd->vdev_ops->vdev_op_leaf)
vd->vdev_not_present = 1;
diff --git a/usr/src/uts/common/fs/zfs/vdev_label.c b/usr/src/uts/common/fs/zfs/vdev_label.c
index 5bc7301544..f1f3bb0066 100644
--- a/usr/src/uts/common/fs/zfs/vdev_label.c
+++ b/usr/src/uts/common/fs/zfs/vdev_label.c
@@ -233,6 +233,10 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
VERIFY(nvlist_add_string(nv, ZPOOL_CONFIG_PHYS_PATH,
vd->vdev_physpath) == 0);
+ if (vd->vdev_fru != NULL)
+ VERIFY(nvlist_add_string(nv, ZPOOL_CONFIG_FRU,
+ vd->vdev_fru) == 0);
+
if (vd->vdev_nparity != 0) {
ASSERT(strcmp(vd->vdev_ops->vdev_op_type,
VDEV_TYPE_RAIDZ) == 0);
diff --git a/usr/src/uts/common/fs/zfs/zfs_fm.c b/usr/src/uts/common/fs/zfs/zfs_fm.c
index 236d69e7e6..6a476c527d 100644
--- a/usr/src/uts/common/fs/zfs/zfs_fm.c
+++ b/usr/src/uts/common/fs/zfs/zfs_fm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -96,7 +96,6 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
nvlist_t *ereport, *detector;
uint64_t ena;
char class[64];
- int state;
/*
* If we are doing a spa_tryimport(), ignore errors.
@@ -129,16 +128,31 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
if (zio->io_flags & ZIO_FLAG_SPECULATIVE)
return;
- /*
- * If the vdev has already been marked as failing due to a
- * failed probe, then ignore any subsequent I/O errors, as the
- * DE will automatically fault the vdev on the first such
- * failure.
- */
- if (vd != NULL &&
- (!vdev_readable(vd) || !vdev_writeable(vd)) &&
- strcmp(subclass, FM_EREPORT_ZFS_PROBE_FAILURE) != 0)
- return;
+ if (vd != NULL) {
+ /*
+ * If the vdev has already been marked as failing due
+ * to a failed probe, then ignore any subsequent I/O
+ * errors, as the DE will automatically fault the vdev
+ * on the first such failure. This also catches cases
+ * where vdev_remove_wanted is set and the device has
+ * not yet been asynchronously placed into the REMOVED
+ * state.
+ */
+ if (zio->io_vd == vd &&
+ !vdev_accessible(vd, zio) &&
+ strcmp(subclass, FM_EREPORT_ZFS_PROBE_FAILURE) != 0)
+ return;
+
+ /*
+ * Ignore checksum errors for reads from DTL regions of
+ * leaf vdevs.
+ */
+ if (zio->io_type == ZIO_TYPE_READ &&
+ zio->io_error == ECKSUM &&
+ vd->vdev_ops->vdev_op_leaf &&
+ vdev_dtl_contains(vd, DTL_MISSING, zio->io_txg, 1))
+ return;
+ }
}
if ((ereport = fm_nvlist_create(NULL)) == NULL)
@@ -189,21 +203,13 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
*/
/*
- * If we are importing a faulted pool, then we treat it like an open,
- * not an import. Otherwise, the DE will ignore all faults during
- * import, since the default behavior is to mark the devices as
- * persistently unavailable, not leave them in the faulted state.
- */
- state = spa->spa_import_faulted ? SPA_LOAD_OPEN : spa->spa_load_state;
-
- /*
* Generic payload members common to all ereports.
*/
fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_POOL,
DATA_TYPE_STRING, spa_name(spa), FM_EREPORT_PAYLOAD_ZFS_POOL_GUID,
DATA_TYPE_UINT64, spa_guid(spa),
FM_EREPORT_PAYLOAD_ZFS_POOL_CONTEXT, DATA_TYPE_INT32,
- state, NULL);
+ spa->spa_load_state, NULL);
if (spa != NULL) {
fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_POOL_FAILMODE,
@@ -222,14 +228,18 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
DATA_TYPE_UINT64, vd->vdev_guid,
FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE,
DATA_TYPE_STRING, vd->vdev_ops->vdev_op_type, NULL);
- if (vd->vdev_path)
+ if (vd->vdev_path != NULL)
fm_payload_set(ereport,
FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH,
DATA_TYPE_STRING, vd->vdev_path, NULL);
- if (vd->vdev_devid)
+ if (vd->vdev_devid != NULL)
fm_payload_set(ereport,
FM_EREPORT_PAYLOAD_ZFS_VDEV_DEVID,
DATA_TYPE_STRING, vd->vdev_devid, NULL);
+ if (vd->vdev_fru != NULL)
+ fm_payload_set(ereport,
+ FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU,
+ DATA_TYPE_STRING, vd->vdev_fru, NULL);
if (pvd != NULL) {
fm_payload_set(ereport,
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 239b1e0baf..5b2a406276 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -981,7 +981,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
guid != zc->zc_guid)
error = EINVAL;
else if (zc->zc_cookie)
- error = spa_import_faulted(zc->zc_name, config,
+ error = spa_import_verbatim(zc->zc_name, config,
props);
else
error = spa_import(zc->zc_name, config, props);
@@ -1329,6 +1329,23 @@ zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
return (error);
}
+static int
+zfs_ioc_vdev_setfru(zfs_cmd_t *zc)
+{
+ spa_t *spa;
+ char *fru = zc->zc_value;
+ uint64_t guid = zc->zc_guid;
+ int error;
+
+ error = spa_open(zc->zc_name, &spa, FTAG);
+ if (error != 0)
+ return (error);
+
+ error = spa_vdev_setfru(spa, guid, fru);
+ spa_close(spa, FTAG);
+ return (error);
+}
+
/*
* inputs:
* zc_name name of filesystem
@@ -3451,6 +3468,8 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
B_TRUE },
{ zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE,
B_TRUE },
+ { zfs_ioc_vdev_setfru, zfs_secpolicy_config, POOL_NAME, B_FALSE,
+ B_TRUE },
{ zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
B_FALSE },
{ zfs_ioc_objset_zplprops, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
diff --git a/usr/src/uts/common/sys/fm/fs/zfs.h b/usr/src/uts/common/sys/fm/fs/zfs.h
index 66ca9c5d71..21b7dbe52c 100644
--- a/usr/src/uts/common/sys/fm/fs/zfs.h
+++ b/usr/src/uts/common/sys/fm/fs/zfs.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_FM_FS_ZFS_H
#define _SYS_FM_FS_ZFS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -57,6 +55,7 @@ extern "C" {
#define FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE "vdev_type"
#define FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH "vdev_path"
#define FM_EREPORT_PAYLOAD_ZFS_VDEV_DEVID "vdev_devid"
+#define FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU "vdev_fru"
#define FM_EREPORT_PAYLOAD_ZFS_PARENT_GUID "parent_guid"
#define FM_EREPORT_PAYLOAD_ZFS_PARENT_TYPE "parent_type"
#define FM_EREPORT_PAYLOAD_ZFS_PARENT_PATH "parent_path"
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index cb05176292..5b09587472 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -388,6 +388,7 @@ typedef enum zfs_cache_type {
#define ZPOOL_CONFIG_FAULTED "faulted"
#define ZPOOL_CONFIG_DEGRADED "degraded"
#define ZPOOL_CONFIG_REMOVED "removed"
+#define ZPOOL_CONFIG_FRU "fru"
#define VDEV_TYPE_ROOT "root"
#define VDEV_TYPE_MIRROR "mirror"
@@ -558,6 +559,7 @@ typedef enum zfs_ioc {
ZFS_IOC_VDEV_ATTACH,
ZFS_IOC_VDEV_DETACH,
ZFS_IOC_VDEV_SETPATH,
+ ZFS_IOC_VDEV_SETFRU,
ZFS_IOC_OBJSET_STATS,
ZFS_IOC_OBJSET_ZPLPROPS,
ZFS_IOC_DATASET_LIST_NEXT,
diff --git a/usr/src/uts/common/sys/sysevent/eventdefs.h b/usr/src/uts/common/sys/sysevent/eventdefs.h
index 2a96996f10..917a9b2f49 100644
--- a/usr/src/uts/common/sys/sysevent/eventdefs.h
+++ b/usr/src/uts/common/sys/sysevent/eventdefs.h
@@ -247,6 +247,7 @@ extern "C" {
#define ESC_ZFS_CONFIG_SYNC "ESC_ZFS_config_sync"
#define ESC_ZFS_SCRUB_START "ESC_ZFS_scrub_start"
#define ESC_ZFS_SCRUB_FINISH "ESC_ZFS_scrub_finish"
+#define ESC_ZFS_VDEV_SPARE "ESC_ZFS_vdev_spare"
/*
* datalink subclass definitions.