mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 18:40:43 +03:00
Add the ability to uninitialize
zpool initialize functions well for touching every free byte...once. But if we want to do it again, we're currently out of luck. So let's add zpool initialize -u to clear it. Co-authored-by: Rich Ercolani <rincebrain@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Rich Ercolani <rincebrain@gmail.com> Closes #12451 Closes #14873
This commit is contained in:
@@ -7421,6 +7421,10 @@ spa_vdev_initialize_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type,
|
||||
vd->vdev_initialize_state != VDEV_INITIALIZE_ACTIVE) {
|
||||
mutex_exit(&vd->vdev_initialize_lock);
|
||||
return (SET_ERROR(ESRCH));
|
||||
} else if (cmd_type == POOL_INITIALIZE_UNINIT &&
|
||||
vd->vdev_initialize_thread != NULL) {
|
||||
mutex_exit(&vd->vdev_initialize_lock);
|
||||
return (SET_ERROR(EBUSY));
|
||||
}
|
||||
|
||||
switch (cmd_type) {
|
||||
@@ -7433,6 +7437,9 @@ spa_vdev_initialize_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type,
|
||||
case POOL_INITIALIZE_SUSPEND:
|
||||
vdev_initialize_stop(vd, VDEV_INITIALIZE_SUSPENDED, vd_list);
|
||||
break;
|
||||
case POOL_INITIALIZE_UNINIT:
|
||||
vdev_uninitialize(vd);
|
||||
break;
|
||||
default:
|
||||
panic("invalid cmd_type %llu", (unsigned long long)cmd_type);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,39 @@ vdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx)
|
||||
&initialize_state, tx));
|
||||
}
|
||||
|
||||
static void
|
||||
vdev_initialize_zap_remove_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
uint64_t guid = *(uint64_t *)arg;
|
||||
|
||||
kmem_free(arg, sizeof (uint64_t));
|
||||
|
||||
vdev_t *vd = spa_lookup_by_guid(tx->tx_pool->dp_spa, guid, B_FALSE);
|
||||
if (vd == NULL || vd->vdev_top->vdev_removing || !vdev_is_concrete(vd))
|
||||
return;
|
||||
|
||||
ASSERT3S(vd->vdev_initialize_state, ==, VDEV_INITIALIZE_NONE);
|
||||
ASSERT3U(vd->vdev_leaf_zap, !=, 0);
|
||||
|
||||
vd->vdev_initialize_last_offset = 0;
|
||||
vd->vdev_initialize_action_time = 0;
|
||||
|
||||
objset_t *mos = vd->vdev_spa->spa_meta_objset;
|
||||
int error;
|
||||
|
||||
error = zap_remove(mos, vd->vdev_leaf_zap,
|
||||
VDEV_LEAF_ZAP_INITIALIZE_LAST_OFFSET, tx);
|
||||
VERIFY(error == 0 || error == ENOENT);
|
||||
|
||||
error = zap_remove(mos, vd->vdev_leaf_zap,
|
||||
VDEV_LEAF_ZAP_INITIALIZE_STATE, tx);
|
||||
VERIFY(error == 0 || error == ENOENT);
|
||||
|
||||
error = zap_remove(mos, vd->vdev_leaf_zap,
|
||||
VDEV_LEAF_ZAP_INITIALIZE_ACTION_TIME, tx);
|
||||
VERIFY(error == 0 || error == ENOENT);
|
||||
}
|
||||
|
||||
static void
|
||||
vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state)
|
||||
{
|
||||
@@ -123,8 +156,14 @@ vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state)
|
||||
|
||||
dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
|
||||
VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
|
||||
dsl_sync_task_nowait(spa_get_dsl(spa), vdev_initialize_zap_update_sync,
|
||||
guid, tx);
|
||||
|
||||
if (new_state != VDEV_INITIALIZE_NONE) {
|
||||
dsl_sync_task_nowait(spa_get_dsl(spa),
|
||||
vdev_initialize_zap_update_sync, guid, tx);
|
||||
} else {
|
||||
dsl_sync_task_nowait(spa_get_dsl(spa),
|
||||
vdev_initialize_zap_remove_sync, guid, tx);
|
||||
}
|
||||
|
||||
switch (new_state) {
|
||||
case VDEV_INITIALIZE_ACTIVE:
|
||||
@@ -145,6 +184,10 @@ vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state)
|
||||
spa_history_log_internal(spa, "initialize", tx,
|
||||
"vdev=%s complete", vd->vdev_path);
|
||||
break;
|
||||
case VDEV_INITIALIZE_NONE:
|
||||
spa_history_log_internal(spa, "uninitialize", tx,
|
||||
"vdev=%s", vd->vdev_path);
|
||||
break;
|
||||
default:
|
||||
panic("invalid state %llu", (unsigned long long)new_state);
|
||||
}
|
||||
@@ -594,6 +637,24 @@ vdev_initialize(vdev_t *vd)
|
||||
vdev_initialize_thread, vd, 0, &p0, TS_RUN, maxclsyspri);
|
||||
}
|
||||
|
||||
/*
|
||||
* Uninitializes a device. Caller must hold vdev_initialize_lock.
|
||||
* Device must be a leaf and not already be initializing.
|
||||
*/
|
||||
void
|
||||
vdev_uninitialize(vdev_t *vd)
|
||||
{
|
||||
ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock));
|
||||
ASSERT(vd->vdev_ops->vdev_op_leaf);
|
||||
ASSERT(vdev_is_concrete(vd));
|
||||
ASSERT3P(vd->vdev_initialize_thread, ==, NULL);
|
||||
ASSERT(!vd->vdev_detached);
|
||||
ASSERT(!vd->vdev_initialize_exit_wanted);
|
||||
ASSERT(!vd->vdev_top->vdev_removing);
|
||||
|
||||
vdev_initialize_change_state(vd, VDEV_INITIALIZE_NONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the initialize thread to be terminated (cancelled or stopped).
|
||||
*/
|
||||
@@ -750,6 +811,7 @@ vdev_initialize_restart(vdev_t *vd)
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vdev_initialize);
|
||||
EXPORT_SYMBOL(vdev_uninitialize);
|
||||
EXPORT_SYMBOL(vdev_initialize_stop);
|
||||
EXPORT_SYMBOL(vdev_initialize_stop_all);
|
||||
EXPORT_SYMBOL(vdev_initialize_stop_wait);
|
||||
|
||||
@@ -4070,7 +4070,8 @@ zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
|
||||
if (!(cmd_type == POOL_INITIALIZE_CANCEL ||
|
||||
cmd_type == POOL_INITIALIZE_START ||
|
||||
cmd_type == POOL_INITIALIZE_SUSPEND)) {
|
||||
cmd_type == POOL_INITIALIZE_SUSPEND ||
|
||||
cmd_type == POOL_INITIALIZE_UNINIT)) {
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user