diff options
author | Arkadiusz Bubała <[email protected]> | 2017-10-26 21:26:09 +0200 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-10-26 12:26:09 -0700 |
commit | d3f2cd7e3b70679f127dd471ea6d37ece27463f2 (patch) | |
tree | c83555f629c501dd5742272c62888caa785b7468 | |
parent | 3ad59c015dce45965fa309a0364a46c6f8bdda9f (diff) |
Added no_scrub_restart flag to zpool reopen
Added -n flag to zpool reopen that allows a running scrub
operation to continue if there is a device with Dirty Time Log.
By default if a component device has a DTL and zpool reopen
is executed all running scan operations will be restarted.
Added functional tests for `zpool reopen`
Tests covers following scenarios:
* `zpool reopen` without arguments,
* `zpool reopen` with pool name as argument,
* `zpool reopen` while scrubbing,
* `zpool reopen -n` while scrubbing,
* `zpool reopen -n` while resilvering,
* `zpool reopen` with bad arguments.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Tom Caputi <[email protected]>
Signed-off-by: Arkadiusz Bubała <[email protected]>
Closes #6076
Closes #6746
28 files changed, 1195 insertions, 382 deletions
diff --git a/cmd/zed/agents/zfs_mod.c b/cmd/zed/agents/zfs_mod.c index a906decab..5fa74d0ce 100644 --- a/cmd/zed/agents/zfs_mod.c +++ b/cmd/zed/agents/zfs_mod.c @@ -23,6 +23,7 @@ * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016, 2017, Intel Corporation. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ /* @@ -722,6 +723,8 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data) (void) strlcpy(fullpath, path, sizeof (fullpath)); if (wholedisk) { char *spath = zfs_strip_partition(fullpath); + boolean_t scrub_restart = B_TRUE; + if (!spath) { zed_log_msg(LOG_INFO, "%s: Can't alloc", __func__); @@ -736,7 +739,7 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data) * device so that the kernel can update the size * of the expanded device. */ - (void) zpool_reopen(zhp); + (void) zpool_reopen_one(zhp, &scrub_restart); } if (zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) { diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index db2486aee..d80cbc6c6 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -28,6 +28,7 @@ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. * Copyright 2016 Igor Kozhukhov <[email protected]>. * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ #include <assert.h> @@ -342,7 +343,7 @@ get_usage(zpool_help_t idx) case HELP_REMOVE: return (gettext("\tremove <pool> <device> ...\n")); case HELP_REOPEN: - return (gettext("\treopen <pool>\n")); + return (gettext("\treopen [-n] <pool>\n")); case HELP_SCRUB: return (gettext("\tscrub [-s | -p] <pool> ...\n")); case HELP_STATUS: @@ -5855,12 +5856,14 @@ zpool_do_reopen(int argc, char **argv) { int c; int ret = 0; - zpool_handle_t *zhp; - char *pool; + boolean_t scrub_restart = B_TRUE; /* check options */ - while ((c = getopt(argc, argv, "")) != -1) { + while ((c = getopt(argc, argv, "n")) != -1) { switch (c) { + case 'n': + scrub_restart = B_FALSE; + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -5868,25 +5871,13 @@ zpool_do_reopen(int argc, char **argv) } } - argc--; - argv++; - - if (argc < 1) { - (void) fprintf(stderr, gettext("missing pool name\n")); - usage(B_FALSE); - } - - if (argc > 1) { - (void) fprintf(stderr, gettext("too many arguments\n")); - usage(B_FALSE); - } + argc -= optind; + argv += optind; - pool = argv[0]; - if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) - return (1); + /* if argc == 0 we will execute zpool_reopen_one on all pools */ + ret = for_each_pool(argc, argv, B_TRUE, NULL, zpool_reopen_one, + &scrub_restart); - ret = zpool_reopen(zhp); - zpool_close(zhp); return (ret); } diff --git a/configure.ac b/configure.ac index 6dff03092..655641afd 100644 --- a/configure.ac +++ b/configure.ac @@ -224,6 +224,7 @@ AC_CONFIG_FILES([ tests/zfs-tests/tests/functional/cli_root/zpool_offline/Makefile tests/zfs-tests/tests/functional/cli_root/zpool_online/Makefile tests/zfs-tests/tests/functional/cli_root/zpool_remove/Makefile + tests/zfs-tests/tests/functional/cli_root/zpool_reopen/Makefile tests/zfs-tests/tests/functional/cli_root/zpool_replace/Makefile tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile tests/zfs-tests/tests/functional/cli_root/zpool_set/Makefile diff --git a/include/libzfs.h b/include/libzfs.h index 7ef250f02..1244bf0e4 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -27,6 +27,7 @@ * Copyright (c) 2016, Intel Corporation. * Copyright 2016 Nexenta Systems, Inc. * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ #ifndef _LIBZFS_H @@ -266,7 +267,7 @@ typedef struct splitflags { extern int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t); extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *); extern int zpool_reguid(zpool_handle_t *); -extern int zpool_reopen(zpool_handle_t *); +extern int zpool_reopen_one(zpool_handle_t *, void *); extern int zpool_sync_one(zpool_handle_t *, void *); diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 46e9641d3..9f914e54f 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -23,6 +23,7 @@ * Copyright (c) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2017 Datto Inc. * Copyright 2017 RackTop Systems. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ #ifndef _LIBZFS_CORE_H @@ -101,6 +102,7 @@ int lzc_rollback(const char *, char *, int); int lzc_rollback_to(const char *, const char *); int lzc_sync(const char *, nvlist_t *, nvlist_t **); +int lzc_reopen(const char *, boolean_t); #ifdef __cplusplus } diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index bfb26d674..aa77b547a 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -25,6 +25,7 @@ * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright 2016 Igor Kozhukhov <[email protected]> * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ #include <ctype.h> @@ -3370,20 +3371,20 @@ zpool_reguid(zpool_handle_t *zhp) * Reopen the pool. */ int -zpool_reopen(zpool_handle_t *zhp) +zpool_reopen_one(zpool_handle_t *zhp, void *data) { - zfs_cmd_t zc = {"\0"}; - char msg[1024]; - libzfs_handle_t *hdl = zhp->zpool_hdl; + libzfs_handle_t *hdl = zpool_get_handle(zhp); + const char *pool_name = zpool_get_name(zhp); + boolean_t *scrub_restart = data; + int error; - (void) snprintf(msg, sizeof (msg), - dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), - zhp->zpool_name); + error = lzc_reopen(pool_name, *scrub_restart); + if (error) { + return (zpool_standard_error_fmt(hdl, error, + dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), pool_name)); + } - (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0) - return (0); - return (zpool_standard_error(hdl, errno, msg)); + return (0); } /* call into libzfs_core to execute the sync IOCTL per pool */ diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index cc663f9dd..675f4a3de 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -24,6 +24,7 @@ * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2017 Datto Inc. * Copyright 2017 RackTop Systems. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ /* @@ -1111,3 +1112,16 @@ lzc_change_key(const char *fsname, uint64_t crypt_cmd, nvlist_t *props, nvlist_free(ioc_args); return (error); } + +int +lzc_reopen(const char *pool_name, boolean_t scrub_restart) +{ + nvlist_t *args = fnvlist_alloc(); + int error; + + fnvlist_add_boolean_value(args, "scrub_restart", scrub_restart); + + error = lzc_ioctl(ZFS_IOC_POOL_REOPEN, pool_name, args, NULL); + nvlist_free(args); + return (error); +} diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index 54ba68698..5c45b049b 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -25,6 +25,7 @@ .\" Copyright (c) 2017 Datto Inc. .\" Copyright (c) 2017 George Melikov. All Rights Reserved. .\" Copyright 2017 Nexenta Systems, Inc. +.\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. .\" .Dd August 23, 2017 .Dt ZPOOL 8 SMM @@ -140,6 +141,7 @@ .Ar pool .Nm .Cm reopen +.Op Fl n .Ar pool .Nm .Cm remove @@ -1739,9 +1741,14 @@ performing this action. .It Xo .Nm .Cm reopen +.Op Fl n .Ar pool .Xc Reopen all the vdevs associated with the pool. +.Bl -tag -width Ds +.It Fl n +Do not restart an in-progress scrub operation. This is not recommended and can +result in partially resilvered devices unless a second scrub is performed. .It Xo .Nm .Cm remove diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index f6291ce59..5f333a42e 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -36,6 +36,7 @@ * Copyright (c) 2017, loli10K <[email protected]>. All rights reserved. * Copyright (c) 2017 Datto Inc. All rights reserved. * Copyright 2017 RackTop Systems. + * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. */ /* @@ -5032,25 +5033,46 @@ zfs_ioc_clear(zfs_cmd_t *zc) return (error); } +/* + * Reopen all the vdevs associated with the pool. + * + * innvl: { + * "scrub_restart" -> when true and scrub is running, allow to restart + * scrub as the side effect of the reopen (boolean). + * } + * + * outnvl is unused + */ +/* ARGSUSED */ static int -zfs_ioc_pool_reopen(zfs_cmd_t *zc) +zfs_ioc_pool_reopen(const char *pool, nvlist_t *innvl, nvlist_t *outnvl) { spa_t *spa; int error; + boolean_t scrub_restart = B_TRUE; - error = spa_open(zc->zc_name, &spa, FTAG); + if (innvl) { + if (nvlist_lookup_boolean_value(innvl, "scrub_restart", + &scrub_restart) != 0) { + return (SET_ERROR(EINVAL)); + } + } + + error = spa_open(pool, &spa, FTAG); if (error != 0) return (error); spa_vdev_state_enter(spa, SCL_NONE); /* - * If a resilver is already in progress then set the - * spa_scrub_reopen flag to B_TRUE so that we don't restart - * the scan as a side effect of the reopen. Otherwise, let - * vdev_open() decided if a resilver is required. + * If the scrub_restart flag is B_FALSE and a scrub is already + * in progress then set spa_scrub_reopen flag to B_TRUE so that + * we don't restart the scrub as a side effect of the reopen. + * Otherwise, let vdev_open() decided if a resilver is required. */ - spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool); + + spa->spa_scrub_reopen = (!scrub_restart && + dsl_scan_scrubbing(spa->spa_dsl_pool)); vdev_reopen(spa->spa_root_vdev); spa->spa_scrub_reopen = B_FALSE; @@ -5058,6 +5080,7 @@ zfs_ioc_pool_reopen(zfs_cmd_t *zc) spa_close(spa, FTAG); return (0); } + /* * inputs: * zc_name name of filesystem @@ -6316,6 +6339,9 @@ zfs_ioctl_init(void) zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC, zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE); + zfs_ioctl_register("reopen", ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, + zfs_secpolicy_config, POOL_NAME, POOL_CHECK_SUSPENDED, B_TRUE, + B_TRUE); /* IOCTLS that use the legacy function signature */ @@ -6389,8 +6415,6 @@ zfs_ioctl_init(void) zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear, zfs_secpolicy_config, B_TRUE, POOL_CHECK_READONLY); - zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen, - zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED); zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN, zfs_ioc_space_written); diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 6fe6b6588..f0c785f59 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -294,6 +294,11 @@ tests = ['zpool_online_001_pos', 'zpool_online_002_neg'] tests = ['zpool_remove_001_neg', 'zpool_remove_002_pos', 'zpool_remove_003_pos'] +[tests/functional/cli_root/zpool_reopen] +tests = ['zpool_reopen_001_pos', 'zpool_reopen_002_pos', + 'zpool_reopen_003_pos', 'zpool_reopen_004_pos', 'zpool_reopen_005_pos', + 'zpool_reopen_006_neg'] + [tests/functional/cli_root/zpool_replace] tests = ['zpool_replace_001_neg', 'replace-o_ashift', 'replace_prop_ashift'] diff --git a/tests/zfs-tests/include/Makefile.am b/tests/zfs-tests/include/Makefile.am index 24633ccc3..e5daa7f5f 100644 --- a/tests/zfs-tests/include/Makefile.am +++ b/tests/zfs-tests/include/Makefile.am @@ -1,5 +1,6 @@ pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/include dist_pkgdata_SCRIPTS = \ + blkdev.shlib \ commands.cfg \ default.cfg \ libtest.shlib \ diff --git a/tests/zfs-tests/include/blkdev.shlib b/tests/zfs-tests/include/blkdev.shlib new file mode 100644 index 000000000..876c84356 --- /dev/null +++ b/tests/zfs-tests/include/blkdev.shlib @@ -0,0 +1,395 @@ +# +# 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. +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# Copyright (c) 2012, 2016 by Delphix. All rights reserved. +# Copyright 2016 Nexenta Systems, Inc. +# Copyright (c) 2016, 2017 by Intel Corporation. All rights reserved. +# Copyright (c) 2017 Lawrence Livermore National Security, LLC. +# Copyright (c) 2017 Datto Inc. +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +# +# Returns SCSI host number for the given disk +# +function get_scsi_host #disk +{ + typeset disk=$1 + ls /sys/block/${disk}/device/scsi_device | cut -d : -f 1 +} + +# +# Cause a scan of all scsi host adapters by default +# +# $1 optional host number +# +function scan_scsi_hosts +{ + typeset hostnum=${1} + + if is_linux; then + if [[ -z $hostnum ]]; then + for host in /sys/class/scsi_host/host*; do + log_must eval "echo '- - -' > $host/scan" + done + else + log_must eval \ + "echo /sys/class/scsi_host/host$hostnum/scan" \ + > /dev/null + log_must eval \ + "echo '- - -' > /sys/class/scsi_host/host$hostnum/scan" + fi + fi +} + +# +# Wait for newly created block devices to have their minors created. +# +function block_device_wait +{ + if is_linux; then + udevadm trigger + udevadm settle + fi +} + +# +# Check if the given device is physical device +# +function is_physical_device #device +{ + typeset device=${1#$DEV_DSKDIR} + device=${device#$DEV_RDSKDIR} + + if is_linux; then + [[ -b "$DEV_DSKDIR/$device" ]] && \ + [[ -f /sys/module/loop/parameters/max_part ]] + return $? + else + echo $device | egrep "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1 + return $? + fi +} + +# +# Check if the given device is a real device (ie SCSI device) +# +function is_real_device #disk +{ + typeset disk=$1 + [[ -z $disk ]] && log_fail "No argument for disk given." + + if is_linux; then + lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \ + egrep disk >/dev/null + return $? + fi +} + +# +# Check if the given device is a loop device +# +function is_loop_device #disk +{ + typeset disk=$1 + [[ -z $disk ]] && log_fail "No argument for disk given." + + if is_linux; then + lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \ + egrep loop >/dev/null + return $? + fi +} + +# +# Check if the given device is a multipath device and if there is a sybolic +# link to a device mapper and to a disk +# Currently no support for dm devices alone without multipath +# +function is_mpath_device #disk +{ + typeset disk=$1 + [[ -z $disk ]] && log_fail "No argument for disk given." + + if is_linux; then + lsblk $DEV_MPATHDIR/$disk -o TYPE 2>/dev/null | \ + egrep mpath >/dev/null + if (($? == 0)); then + readlink $DEV_MPATHDIR/$disk > /dev/null 2>&1 + return $? + else + return $? + fi + fi +} + +# Set the slice prefix for disk partitioning depending +# on whether the device is a real, multipath, or loop device. +# Currently all disks have to be of the same type, so only +# checks first disk to determine slice prefix. +# +function set_slice_prefix +{ + typeset disk + typeset -i i=0 + + if is_linux; then + while (( i < $DISK_ARRAY_NUM )); do + disk="$(echo $DISKS | nawk '{print $(i + 1)}')" + if ( is_mpath_device $disk ) && [[ -z $(echo $disk | awk 'substr($1,18,1)\ + ~ /^[[:digit:]]+$/') ]] || ( is_real_device $disk ); then + export SLICE_PREFIX="" + return 0 + elif ( is_mpath_device $disk || is_loop_device \ + $disk ); then + export SLICE_PREFIX="p" + return 0 + else + log_fail "$disk not supported for partitioning." + fi + (( i = i + 1)) + done + fi +} + +# +# Set the directory path of the listed devices in $DISK_ARRAY_NUM +# Currently all disks have to be of the same type, so only +# checks first disk to determine device directory +# default = /dev (linux) +# real disk = /dev (linux) +# multipath device = /dev/mapper (linux) +# +function set_device_dir +{ + typeset disk + typeset -i i=0 + + if is_linux; then + while (( i < $DISK_ARRAY_NUM )); do + disk="$(echo $DISKS | nawk '{print $(i + 1)}')" + if is_mpath_device $disk; then + export DEV_DSKDIR=$DEV_MPATHDIR + return 0 + else + export DEV_DSKDIR=$DEV_RDSKDIR + return 0 + fi + (( i = i + 1)) + done + else + export DEV_DSKDIR=$DEV_RDSKDIR + fi +} + +# +# Get the directory path of given device +# +function get_device_dir #device +{ + typeset device=$1 + + if ! $(is_physical_device $device) ; then + if [[ $device != "/" ]]; then + device=${device%/*} + fi + if [[ -b "$DEV_DSKDIR/$device" ]]; then + device="$DEV_DSKDIR" + fi + echo $device + else + echo "$DEV_DSKDIR" + fi +} + +# +# Get persistent name for given disk +# +function get_persistent_disk_name #device +{ + typeset device=$1 + typeset dev_id + + if is_linux; then + if is_real_device $device; then + dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \ + | egrep disk/by-id | nawk '{print $2; exit}' \ + | nawk -F / '{print $3}')" + echo $dev_id + elif is_mpath_device $device; then + dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \ + | egrep disk/by-id/dm-uuid \ + | nawk '{print $2; exit}' \ + | nawk -F / '{print $3}')" + echo $dev_id + else + echo $device + fi + else + echo $device + fi +} + +# +# Online or offline a disk on the system +# +# First checks state of disk. Test will fail if disk is not properly onlined +# or offlined. Online is a full rescan of SCSI disks by echoing to every +# host entry. +# +function on_off_disk # disk state{online,offline} host +{ + typeset disk=$1 + typeset state=$2 + typeset host=$3 + + [[ -z $disk ]] || [[ -z $state ]] && \ + log_fail "Arguments invalid or missing" + + if is_linux; then + if [[ $state == "offline" ]] && ( is_mpath_device $disk ); then + dm_name="$(readlink $DEV_DSKDIR/$disk \ + | nawk -F / '{print $2}')" + slave="$(ls /sys/block/${dm_name}/slaves \ + | nawk '{print $1}')" + while [[ -n $slave ]]; do + #check if disk is online + lsscsi | egrep $slave > /dev/null + if (($? == 0)); then + slave_dir="/sys/block/${dm_name}" + slave_dir+="/slaves/${slave}/device" + ss="${slave_dir}/state" + sd="${slave_dir}/delete" + log_must eval "echo 'offline' > ${ss}" + log_must eval "echo '1' > ${sd}" + lsscsi | egrep $slave > /dev/null + if (($? == 0)); then + log_fail "Offlining" \ + "$disk failed" + fi + fi + slave="$(ls /sys/block/$dm_name/slaves \ + 2>/dev/null | nawk '{print $1}')" + done + elif [[ $state == "offline" ]] && ( is_real_device $disk ); then + #check if disk is online + lsscsi | egrep $disk > /dev/null + if (($? == 0)); then + dev_state="/sys/block/$disk/device/state" + dev_delete="/sys/block/$disk/device/delete" + log_must eval "echo 'offline' > ${dev_state}" + log_must eval "echo '1' > ${dev_delete}" + lsscsi | egrep $disk > /dev/null + if (($? == 0)); then + log_fail "Offlining $disk" \ + "failed" + fi + else + log_note "$disk is already offline" + fi + elif [[ $state == "online" ]]; then + #force a full rescan + scan_scsi_hosts $host + block_device_wait + if is_mpath_device $disk; then + dm_name="$(readlink $DEV_DSKDIR/$disk \ + | nawk -F / '{print $2}')" + slave="$(ls /sys/block/$dm_name/slaves \ + | nawk '{print $1}')" + lsscsi | egrep $slave > /dev/null + if (($? != 0)); then + log_fail "Onlining $disk failed" + fi + elif is_real_device $disk; then + typeset -i retries=0 + while ! lsscsi | egrep -q $disk; do + if (( $retries > 2 )); then + log_fail "Onlining $disk failed" + break + fi + (( ++retries )) + sleep 1 + done + else + log_fail "$disk is not a real dev" + fi + else + log_fail "$disk failed to $state" + fi + fi +} + +# +# Simulate disk removal +# +function remove_disk #disk +{ + typeset disk=$1 + on_off_disk $disk "offline" + block_device_wait +} + +# +# Simulate disk insertion for the given SCSI host +# +function insert_disk #disk scsi_host +{ + typeset disk=$1 + typeset scsi_host=$2 + on_off_disk $disk "online" $scsi_host + block_device_wait +} + +# +# Load scsi_debug module with specified parameters +# +function load_scsi_debug # dev_size_mb add_host num_tgts max_luns +{ + typeset devsize=$1 + typeset hosts=$2 + typeset tgts=$3 + typeset luns=$4 + + [[ -z $devsize ]] || [[ -z $hosts ]] || [[ -z $tgts ]] || \ + [[ -z $luns ]] && log_fail "Arguments invalid or missing" + + if is_linux; then + modprobe -n scsi_debug + if (($? != 0)); then + log_unsupported "Platform does not have scsi_debug" + "module" + fi + lsmod | egrep scsi_debug > /dev/null + if (($? == 0)); then + log_fail "scsi_debug module already installed" + else + log_must modprobe scsi_debug dev_size_mb=$devsize \ + add_host=$hosts num_tgts=$tgts max_luns=$luns + block_device_wait + lsscsi | egrep scsi_debug > /dev/null + if (($? == 1)); then + log_fail "scsi_debug module install failed" + fi + fi + fi +} + +# +# Get scsi_debug device name. +# Returns basename of scsi_debug device (for example "sdb"). +# +function get_debug_device +{ + lsscsi | nawk '/scsi_debug/ {print $6; exit}' | cut -d / -f3 +} diff --git a/tests/zfs-tests/include/libtest.shlib b/tests/zfs-tests/include/libtest.shlib index 0e7f20f0e..6b1658c1b 100644 --- a/tests/zfs-tests/include/libtest.shlib +++ b/tests/zfs-tests/include/libtest.shlib @@ -27,10 +27,12 @@ # Copyright 2016 Nexenta Systems, Inc. # Copyright (c) 2017 Lawrence Livermore National Security, LLC. # Copyright (c) 2017 Datto Inc. +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. # . ${STF_TOOLS}/include/logapi.shlib . ${STF_SUITE}/include/math.shlib +. ${STF_SUITE}/include/blkdev.shlib # # Apply constrained path when available. This is required since the @@ -1752,124 +1754,6 @@ function check_state # pool disk state{online,offline,degraded} } # -# Cause a scan of all scsi host adapters by default -# -# $1 optional host number -# -function scan_scsi_hosts -{ - typeset hostnum=${1} - - if is_linux; then - if [[ -z $hostnum ]]; then - for host in /sys/class/scsi_host/host*; do - log_must eval "echo '- - -' > $host/scan" - done - else - log_must eval \ - "echo /sys/class/scsi_host/host$hostnum/scan" \ - > /dev/null - log_must eval \ - "echo '- - -' > /sys/class/scsi_host/host$hostnum/scan" - fi - fi -} -# -# Wait for newly created block devices to have their minors created. -# -function block_device_wait -{ - if is_linux; then - udevadm trigger - udevadm settle - fi -} - -# -# Online or offline a disk on the system -# -# First checks state of disk. Test will fail if disk is not properly onlined -# or offlined. Online is a full rescan of SCSI disks by echoing to every -# host entry. -# -function on_off_disk # disk state{online,offline} host -{ - typeset disk=$1 - typeset state=$2 - typeset host=$3 - - [[ -z $disk ]] || [[ -z $state ]] && \ - log_fail "Arguments invalid or missing" - - if is_linux; then - if [[ $state == "offline" ]] && ( is_mpath_device $disk ); then - dm_name="$(readlink $DEV_DSKDIR/$disk \ - | nawk -F / '{print $2}')" - slave="$(ls /sys/block/${dm_name}/slaves \ - | nawk '{print $1}')" - while [[ -n $slave ]]; do - #check if disk is online - lsscsi | egrep $slave > /dev/null - if (($? == 0)); then - slave_dir="/sys/block/${dm_name}" - slave_dir+="/slaves/${slave}/device" - ss="${slave_dir}/state" - sd="${slave_dir}/delete" - log_must eval "echo 'offline' > ${ss}" - log_must eval "echo '1' > ${sd}" - lsscsi | egrep $slave > /dev/null - if (($? == 0)); then - log_fail "Offlining" \ - "$disk failed" - fi - fi - slave="$(ls /sys/block/$dm_name/slaves \ - 2>/dev/null | nawk '{print $1}')" - done - elif [[ $state == "offline" ]] && ( is_real_device $disk ); then - #check if disk is online - lsscsi | egrep $disk > /dev/null - if (($? == 0)); then - dev_state="/sys/block/$disk/device/state" - dev_delete="/sys/block/$disk/device/delete" - log_must eval "echo 'offline' > ${dev_state}" - log_must eval "echo '1' > ${dev_delete}" - lsscsi | egrep $disk > /dev/null - if (($? == 0)); then - log_fail "Offlining $disk" \ - "failed" - fi - else - log_note "$disk is already offline" - fi - elif [[ $state == "online" ]]; then - #force a full rescan - scan_scsi_hosts $host - block_device_wait - if is_mpath_device $disk; then - dm_name="$(readlink $DEV_DSKDIR/$disk \ - | nawk -F / '{print $2}')" - slave="$(ls /sys/block/$dm_name/slaves \ - | nawk '{print $1}')" - lsscsi | egrep $slave > /dev/null - if (($? != 0)); then - log_fail "Onlining $disk failed" - fi - elif is_real_device $disk; then - lsscsi | egrep $disk > /dev/null - if (($? != 0)); then - log_fail "Onlining $disk failed" - fi - else - log_fail "$disk is not a real dev" - fi - else - log_fail "$disk failed to $state" - fi - fi -} - -# # Get the mountpoint of snapshot # For the snapshot use <mp_filesystem>/.zfs/snapshot/<snap> # as its mountpoint @@ -2898,217 +2782,6 @@ function get_rootpool } # -# Check if the given device is physical device -# -function is_physical_device #device -{ - typeset device=${1#$DEV_DSKDIR} - device=${device#$DEV_RDSKDIR} - - if is_linux; then - [[ -b "$DEV_DSKDIR/$device" ]] && \ - [[ -f /sys/module/loop/parameters/max_part ]] - return $? - else - echo $device | egrep "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1 - return $? - fi -} - -# -# Check if the given device is a real device (ie SCSI device) -# -function is_real_device #disk -{ - typeset disk=$1 - [[ -z $disk ]] && log_fail "No argument for disk given." - - if is_linux; then - lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \ - egrep disk >/dev/null - return $? - fi -} - -# -# Check if the given device is a loop device -# -function is_loop_device #disk -{ - typeset disk=$1 - [[ -z $disk ]] && log_fail "No argument for disk given." - - if is_linux; then - lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \ - egrep loop >/dev/null - return $? - fi -} - -# -# Check if the given device is a multipath device and if there is a sybolic -# link to a device mapper and to a disk -# Currently no support for dm devices alone without multipath -# -function is_mpath_device #disk -{ - typeset disk=$1 - [[ -z $disk ]] && log_fail "No argument for disk given." - - if is_linux; then - lsblk $DEV_MPATHDIR/$disk -o TYPE 2>/dev/null | \ - egrep mpath >/dev/null - if (($? == 0)); then - readlink $DEV_MPATHDIR/$disk > /dev/null 2>&1 - return $? - else - return $? - fi - fi -} - -# Set the slice prefix for disk partitioning depending -# on whether the device is a real, multipath, or loop device. -# Currently all disks have to be of the same type, so only -# checks first disk to determine slice prefix. -# -function set_slice_prefix -{ - typeset disk - typeset -i i=0 - - if is_linux; then - while (( i < $DISK_ARRAY_NUM )); do - disk="$(echo $DISKS | nawk '{print $(i + 1)}')" - if ( is_mpath_device $disk ) && [[ -z $(echo $disk | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $disk ); then - export SLICE_PREFIX="" - return 0 - elif ( is_mpath_device $disk || is_loop_device \ - $disk ); then - export SLICE_PREFIX="p" - return 0 - else - log_fail "$disk not supported for partitioning." - fi - (( i = i + 1)) - done - fi -} - -# -# Set the directory path of the listed devices in $DISK_ARRAY_NUM -# Currently all disks have to be of the same type, so only -# checks first disk to determine device directory -# default = /dev (linux) -# real disk = /dev (linux) -# multipath device = /dev/mapper (linux) -# -function set_device_dir -{ - typeset disk - typeset -i i=0 - - if is_linux; then - while (( i < $DISK_ARRAY_NUM )); do - disk="$(echo $DISKS | nawk '{print $(i + 1)}')" - if is_mpath_device $disk; then - export DEV_DSKDIR=$DEV_MPATHDIR - return 0 - else - export DEV_DSKDIR=$DEV_RDSKDIR - return 0 - fi - (( i = i + 1)) - done - else - export DEV_DSKDIR=$DEV_RDSKDIR - fi -} - -# -# Get the directory path of given device -# -function get_device_dir #device -{ - typeset device=$1 - - if ! $(is_physical_device $device) ; then - if [[ $device != "/" ]]; then - device=${device%/*} - fi - if [[ -b "$DEV_DSKDIR/$device" ]]; then - device="$DEV_DSKDIR" - fi - echo $device - else - echo "$DEV_DSKDIR" - fi -} - -# -# Get persistent name for given disk -# -function get_persistent_disk_name #device -{ - typeset device=$1 - typeset dev_id - - if is_linux; then - if is_real_device $device; then - dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \ - | egrep disk/by-id | nawk '{print $2; exit}' \ - | nawk -F / '{print $3}')" - echo $dev_id - elif is_mpath_device $device; then - dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \ - | egrep disk/by-id/dm-uuid \ - | nawk '{print $2; exit}' \ - | nawk -F / '{print $3}')" - echo $dev_id - else - echo $device - fi - else - echo $device - fi -} - -# -# Load scsi_debug module with specified parameters -# -function load_scsi_debug # dev_size_mb add_host num_tgts max_luns -{ - typeset devsize=$1 - typeset hosts=$2 - typeset tgts=$3 - typeset luns=$4 - - [[ -z $devsize ]] || [[ -z $hosts ]] || [[ -z $tgts ]] || \ - [[ -z $luns ]] && log_fail "Arguments invalid or missing" - - if is_linux; then - modprobe -n scsi_debug - if (($? != 0)); then - log_unsupported "Platform does not have scsi_debug" - "module" - fi - lsmod | egrep scsi_debug > /dev/null - if (($? == 0)); then - log_fail "scsi_debug module already installed" - else - log_must modprobe scsi_debug dev_size_mb=$devsize \ - add_host=$hosts num_tgts=$tgts max_luns=$luns - block_device_wait - lsscsi | egrep scsi_debug > /dev/null - if (($? == 1)); then - log_fail "scsi_debug module install failed" - fi - fi - fi -} - -# # Get the package name # function get_package_name diff --git a/tests/zfs-tests/tests/functional/cli_root/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/Makefile.am index acea36bb7..6c70fa13e 100644 --- a/tests/zfs-tests/tests/functional/cli_root/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/Makefile.am @@ -46,6 +46,7 @@ SUBDIRS = \ zpool_offline \ zpool_online \ zpool_remove \ + zpool_reopen \ zpool_replace \ zpool_scrub \ zpool_set \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/Makefile.am new file mode 100644 index 000000000..26de288a8 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/Makefile.am @@ -0,0 +1,12 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_reopen +dist_pkgdata_SCRIPTS = \ + setup.ksh \ + cleanup.ksh \ + zpool_reopen.cfg \ + zpool_reopen.shlib \ + zpool_reopen_001_pos.ksh \ + zpool_reopen_002_pos.ksh \ + zpool_reopen_003_pos.ksh \ + zpool_reopen_004_pos.ksh \ + zpool_reopen_005_pos.ksh \ + zpool_reopen_006_neg.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/cleanup.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/cleanup.ksh new file mode 100755 index 000000000..4477e5402 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/cleanup.ksh @@ -0,0 +1,33 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2016, 2017 by Intel Corporation. All rights reserved. +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +verify_runnable "global" + +cleanup_devices $DISKS + +# Unplug the disk and remove scsi_debug module +if is_linux; then + for SDDEVICE in $(get_debug_device); do + unplug $SDDEVICE + done + modprobe -r scsi_debug +fi + +log_pass diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/setup.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/setup.ksh new file mode 100755 index 000000000..4dbf8965d --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/setup.ksh @@ -0,0 +1,30 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2016, 2017 by Intel Corporation. All rights reserved. +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.cfg + +verify_runnable "global" + +# Create scsi_debug devices for the reopen tests +if is_linux; then + load_scsi_debug $SDSIZE $SDHOSTS $SDTGTS $SDLUNS +else + log_unsupported "scsi debug module unsupported" +fi + +log_pass diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.cfg new file mode 100755 index 000000000..9227cbb18 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.cfg @@ -0,0 +1,47 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2016, 2017 by Intel Corporation. All rights reserved. +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "global" + +export DISK_ARRAY_NUM=$(echo ${DISKS} | nawk '{print NF}') +export DISKSARRAY=$DISKS +export SMALL_FILE_SIZE=10 +export LARGE_FILE_SIZE=80 +export MAXTIMEOUT=40 + +export SDSIZE=256 +export SDHOSTS=1 +export SDTGTS=1 +export SDLUNS=1 + +export DISK1=$(echo $DISKS | nawk '{print $1}') +export DISK2=$(echo $DISKS | nawk '{print $2}') +export DISK3=$(echo $DISKS | nawk '{print $3}') + +if is_linux; then + set_slice_prefix + set_device_dir + devs_id[0]=$(get_persistent_disk_name $DISK1) + devs_id[1]=$(get_persistent_disk_name $DISK2) + devs_id[2]=$(get_persistent_disk_name $DISK3) + export devs_id +else + DEV_DSKDIR="/dev" +fi diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib new file mode 100755 index 000000000..82860deb3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib @@ -0,0 +1,117 @@ +# +# 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. +# +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.cfg + +# +# Clear labels on the given disks +# +function clear_labels #disks +{ + for disk in $@; do + if ( is_loop_device $disk ) || ( is_mpath_device $disk ); then + zpool labelclear -f /dev/$disk + else + zpool labelclear -f /dev/${disk}1 + fi + done +} + +# +# Set the REMOVED_DISK and REMOVED_DISK_ID constants for device +# used for re-plugging. When the disk is loop device use the +# scsi_debug emulated drive. Otherwise use the real drive. +# +function set_removed_disk +{ + if is_loop_device $DISK1; then + export REMOVED_DISK=$(get_debug_device) + export REMOVED_DISK_ID=$(get_persistent_disk_name $REMOVED_DISK) + elif ( is_real_device $DISK1 ) || ( is_mpath_device $DISK1 ); then + export REMOVED_DISK="$DISK1" + export REMOVED_DISK_ID=${devs_id[0]} + else + log_fail "No drives that supports removal" + fi +} + +# +# Generate random file of the given size in MiB +# +function generate_random_file #path size_mb +{ + typeset path=$1 + typeset -i size_mb=$2 + file_write -o create -f $path -b 1048576 -s0 -c $size_mb -d R +} + +# +# Wait until specific event or timeout occur. +# +# The passed function is executed with pool name as argument +# with an interval of 1 second until it succeeds or until the +# timeout occurs. +# It returns 1 on timeout or 0 otherwise. +# +function wait_for_action #pool timeout function +{ + typeset pool=$1 + typeset -i timeout=$2 + typeset func=$3 + + while [ $timeout -gt 0 ]; do + (( --timeout )) + if ( $func $pool ); then + return 0 + fi + sleep 1 + done + + return 1 +} + +# +# Helpers for wait_for_action function: +# wait_for_resilver_start - wait until resilver is started +# wait_for_resilver_end - wait until resilver is finished +# wait_for_scrub_end - wait until scrub is finished +# +function wait_for_resilver_start #pool timeout +{ + wait_for_action $1 $2 is_pool_resilvering + return $? +} + +function wait_for_resilver_end #pool timeout +{ + wait_for_action $1 $2 is_pool_resilvered + return $? +} + +function wait_for_scrub_end #pool timeout +{ + wait_for_action $1 $2 is_pool_scrubbed + return $? +} + +# +# Check if scan action has been restarted on the given pool +# + +function is_scan_restarted #pool +{ + typeset pool=$1 + zpool history -i $pool | grep -q "scan aborted, restarting" + return $? +} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_001_pos.ksh new file mode 100755 index 000000000..68ebf669c --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_001_pos.ksh @@ -0,0 +1,70 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +# +# DESCRIPTION: +# Test if zpool reopen with no arguments works correctly. +# +# STRATEGY: +# 1. Create a pool. +# 2. Remove a disk. +# 3. Reopen a pool and verify if removed disk is marked as unavailable. +# 4. "Plug back" disk. +# 5. Reopen a pool and verify if removed disk is marked online again. +# 6. Check if reopen caused resilver start. +# + +verify_runnable "global" + +function cleanup +{ + # bring back removed disk online for further tests + insert_disk $REMOVED_DISK $scsi_host + poolexists $TESTPOOL && destroy_pool $TESTPOOL + clear_labels $REMOVED_DISK $DISK2 +} + +log_assert "Testing zpool reopen with no arguments" +log_onexit cleanup + +set_removed_disk +scsi_host=$(get_scsi_host $REMOVED_DISK) + +# 1. Create a pool. +default_mirror_setup_noexit $REMOVED_DISK_ID $DISK2 +# 2. Remove a disk. +remove_disk $REMOVED_DISK +# 3. Reopen a pool and verify if removed disk is marked as unavailable. +log_must zpool reopen +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "unavail" +# Write some data to the pool +log_must generate_random_file /$TESTPOOL/data $SMALL_FILE_SIZE +# 4. "Plug back" disk. +insert_disk $REMOVED_DISK $scsi_host +# 5. Reopen a pool and verify if removed disk is marked online again. +log_must zpool reopen +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "online" +# 6. Check if reopen caused resilver start. +log_must wait_for_resilver_end $TESTPOOL $MAXTIMEOUT + +# clean up +log_must zpool destroy $TESTPOOL +clear_labels $REMOVED_DISK $DISK2 + +log_pass "Zpool reopen with no arguments test passed" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_002_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_002_pos.ksh new file mode 100755 index 000000000..444c8a685 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_002_pos.ksh @@ -0,0 +1,70 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +# +# DESCRIPTION: +# Test if zpool reopen with pool name as argument works correctly. +# +# STRATEGY: +# 1. Create a pool. +# 2. Remove a disk. +# 3. Reopen a pool and verify if removed disk is marked as unavailable. +# 4. "Plug back" disk. +# 5. Reopen a pool and verify if removed disk is marked online again. +# 6. Check if reopen caused resilver start. +# + +verify_runnable "global" + +function cleanup +{ + # bring back removed disk online for further tests + insert_disk $REMOVED_DISK $scsi_host + poolexists $TESTPOOL && destroy_pool $TESTPOOL + clear_labels $REMOVED_DISK $DISK2 +} + +log_assert "Testing zpool reopen with no arguments" +log_onexit cleanup + +set_removed_disk +scsi_host=$(get_scsi_host $REMOVED_DISK) + +# 1. Create a pool. +default_mirror_setup_noexit $REMOVED_DISK_ID $DISK2 +# 2. Remove a disk. +remove_disk $REMOVED_DISK +# 3. Reopen a pool and verify if removed disk is marked as unavailable. +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "unavail" +# Write some data to the pool +log_must generate_random_file /$TESTPOOL/data $SMALL_FILE_SIZE +# 4. "Plug back" disk. +insert_disk $REMOVED_DISK $scsi_host +# 5. Reopen a pool and verify if removed disk is marked online again. +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "online" +# 6. Check if reopen caused resilver start. +log_must wait_for_resilver_end $TESTPOOL $MAXTIMEOUT + +# clean up +log_must zpool destroy $TESTPOOL +clear_labels $REMOVED_DISK $DISK2 + +log_pass "Zpool reopen with no arguments test passed" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_003_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_003_pos.ksh new file mode 100755 index 000000000..42bc457ea --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_003_pos.ksh @@ -0,0 +1,101 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +# +# DESCRIPTION: +# Test zpool reopen while scrub is running. +# Checks if re-plugged device is fully resilvered. +# +# STRATEGY: +# 1. Create a pool +# 2. Remove a disk. +# 3. Write a test file to the pool and calculate its checksum. +# 4. Execute scrub. +# 5. "Plug back" disk. +# 6. Reopen a pool. +# 7. Check if scrub scan is replaced by resilver. +# 8. Put another device offline and check if the test file checksum is correct. +# +# NOTES: +# A 25ms delay is added to make sure that the scrub is running while +# the reopen kicks the resilver. +# + +verify_runnable "global" + +function cleanup +{ + log_must zinject -c all + rm -f $TESTFILE_MD5 2>/dev/null + # bring back removed disk online for further tests + insert_disk $REMOVED_DISK $scsi_host + poolexists $TESTPOOL && destroy_pool $TESTPOOL +} + +log_assert "Testing zpool reopen with pool name as argument" +log_onexit cleanup + +set_removed_disk +scsi_host=$(get_scsi_host $REMOVED_DISK) + +# 1. Create a pool +default_mirror_setup_noexit $REMOVED_DISK_ID $DISK2 +# 2. Remove a disk. +remove_disk $REMOVED_DISK + +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "unavail" + +# 3. Write a test file to the pool and calculate its checksum. +TESTFILE=/$TESTPOOL/data +TESTFILE_MD5=$(mktemp --tmpdir=/var/tmp) +log_must generate_random_file /$TESTPOOL/data $LARGE_FILE_SIZE +log_must md5sum $TESTFILE > $TESTFILE_MD5 + +# 4. Execute scrub. +# add delay to I/O requests for remaining disk in pool +log_must zinject -d $DISK2 -D25:1 $TESTPOOL +log_must zpool scrub $TESTPOOL + +# 5. "Plug back" disk. +insert_disk $REMOVED_DISK $scsi_host +# 6. Reopen a pool. +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "online" +# 7. Check if scrub scan is replaced by resilver. +# the scrub operation has to be running while reopen is executed +log_must is_pool_scrubbing $TESTPOOL true +# the scrub will be replaced by resilver, wait until it ends +log_must wait_for_resilver_end $TESTPOOL $MAXTIMEOUT +# check if the scrub scan has been interrupted by resilver +log_must is_scan_restarted $TESTPOOL +# remove delay from disk +log_must zinject -c all + +# 8. Put another device offline and check if the test file checksum is correct. +log_must zpool offline $TESTPOOL $DISK2 +log_must md5sum -c $TESTFILE_MD5 +log_must zpool online $TESTPOOL $DISK2 +sleep 1 + +# clean up +rm -f $TESTFILE_MD5 2>/dev/null +log_must zpool destroy $TESTPOOL + +log_pass "Zpool reopen test successful" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh new file mode 100755 index 000000000..d61283d14 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh @@ -0,0 +1,88 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +# +# DESCRIPTION: +# Test zpool reopen -n while scrub is running. +# Checks if re-plugged device is NOT resilvered. +# +# STRATEGY: +# 1. Create a pool +# 2. Remove a disk. +# 3. Write test file to pool. +# 4. Execute scrub. +# 5. "Plug back" disk. +# 6. Reopen a pool with an -n flag. +# 7. Check if scrub scan is NOT replaced by resilver. +# 8. Check if trying to put device to offline fails because of no valid +# replicas. +# +# NOTES: +# A 25ms delay is added to make sure that the scrub is running while +# the reopen is invoked. +# + +verify_runnable "global" + +function cleanup +{ + log_must zinject -c all + # bring back removed disk online for further tests + insert_disk $REMOVED_DISK $scsi_host + poolexists $TESTPOOL && destroy_pool $TESTPOOL +} + +log_assert "Testing zpool reopen with pool name as argument" +log_onexit cleanup + +set_removed_disk +scsi_host=$(get_scsi_host $REMOVED_DISK) + +# 1. Create a pool +default_mirror_setup_noexit $REMOVED_DISK_ID $DISK2 +# 2. Remove a disk. +remove_disk $REMOVED_DISK +log_must zpool reopen -n $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "unavail" +# 3. Write test file to pool. +log_must generate_random_file /$TESTPOOL/data $LARGE_FILE_SIZE +# 4. Execute scrub. +# add delay to I/O requests for remaining disk in pool +log_must zinject -d $DISK2 -D25:1 $TESTPOOL +log_must zpool scrub $TESTPOOL +# 5. "Plug back" disk. +insert_disk $REMOVED_DISK $scsi_host +# 6. Reopen a pool with an -n flag. +log_must zpool reopen -n $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "online" +# 7. Check if scrub scan is NOT replaced by resilver. +log_must wait_for_scrub_end $TESTPOOL $MAXTIMEOUT +log_mustnot is_scan_restarted $TESTPOOL + +# remove delay from disk +log_must zinject -c all + +# 8. Check if trying to put device to offline fails because of no valid +# replicas. +log_mustnot zpool offline $TESTPOOL $DISK2 + +# clean up +log_must zpool destroy $TESTPOOL + +log_pass "Zpool reopen test successful" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_005_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_005_pos.ksh new file mode 100755 index 000000000..95029a8b6 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_005_pos.ksh @@ -0,0 +1,86 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/tests/functional/cli_root/zpool_reopen/zpool_reopen.shlib + +# +# DESCRIPTION: +# Test zpool reopen -n while resilver is running. +# Checks if the resilver is restarted. +# +# STRATEGY: +# 1. Create a pool +# 2. Remove a disk. +# 3. Write test file to pool. +# 4. "Plug back" disk. +# 5. Reopen a pool and wait until resilvering is started. +# 6. Reopen a pool again with -n flag. +# 7. Wait until resilvering is finished and check if it was restarted. +# +# NOTES: +# A 25ms delay is added to make sure that the resilver is running while +# the reopen is invoked. +# + +verify_runnable "global" + +function cleanup +{ + log_must zinject -c all + insert_disk $REMOVED_DISK $scsi_host + poolexists $TESTPOOL && destroy_pool $TESTPOOL +} + +log_assert "Testing zpool reopen with pool name as argument" +log_onexit cleanup + +set_removed_disk +scsi_host=$(get_scsi_host $REMOVED_DISK) + +# 1. Create a pool +default_mirror_setup_noexit $REMOVED_DISK_ID $DISK2 +# 2. Remove a disk. +remove_disk $REMOVED_DISK + +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "unavail" +# 3. Write test file to pool. +log_must generate_random_file /$TESTPOOL/data $LARGE_FILE_SIZE +# 4. "Plug back" disk. +insert_disk $REMOVED_DISK $scsi_host + +# 5. Reopen a pool and wait until resilvering is started. +log_must zpool reopen $TESTPOOL +log_must check_state $TESTPOOL "$REMOVED_DISK_ID" "online" +# add delay to I/O requests for the reopened disk +log_must zinject -d $REMOVED_DISK_ID -D25:1 $TESTPOOL +# wait until resilver starts +log_must wait_for_resilver_start $TESTPOOL $MAXTIMEOUT + +# 6. Reopen a pool again with -n flag. +zpool reopen -n $TESTPOOL + +# 7. Wait until resilvering is finished and check if it was restarted. +log_must wait_for_resilver_end $TESTPOOL $MAXTIMEOUT +# remove delay from disk +log_must zinject -c all +log_must is_scan_restarted $TESTPOOL + +# clean up +log_must zpool destroy $TESTPOOL + +log_pass "Zpool reopen test successful" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_006_neg.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_006_neg.ksh new file mode 100755 index 000000000..6533bde68 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_006_neg.ksh @@ -0,0 +1,43 @@ +#!/bin/ksh -p + +# +# 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. +# + +# +# Copyright (c) 2017 Open-E, Inc. All Rights Reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Wrong arguments passed to zpool reopen should cause an error. +# +# STRATEGY: +# 1. Create an array with bad 'zpool reopen' arguments. +# 2. For each argument execute the 'zpool reopen' command and verify +# if it returns an error. +# + +verify_runnable "global" + +# 1. Create an array with bad 'zpool reopen' arguments. +typeset -a args=("!" "1" "-s" "--n" "-1" "-" "-c" "-f" "-d 2" "-abc" "-na") + +log_assert "Test 'zpool reopen' with invalid arguments." + +# 2. For each argument execute the 'zpool reopen' command and verify +# if it returns an error. +for arg in ${args[@]}; do + log_mustnot zpool reopen $arg +done + +log_pass "Passing invalid arguments to 'zpool reopen' failed as expected." diff --git a/tests/zfs-tests/tests/functional/fault/auto_online_001_pos.ksh b/tests/zfs-tests/tests/functional/fault/auto_online_001_pos.ksh index bf09816bc..50f721c27 100755 --- a/tests/zfs-tests/tests/functional/fault/auto_online_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/fault/auto_online_001_pos.ksh @@ -55,7 +55,7 @@ fi function cleanup { #online last disk before fail - on_off_disk $offline_disk "online" $host + insert_disk $offline_disk $host poolexists $TESTPOOL && destroy_pool $TESTPOOL } @@ -98,11 +98,10 @@ for offline_disk in $autoonline_disks do log_must zpool export -F $TESTPOOL - host=$(ls /sys/block/$offline_disk/device/scsi_device \ - | nawk -F : '{ print $1}') + host=$(get_scsi_host $offline_disk) # Offline disk - on_off_disk $offline_disk "offline" + remove_disk $offline_disk # Reimport pool with drive missing log_must zpool import $TESTPOOL @@ -115,7 +114,7 @@ do zpool events -c $TESTPOOL # Online disk - on_off_disk $offline_disk "online" $host + insert_disk $offline_disk $host log_note "Delay for ZED auto-online" typeset -i timeout=0 diff --git a/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh b/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh index 24f128c3d..0f71a575e 100755 --- a/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh @@ -110,7 +110,7 @@ log_must mkfile $FSIZE /$TESTPOOL/data log_must zpool export -F $TESTPOOL # Offline disk -on_off_disk $SD "offline" +remove_disk $SD block_device_wait log_must modprobe -r scsi_debug diff --git a/tests/zfs-tests/tests/functional/fault/cleanup.ksh b/tests/zfs-tests/tests/functional/fault/cleanup.ksh index f39f05d6f..82e379b0d 100755 --- a/tests/zfs-tests/tests/functional/fault/cleanup.ksh +++ b/tests/zfs-tests/tests/functional/fault/cleanup.ksh @@ -33,14 +33,12 @@ cleanup_devices $DISKS zed_stop zed_cleanup -SD=$(lsscsi | nawk '/scsi_debug/ {print $6; exit}') -SDDEVICE=$(echo $SD | nawk -F / '{print $3}') +SDDEVICE=$(get_debug_device) # Offline disk and remove scsi_debug module if is_linux; then if [ -n "$SDDEVICE" ]; then - on_off_disk $SDDEVICE "offline" - block_device_wait + remove_disk $SDDEVICE fi modprobe -r scsi_debug fi |