Skip to content

Commit

Permalink
Sync with latest upstream PR
Browse files Browse the repository at this point in the history
  • Loading branch information
dweeezil committed Dec 6, 2017
1 parent fafb7c4 commit 2f3473c
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 22 deletions.
42 changes: 38 additions & 4 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ get_usage(zpool_help_t idx)
return (gettext("\treplace [-f] [-o property=value] "
"<pool> <device> [new-device]\n"));
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
return (gettext("\tremove [-nps] <pool> <device> ...\n"));
case HELP_REOPEN:
return (gettext("\treopen [-n] <pool>\n"));
case HELP_SCRUB:
Expand Down Expand Up @@ -790,10 +790,18 @@ zpool_do_remove(int argc, char **argv)
zpool_handle_t *zhp = NULL;
boolean_t stop = B_FALSE;
char c;
boolean_t noop = B_FALSE;
boolean_t parsable = B_FALSE;

/* check options */
while ((c = getopt(argc, argv, "s")) != -1) {
while ((c = getopt(argc, argv, "nps")) != -1) {
switch (c) {
case 'n':
noop = B_TRUE;
break;
case 'p':
parsable = B_TRUE;
break;
case 's':
stop = B_TRUE;
break;
Expand All @@ -818,6 +826,11 @@ zpool_do_remove(int argc, char **argv)
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);

if (stop && noop) {
(void) fprintf(stderr, gettext("stop request ignored\n"));
return (0);
}

if (stop) {
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
Expand All @@ -832,8 +845,29 @@ zpool_do_remove(int argc, char **argv)
}

for (i = 1; i < argc; i++) {
if (zpool_vdev_remove(zhp, argv[i]) != 0)
ret = 1;
if (noop) {
uint64_t size;

if (zpool_vdev_indirect_size(zhp, argv[i],
&size) != 0) {
ret = 1;
break;
}
if (parsable) {
(void) printf("%s %llu\n",
argv[i], (unsigned long long)size);
} else {
char valstr[32];
zfs_nicenum(size, valstr,
sizeof (valstr));
(void) printf("Memory that will be "
"used after removing %s: %s\n",
argv[i], valstr);
}
} else {
if (zpool_vdev_remove(zhp, argv[i]) != 0)
ret = 1;
}
}
}
zpool_close(zhp);
Expand Down
1 change: 1 addition & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ extern int zpool_vdev_attach(zpool_handle_t *, const char *,
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
extern int zpool_vdev_remove_cancel(zpool_handle_t *);
extern int zpool_vdev_indirect_size(zpool_handle_t *, const char *, uint64_t *);
extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
splitflags_t);

Expand Down
50 changes: 41 additions & 9 deletions lib/libzfs/libzfs_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
Expand Down Expand Up @@ -1411,8 +1411,10 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)

case EINVAL:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Invalid config; a pool with removing/removed "
"vdevs does not support redundant vdevs"));
"invalid config; a pool with removing/removed "
"vdevs does not support adding raidz vdevs "
"or a top level mirror must be a "
"mirror of leaf vdevs only"));
(void) zfs_error(hdl, EZFS_BADDEV, msg);
break;

Expand Down Expand Up @@ -2766,7 +2768,7 @@ zpool_vdev_attach(zpool_handle_t *zhp,

(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
&islog)) == 0)
&islog)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));

if (avail_spare)
Expand Down Expand Up @@ -2921,7 +2923,7 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path)

(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
NULL)) == 0)
NULL)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));

if (avail_spare)
Expand Down Expand Up @@ -3227,7 +3229,7 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path)

(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
&islog)) == 0)
&islog)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));

version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
Expand All @@ -3244,7 +3246,7 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
return (zfs_error(hdl, EINVAL, msg));
}

verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);

