Skip to content

Commit

Permalink
Enable splitting mirrors with indirect vdevs
Browse files Browse the repository at this point in the history
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 openzfs#10283
  • Loading branch information
gamanakis authored May 6, 2020
1 parent ddc7a2d commit 1b66495
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 7 deletions.
8 changes: 7 additions & 1 deletion lib/libzfs/libzfs_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 9 additions & 3 deletions module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

/*
Expand Down
3 changes: 2 additions & 1 deletion module/zfs/vdev_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/runfiles/common.run
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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."

0 comments on commit 1b66495

Please sign in to comment.