diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/truss/codes.c | 2 | ||||
-rw-r--r-- | usr/src/cmd/zdb/zdb.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 443 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa_impl.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/vdev_impl.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev.c | 22 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_label.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_fm.c | 56 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ioctl.c | 21 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fm/fs/zfs.h | 5 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fs/zfs.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sysevent/eventdefs.h | 1 |
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. |