summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Amanakis <[email protected]>2020-05-06 13:32:28 -0400
committerGitHub <[email protected]>2020-05-06 10:32:28 -0700
commit1b664952ae34d28c0408c20947f8aa5420c4ab63 (patch)
treeb802421507dee5ff43acb4c3fd550a2770e74036
parentddc7a2dd3b099c280b4f3ed978f16fa6bd7012c0 (diff)
Enable splitting mirrors with indirect vdevs
When a top-level vdev is removed from a pool it is converted to an indirect vdev. Until now splitting such mirrored pools was not possible with zpool split. This patch enables handling of indirect vdevs and splitting of those pools with zpool split. Reviewed-by: Matthew Ahrens <[email protected]> Reviewed by: Brian Behlendorf <[email protected]> Signed-off-by: George Amanakis <[email protected]> Closes #10283
-rw-r--r--lib/libzfs/libzfs_pool.c8
-rw-r--r--module/zfs/spa.c12
-rw-r--r--module/zfs/vdev_root.c3
-rw-r--r--tests/runfiles/common.run2
-rw-r--r--tests/zfs-tests/tests/functional/cli_root/zpool_split/Makefile.am3
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_indirect.ksh68
6 files changed, 89 insertions, 7 deletions
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index 06c85f145..9122b3ee1 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -3452,7 +3452,13 @@ zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
lastlog = 0;
verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type)
== 0);
- if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+
+ if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) {
+ vdev = child[c];
+ if (nvlist_dup(vdev, &varray[vcount++], 0) != 0)
+ goto out;
+ continue;
+ } else if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Source pool must be composed only of mirrors\n"));
retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
diff --git a/module/zfs/spa.c b/module/zfs/spa.c
index bd1e091ca..73d63f849 100644
--- a/module/zfs/spa.c
+++ b/module/zfs/spa.c
@@ -7297,7 +7297,8 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
vdev_t *vd = rvd->vdev_child[c];
/* don't count the holes & logs as children */
- if (vd->vdev_islog || !vdev_is_concrete(vd)) {
+ if (vd->vdev_islog || (vd->vdev_ops != &vdev_indirect_ops &&
+ !vdev_is_concrete(vd))) {
if (lastlog == 0)
lastlog = c;
continue;
@@ -7333,6 +7334,11 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
}
}
+ /* deal with indirect vdevs */
+ if (spa->spa_root_vdev->vdev_child[c]->vdev_ops ==
+ &vdev_indirect_ops)
+ continue;
+
/* which disk is going to be split? */
if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_GUID,
&glist[c]) != 0) {
@@ -7460,7 +7466,7 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
offsetof(vdev_t, vdev_trim_node));
for (c = 0; c < children; c++) {
- if (vml[c] != NULL) {
+ if (vml[c] != NULL && vml[c]->vdev_ops != &vdev_indirect_ops) {
mutex_enter(&vml[c]->vdev_initialize_lock);
vdev_initialize_stop(vml[c],
VDEV_INITIALIZE_ACTIVE, &vd_initialize_list);
@@ -7521,7 +7527,7 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
if (error != 0)
dmu_tx_abort(tx);
for (c = 0; c < children; c++) {
- if (vml[c] != NULL) {
+ if (vml[c] != NULL && vml[c]->vdev_ops != &vdev_indirect_ops) {
vdev_t *tvd = vml[c]->vdev_top;
/*
diff --git a/module/zfs/vdev_root.c b/module/zfs/vdev_root.c
index 7170f7013..ce79f7c73 100644
--- a/module/zfs/vdev_root.c
+++ b/module/zfs/vdev_root.c
@@ -98,7 +98,8 @@ vdev_root_open(vdev_t *vd, uint64_t *asize, uint64_t *max_asize,
for (int c = 0; c < vd->vdev_children; c++) {
vdev_t *cvd = vd->vdev_child[c];
- if (cvd->vdev_open_error && !cvd->vdev_islog) {
+ if (cvd->vdev_open_error && !cvd->vdev_islog &&
+ cvd->vdev_ops != &vdev_indirect_ops) {
lasterror = cvd->vdev_open_error;
numerrors++;
}
diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run
index a475db297..2fcde83b3 100644
--- a/tests/runfiles/common.run
+++ b/tests/runfiles/common.run
@@ -442,7 +442,7 @@ tags = ['functional', 'cli_root', 'zpool_set']
[tests/functional/cli_root/zpool_split]
tests = ['zpool_split_cliargs', 'zpool_split_devices',
'zpool_split_encryption', 'zpool_split_props', 'zpool_split_vdevs',
- 'zpool_split_resilver']
+ 'zpool_split_resilver', 'zpool_split_indirect']
tags = ['functional', 'cli_root', 'zpool_split']
[tests/functional/cli_root/zpool_status]
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_split/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_split/Makefile.am
index d00f39d35..1ca05a4e8 100644
--- a/tests/zfs-tests/tests/functional/cli_root/zpool_split/Makefile.am
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_split/Makefile.am
@@ -11,7 +11,8 @@ dist_pkgdata_SCRIPTS = \
zpool_split_props.ksh \
zpool_split_vdevs.ksh \
zpool_split_resilver.ksh \
- zpool_split_wholedisk.ksh
+ zpool_split_wholedisk.ksh \
+ zpool_split_indirect.ksh
dist_pkgdata_DATA = \
zpool_split.cfg
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_indirect.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_indirect.ksh
new file mode 100755
index 000000000..d6b0e7358
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_indirect.ksh
@@ -0,0 +1,68 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2020, George Amanakis. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/removal/removal.kshlib
+
+#
+# DESCRIPTION:
+# 'zpool split' should succeed on pools with indirect vdevs.
+#
+# STRATEGY:
+# Create a mirrored pool, add a single device, remove it. `zpool split`
+# should succeed.
+#
+
+verify_runnable "global"
+
+log_assert "'zpool split' works on pools with indirect VDEVs."
+
+function cleanup
+{
+ if poolexists $TESTPOOL ; then
+ destroy_pool $TESTPOOL
+ fi
+ if poolexists $TESTPOOL2 ; then
+ destroy_pool $TESTPOOL2
+ fi
+ rm -f $VDEV_*
+}
+log_onexit cleanup
+
+typeset vdev_m12_mb=400
+typeset vdev_temp_mb=$(( floor($vdev_m12_mb / 2) ))
+typeset VDEV_TEMP="$TEST_BASE_DIR/vdev_temp"
+typeset VDEV_M1="$TEST_BASE_DIR/vdev_m1"
+typeset VDEV_M2="$TEST_BASE_DIR/vdev_m2"
+typeset altroot="$TESTDIR/altroot-$TESTPOOL2"
+
+log_must truncate -s ${vdev_temp_mb}M $VDEV_TEMP
+log_must truncate -s ${vdev_m12_mb}M $VDEV_M1
+log_must truncate -s ${vdev_m12_mb}M $VDEV_M2
+
+log_must zpool create -f $TESTPOOL $VDEV_TEMP
+log_must zpool add -f $TESTPOOL mirror $VDEV_M1 $VDEV_M2
+log_must zpool remove $TESTPOOL $VDEV_TEMP
+log_must wait_for_removal $TESTPOOL
+log_must zpool split -R $altroot $TESTPOOL $TESTPOOL2
+log_must poolexists $TESTPOOL2
+log_must test "$(get_pool_prop 'altroot' $TESTPOOL2)" == "$altroot"
+
+log_pass "'zpool split' works on pools with indirect VDEVs."