diff options
author | George Wilson <[email protected]> | 2018-12-19 09:20:39 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-01-07 11:03:08 -0800 |
commit | c10d37dd9f5d56e19330add732f1a713250d24f7 (patch) | |
tree | a43f6b7c1592612fe4277bcaf5d99c02543523b8 /module/zfs/zfs_ioctl.c | |
parent | 619f09769393d4e0cbaa5f662362138e1c699159 (diff) |
zfs initialize performance enhancements
PROBLEM
========
When invoking "zpool initialize" on a pool the command will
create a thread to initialize each disk. Unfortunately, it does
this serially across many transaction groups which can result
in commands taking a long time to return to the user and may
appear hung. The same thing is true when trying to suspend/cancel
the operation.
SOLUTION
=========
This change refactors the way we invoke the initialize interface
to ensure we can start or stop the intialization in just a few
transaction groups.
When stopping or cancelling a vdev initialization perform it
in two phases. First signal each vdev initialization thread
that it should exit, then after all threads have been signaled
wait for them to exit.
On a pool with 40 leaf vdevs this reduces the vdev initialize
stop/cancel time from ~10 minutes to under a second. The reason
for this is spa_vdev_initialize() no longer needs to wait on
multiple full TXGs per leaf vdev being stopped.
This commit additionally adds some missing checks for the passed
"initialize_vdevs" input nvlist. The contents of the user provided
input "initialize_vdevs" nvlist must be validated to ensure all
values are uint64s. This is done in zfs_ioc_pool_initialize() in
order to keep all of these checks in a single location.
Updated the innvl and outnvl comments to match the formatting used
for all other new sytle ioctls.
Reviewed by: Matt Ahrens <[email protected]>
Reviewed-by: loli10K <[email protected]>
Reviewed-by: Tim Chase <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Signed-off-by: George Wilson <[email protected]>
Closes #8230
Diffstat (limited to 'module/zfs/zfs_ioctl.c')
-rw-r--r-- | module/zfs/zfs_ioctl.c | 57 |
1 files changed, 26 insertions, 31 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 3c36502d8..0dfa01684 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3846,73 +3846,68 @@ zfs_ioc_destroy(zfs_cmd_t *zc) /* * innvl: { - * vdevs: { - * guid 1, guid 2, ... + * "initialize_command" -> POOL_INITIALIZE_{CANCEL|DO|SUSPEND} (uint64) + * "initialize_vdevs": { -> guids to initialize (nvlist) + * "vdev_path_1": vdev_guid_1, (uint64), + * "vdev_path_2": vdev_guid_2, (uint64), + * ... * }, - * func: POOL_INITIALIZE_{CANCEL|DO|SUSPEND} * } * * outnvl: { - * [func: EINVAL (if provided command type didn't make sense)], - * [vdevs: { - * guid1: errno, (see function body for possible errnos) + * "initialize_vdevs": { -> initialization errors (nvlist) + * "vdev_path_1": errno, see function body for possible errnos (uint64) + * "vdev_path_2": errno, ... (uint64) * ... - * }] + * } * } * + * EINVAL is returned for an unknown commands or if any of the provided vdev + * guids have be specified with a type other than uint64. */ static const zfs_ioc_key_t zfs_keys_pool_initialize[] = { - {ZPOOL_INITIALIZE_COMMAND, DATA_TYPE_UINT64, 0}, + {ZPOOL_INITIALIZE_COMMAND, DATA_TYPE_UINT64, 0}, {ZPOOL_INITIALIZE_VDEVS, DATA_TYPE_NVLIST, 0} }; static int zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) { - spa_t *spa; - int error; - - error = spa_open(poolname, &spa, FTAG); - if (error != 0) - return (error); - uint64_t cmd_type; if (nvlist_lookup_uint64(innvl, ZPOOL_INITIALIZE_COMMAND, &cmd_type) != 0) { - spa_close(spa, FTAG); return (SET_ERROR(EINVAL)); } + if (!(cmd_type == POOL_INITIALIZE_CANCEL || cmd_type == POOL_INITIALIZE_DO || cmd_type == POOL_INITIALIZE_SUSPEND)) { - spa_close(spa, FTAG); return (SET_ERROR(EINVAL)); } nvlist_t *vdev_guids; if (nvlist_lookup_nvlist(innvl, ZPOOL_INITIALIZE_VDEVS, &vdev_guids) != 0) { - spa_close(spa, FTAG); return (SET_ERROR(EINVAL)); } - nvlist_t *vdev_errlist = fnvlist_alloc(); - int total_errors = 0; - for (nvpair_t *pair = nvlist_next_nvpair(vdev_guids, NULL); pair != NULL; pair = nvlist_next_nvpair(vdev_guids, pair)) { - uint64_t vdev_guid = fnvpair_value_uint64(pair); - - error = spa_vdev_initialize(spa, vdev_guid, cmd_type); - if (error != 0) { - char guid_as_str[MAXNAMELEN]; - - (void) snprintf(guid_as_str, sizeof (guid_as_str), - "%llu", (unsigned long long)vdev_guid); - fnvlist_add_int64(vdev_errlist, guid_as_str, error); - total_errors++; + uint64_t vdev_guid; + if (nvpair_value_uint64(pair, &vdev_guid) != 0) { + return (SET_ERROR(EINVAL)); } } + + spa_t *spa; + int error = spa_open(poolname, &spa, FTAG); + if (error != 0) + return (error); + + nvlist_t *vdev_errlist = fnvlist_alloc(); + int total_errors = spa_vdev_initialize(spa, vdev_guids, cmd_type, + vdev_errlist); + if (fnvlist_size(vdev_errlist) > 0) { fnvlist_add_nvlist(outnvl, ZPOOL_INITIALIZE_VDEVS, vdev_errlist); |