Skip to content

Commit

Permalink
Add the ability to uninitialize
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Rich Ercolani <[email protected]>
  • Loading branch information
rincebrain committed Sep 22, 2021
1 parent df5ea74 commit 910b104
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 9 deletions.
22 changes: 17 additions & 5 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ get_usage(zpool_help_t idx)
case HELP_REOPEN:
return (gettext("\treopen [-n] <pool>\n"));
case HELP_INITIALIZE:
return (gettext("\tinitialize [-c | -s] [-w] <pool> "
return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> "
"[<device> ...]\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s | -p] [-w] <pool> ...\n"));
Expand Down Expand Up @@ -552,12 +552,13 @@ usage(boolean_t requested)
}

/*
* zpool initialize [-c | -s] [-w] <pool> [<vdev> ...]
* zpool initialize [-c | -s | -u] [-w] <pool> [<vdev> ...]
* Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
* if none specified.
*
* -c Cancel. Ends active initializing.
* -s Suspend. Initializing can then be restarted with no flags.
* -u Uninitialize. Clears initialization state.
* -w Wait. Blocks until initializing has completed.
*/
int
Expand All @@ -573,12 +574,14 @@ zpool_do_initialize(int argc, char **argv)
struct option long_options[] = {
{"cancel", no_argument, NULL, 'c'},
{"suspend", no_argument, NULL, 's'},
{"uninit", no_argument, NULL, 'u'},
{"wait", no_argument, NULL, 'w'},
{0, 0, 0, 0}
};

pool_initialize_func_t cmd_type = POOL_INITIALIZE_START;
while ((c = getopt_long(argc, argv, "csw", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "csuw", long_options,
NULL)) != -1) {
switch (c) {
case 'c':
if (cmd_type != POOL_INITIALIZE_START &&
Expand All @@ -598,6 +601,15 @@ zpool_do_initialize(int argc, char **argv)
}
cmd_type = POOL_INITIALIZE_SUSPEND;
break;
case 'u':
if (cmd_type != POOL_INITIALIZE_START &&
cmd_type != POOL_INITIALIZE_UNINIT) {
(void) fprintf(stderr, gettext("-u cannot be "
"combined with other options\n"));
usage(B_FALSE);
}
cmd_type = POOL_INITIALIZE_UNINIT;
break;
case 'w':
wait = B_TRUE;
break;
Expand All @@ -624,8 +636,8 @@ zpool_do_initialize(int argc, char **argv)
}

if (wait && (cmd_type != POOL_INITIALIZE_START)) {
(void) fprintf(stderr, gettext("-w cannot be used with -c or "
"-s\n"));
(void) fprintf(stderr, gettext("-w cannot be used with -c, -s"
"or -u\n"));
usage(B_FALSE);
}

Expand Down
4 changes: 3 additions & 1 deletion include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,7 @@ typedef enum pool_initialize_func {
POOL_INITIALIZE_START,
POOL_INITIALIZE_CANCEL,
POOL_INITIALIZE_SUSPEND,
POOL_INITIALIZE_UNINIT,
POOL_INITIALIZE_FUNCS
} pool_initialize_func_t;

Expand Down Expand Up @@ -1237,7 +1238,8 @@ typedef enum {
VDEV_INITIALIZE_ACTIVE,
VDEV_INITIALIZE_CANCELED,
VDEV_INITIALIZE_SUSPENDED,
VDEV_INITIALIZE_COMPLETE
VDEV_INITIALIZE_COMPLETE,
VDEV_INITIALIZE_UNINIT
} vdev_initializing_state_t;

typedef enum {
Expand Down
1 change: 1 addition & 0 deletions include/sys/vdev_initialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ extern "C" {
#endif

extern void vdev_initialize(vdev_t *vd);
extern void vdev_uninitialize(vdev_t *vd);
extern void vdev_initialize_stop(vdev_t *vd,
vdev_initializing_state_t tgt_state, list_t *vd_list);
extern void vdev_initialize_stop_all(vdev_t *vd,
Expand Down
7 changes: 7 additions & 0 deletions module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -7255,6 +7255,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) {
Expand All @@ -7267,6 +7271,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);
}
Expand Down
39 changes: 37 additions & 2 deletions module/zfs/vdev_initialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,19 @@ vdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx)

objset_t *mos = vd->vdev_spa->spa_meta_objset;

if (last_offset > 0) {
uint64_t initialize_state = vd->vdev_initialize_state;

/*
* XXX: need to double-check that there's really no way around this
*
* It turns out we call this with last_offset = 0 and
* VDEV_INITIALIZE_NONE when resuming, so we can't just lob
* VDEV_INITIALIZE_NONE out if we see it or we'll clobber that.
*/
if (last_offset > 0 || initialize_state == VDEV_INITIALIZE_UNINIT) {
if (initialize_state == VDEV_INITIALIZE_UNINIT) {
vd->vdev_initialize_state = VDEV_INITIALIZE_NONE;
}
vd->vdev_initialize_last_offset = last_offset;
VERIFY0(zap_update(mos, vd->vdev_leaf_zap,
VDEV_LEAF_ZAP_INITIALIZE_LAST_OFFSET,
Expand All @@ -94,7 +106,7 @@ vdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx)
1, &val, tx));
}

uint64_t initialize_state = vd->vdev_initialize_state;
initialize_state = vd->vdev_initialize_state;
VERIFY0(zap_update(mos, vd->vdev_leaf_zap,
VDEV_LEAF_ZAP_INITIALIZE_STATE, sizeof (initialize_state), 1,
&initialize_state, tx));
Expand Down Expand Up @@ -149,6 +161,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_UNINIT:
spa_history_log_internal(spa, "uninitialize", tx,
"vdev=%s", vd->vdev_path);
break;
default:
panic("invalid state %llu", (unsigned long long)new_state);
}
Expand Down Expand Up @@ -603,6 +619,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_UNINIT);
}

/*
* Wait for the initialize thread to be terminated (cancelled or stopped).
*/
Expand Down Expand Up @@ -758,6 +792,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);
Expand Down
3 changes: 2 additions & 1 deletion module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3981,7 +3981,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));
}

Expand Down

0 comments on commit 910b104

Please sign in to comment.