summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/spa.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/zfs/spa.c')
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c54
1 files changed, 48 insertions, 6 deletions
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index a838b0f45b..a780a2ca1f 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -362,6 +362,27 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
dmu_objset_close(os);
}
break;
+ case ZPOOL_PROP_FAILUREMODE:
+ error = nvpair_value_uint64(elem, &intval);
+ if (!error && (intval < ZIO_FAILURE_MODE_WAIT ||
+ intval > ZIO_FAILURE_MODE_PANIC))
+ error = EINVAL;
+
+ /*
+ * 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
+ * without syncing it out to disk (I/Os might
+ * 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.
+ */
+ if (!error && spa_state(spa) == POOL_STATE_IO_FAILURE) {
+ spa->spa_failmode = intval;
+ error = EIO;
+ }
+ break;
}
if (error)
@@ -477,6 +498,8 @@ spa_activate(spa_t *spa)
list_create(&spa->spa_dirty_list, sizeof (vdev_t),
offsetof(vdev_t, vdev_dirty_node));
+ list_create(&spa->spa_zio_list, sizeof (zio_t),
+ offsetof(zio_t, zio_link_node));
txg_list_create(&spa->spa_vdev_txg_list,
offsetof(struct vdev, vdev_txg_node));
@@ -506,6 +529,7 @@ spa_deactivate(spa_t *spa)
txg_list_destroy(&spa->spa_vdev_txg_list);
list_destroy(&spa->spa_dirty_list);
+ list_destroy(&spa->spa_zio_list);
for (t = 0; t < ZIO_TYPES; t++) {
taskq_destroy(spa->spa_zio_issue_taskq[t]);
@@ -1077,6 +1101,10 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig)
spa->spa_pool_props_object,
zpool_prop_to_name(ZPOOL_PROP_DELEGATION),
sizeof (uint64_t), 1, &spa->spa_delegation);
+ (void) zap_lookup(spa->spa_meta_objset,
+ spa->spa_pool_props_object,
+ zpool_prop_to_name(ZPOOL_PROP_FAILUREMODE),
+ sizeof (uint64_t), 1, &spa->spa_failmode);
}
/*
@@ -1618,6 +1646,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
spa->spa_bootfs = zpool_prop_default_numeric(ZPOOL_PROP_BOOTFS);
spa->spa_delegation = zpool_prop_default_numeric(ZPOOL_PROP_DELEGATION);
spa->spa_temporary = zpool_prop_default_numeric(ZPOOL_PROP_TEMPORARY);
+ spa->spa_failmode = zpool_prop_default_numeric(ZPOOL_PROP_FAILUREMODE);
if (props)
spa_sync_props(spa, props, CRED(), tx);
@@ -3091,7 +3120,7 @@ spa_async_remove(spa_t *spa, vdev_t *vd)
tvd->vdev_remove_wanted = 0;
vdev_set_state(tvd, B_FALSE, VDEV_STATE_REMOVED,
VDEV_AUX_NONE);
- vdev_clear(spa, tvd);
+ vdev_clear(spa, tvd, B_TRUE);
vdev_config_dirty(tvd->vdev_top);
}
spa_async_remove(spa, tvd);
@@ -3122,8 +3151,14 @@ spa_async_thread(spa_t *spa)
/*
* See if any devices need to be marked REMOVED.
+ *
+ * XXX - We avoid doing this when we are in
+ * I/O failure state since spa_vdev_enter() grabs
+ * the namespace lock and would not be able to obtain
+ * the writer config lock.
*/
- if (tasks & SPA_ASYNC_REMOVE) {
+ if (tasks & SPA_ASYNC_REMOVE &&
+ spa_state(spa) != POOL_STATE_IO_FAILURE) {
txg = spa_vdev_enter(spa);
spa_async_remove(spa, spa->spa_root_vdev);
(void) spa_vdev_exit(spa, NULL, txg, 0);
@@ -3379,7 +3414,6 @@ spa_sync_props(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
VERIFY(nvpair_value_uint64(elem, &intval) == 0);
spa->spa_temporary = intval;
break;
-
default:
/*
* Set pool property values in the poolprops mos object.
@@ -3425,11 +3459,19 @@ spa_sync_props(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
ASSERT(0); /* not allowed */
}
- if (prop == ZPOOL_PROP_DELEGATION)
+ switch (prop) {
+ case ZPOOL_PROP_DELEGATION:
spa->spa_delegation = intval;
-
- if (prop == ZPOOL_PROP_BOOTFS)
+ break;
+ case ZPOOL_PROP_BOOTFS:
spa->spa_bootfs = intval;
+ break;
+ case ZPOOL_PROP_FAILUREMODE:
+ spa->spa_failmode = intval;
+ break;
+ default:
+ break;
+ }
}
/* log internal history if this is not a zpool create */