if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
return (0);
Expand All @@ -3254,7 +3256,7 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
case EINVAL:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid config; all top-level vdevs must "
"have the same sector size and not be raidz "));
"have the same sector size and not be raidz."));
(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
break;

Expand Down Expand Up @@ -3290,6 +3292,36 @@ zpool_vdev_remove_cancel(zpool_handle_t *zhp)
return (zpool_standard_error(hdl, errno, msg));
}

int
zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path,
uint64_t *sizep)
{
char msg[1024];
nvlist_t *tgt;
boolean_t avail_spare, l2cache, islog;
libzfs_handle_t *hdl = zhp->zpool_hdl;

(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"),
path);

if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
&islog)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));

if (avail_spare || l2cache || islog) {
*sizep = 0;
return (0);
}

if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"indirect size not available"));
return (zfs_error(hdl, EINVAL, msg));
}
return (0);
}

/*
* Clear the errors for the pool, or the particular device if specified.
*/
Expand Down Expand Up @@ -3317,7 +3349,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if (path) {
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
&l2cache, NULL)) == 0)
&l2cache, NULL)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));

/*
Expand Down
21 changes: 18 additions & 3 deletions man/man8/zpool.8
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
.Ar pool
.Nm
.Cm remove
.Op Fl np
.Ar pool Ar device Ns ...
.Nm
.Cm remove
Expand Down Expand Up @@ -1754,18 +1755,19 @@ result in partially resilvered devices unless a second scrub is performed.
.It Xo
.Nm
.Cm remove
.Op Fl np
.Ar pool Ar device Ns ...
.Xc
Removes the specified device from the pool.
This command currently only supports removing hot spares, cache, log
devices and mirrored top-level vdevs (mirror of leaf devices); but not raidz.
.sp
Removing a top-level vdev reduces the total amount of space in the storage pool.
The specified device must be evacuated by copying all allocated space from it to
The specified device will be evacuated by copying all allocated space from it to
the other devices in the pool.
In this case, the
.Nm zpool Cm remove
command initiates the removal and continues while the evacuation continues in
command initiates the removal and returns, while the evacuation continues in
the background.
The removal progress can be monitored with
.Nm zpool Cm status.
Expand All @@ -1778,6 +1780,19 @@ Non-log devices or data devices that are part of a mirrored configuration can be
the
.Nm zpool Cm detach
command.
.Bl -tag -width Ds
.It Fl n
Do not actually perform the removal ("no-op").
Instead, print the estimated amount of memory that will be used by the
mapping table after the removal completes.
This is nonzero only for top-level vdevs.
.El
.Bl -tag -width Ds
.It Fl p
Used in conjunction with the
.Fl p
flag, displays numbers as parsable (exact) values.
.El
.It Xo
.Nm
.Cm remove
Expand Down Expand Up @@ -2232,7 +2247,7 @@ option as follows:
# zpool iostat -v pool 5
.Ed
.It Sy Example 14 No Removing a Mirrored top-level (Log or Data) Device
The following commands removes the mirrored log device
The following commands remove the mirrored log device
.Sy mirror-2
and mirrored top-level data device
.Sy mirror-1 .
Expand Down
1 change: 1 addition & 0 deletions module/zfs/metaslab.c
Original file line number Diff line number Diff line change
Expand Up @@ -3899,6 +3899,7 @@ module_param(zfs_metaslab_switch_threshold, int, 0644);
MODULE_PARM_DESC(zfs_metaslab_switch_threshold,
"segment-based metaslab selection maximum buckets before switching");

/* CSTYLED */
module_param(metaslab_gang_bang, ulong, 0644);
MODULE_PARM_DESC(metaslab_gang_bang,
"blocks larger than this size are forced to be gang blocks");
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/spa.c
Original file line number Diff line number Diff line change
Expand Up @@ -4843,7 +4843,7 @@ spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
}
/*
* Need the top level mirror to be
* a mirror of leaf vdevs only.
* a mirror of leaf vdevs only
*/
if (tvd->vdev_ops == &vdev_mirror_ops) {
for (uint64_t cid = 0;
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/vdev_removal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1618,7 +1618,7 @@ spa_vdev_remove_top_check(vdev_t *vd)
spa_t *spa = vd->vdev_spa;

if (vd != vd->vdev_top)
return (SET_ERROR(EINVAL));
return (SET_ERROR(ENOTSUP));

if (!spa_feature_is_enabled(spa, SPA_FEATURE_DEVICE_REMOVAL))
return (SET_ERROR(ENOTSUP));
Expand Down
2 changes: 1 addition & 1 deletion tests/runfiles/linux.run
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ tests = ['removal_sanity', 'removal_all_vdev', 'removal_check_space',
'removal_with_export', 'removal_with_ganging', 'removal_with_remap',
'removal_with_remove', 'removal_with_scrub', 'removal_with_send',
'removal_with_send_recv', 'removal_with_snapshot', 'removal_with_write',
'removal_with_zdb', 'remove_mirror', 'remove_raidz']
'removal_with_zdb', 'remove_mirror', 'remove_mirror_sanity', 'remove_raidz']
tags = ['functional', 'removal']

[tests/functional/rename_dirs]
Expand Down
6 changes: 3 additions & 3 deletions tests/zfs-tests/tests/functional/removal/remove_mirror.ksh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#

#
# Copyright (c) 2014, 2016 by Delphix. All rights reserved.
# Copyright (c) 2014, 2017 by Delphix. All rights reserved.
#

. $STF_SUITE/include/libtest.shlib
Expand Down Expand Up @@ -43,6 +43,6 @@ log_mustnot zpool remove $TESTPOOL $TMPDIR/dsk1
log_mustnot zpool remove $TESTPOOL $TMPDIR/dsk2

# Attempt to remove the mirror.
log_must zpool remove $TESTPOOL mirror-1
log_mustnot zpool remove $TESTPOOL mirror-1

log_pass "Removal will succeed if there is a top level mirror."
log_pass "Removal will not succeed if there is not enough space."
59 changes: 59 additions & 0 deletions tests/zfs-tests/tests/functional/removal/remove_mirror_sanity.ksh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#! /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) 2017 by Delphix. All rights reserved.
#

. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/removal/removal.kshlib

DISK1=$(echo $DISKS | awk '{print $1}')
DISK2=$(echo $DISKS | awk '{print $2}')
DISK3=$(echo $DISKS | awk '{print $3}')

DISKS="$DISK1 mirror $DISK2 $DISK3"

log_must default_setup_noexit "$DISKS"
log_onexit default_cleanup_noexit

WORDS_FILE1="/usr/dict/words"
WORDS_FILE2="/usr/share/dict/words"
FILE_CONTENTS="Leeloo Dallas mul-ti-pass."

if [[ -f $WORDS_FILE1 ]]; then
log_must cp $WORDS_FILE1 $TESTDIR
elif [[ -f $WORDS_FILE2 ]]; then
log_must cp $WORDS_FILE2 $TESTDIR
else
echo $FILE_CONTENTS >$TESTDIR/$TESTFILE0
log_must [ "x$(cat $TESTDIR/$TESTFILE0)" = "x$FILE_CONTENTS" ]
fi

log_must zpool remove $TESTPOOL mirror-1
log_must wait_for_removal $TESTPOOL
log_mustnot vdevs_in_pool $TESTPOOL mirror-1

if [[ -f $WORDS_FILE1 ]]; then
log_must diff $WORDS_FILE1 $TESTDIR/words
elif [[ -f $WORDS_FILE2 ]]; then
log_must diff $WORDS_FILE2 $TESTDIR/words
else
log_must dd if=/$TESTDIR/$TESTFILE0 of=/dev/null
log_must [ "x$(cat $TESTDIR/$TESTFILE0)" = "x$FILE_CONTENTS" ]
fi

log_pass "Removed top-level mirror device not in use after removal."

0 comments on commit 2f3473c

Please sign in to comment.