From 6917ec825fbd69704c117a94e02220b5b4b8b65a Mon Sep 17 00:00:00 2001 From: Alek P Date: Fri, 19 May 2017 12:33:11 -0700 Subject: [PATCH] Implemented zpool sync command This addition will enable us to sync an open TXG to the main pool on demand. The functionality is similar to 'sync(2)' but 'zpool sync' will return when data has hit the main storage instead of potentially just the ZIL as is the case with the 'sync(2)' cmd. Reviewed-by: Brian Behlendorf Reviewed by: Matthew Ahrens Signed-off-by: Alek Pinchuk --- cmd/zpool/zpool_main.c | 46 ++++++ include/libzfs.h | 2 + include/libzfs_core.h | 2 + include/sys/zfs_ioctl.h | 2 + lib/libzfs/libzfs_pool.c | 21 +++ lib/libzfs_core/libzfs_core.c | 22 ++- man/man8/zpool.8 | 15 ++ module/zfs/zfs_ioctl.c | 45 +++++- tests/runfiles/linux.run | 3 + tests/zfs-tests/include/libtest.shlib | 40 ++++++ .../clean_mirror/clean_mirror_common.kshlib | 4 +- .../tests/functional/cli_root/Makefile.am | 49 +++++++ .../cli_root/zpool_create/create-o_ashift.ksh | 133 ++++++++++++++++++ .../cli_root/zpool_sync/Makefile.am | 6 + .../cli_root/zpool_sync/cleanup.ksh | 32 +++++ .../functional/cli_root/zpool_sync/setup.ksh | 34 +++++ .../zpool_sync/zpool_sync_001_pos.ksh | 88 ++++++++++++ .../zpool_sync/zpool_sync_002_neg.ksh | 44 ++++++ .../upgrade/upgrade_userobj_001_pos.ksh | 100 +++++++++++++ 19 files changed, 680 insertions(+), 8 deletions(-) create mode 100644 tests/zfs-tests/tests/functional/cli_root/Makefile.am create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_create/create-o_ashift.ksh create mode 100644 tests/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile.am create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh create mode 100755 tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 249114b4ae..7ef8b7e9d0 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -27,6 +27,7 @@ * Copyright (c) 2012 by Cyril Plisko. All rights reserved. * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. * Copyright 2016 Nexenta Systems, Inc. + * Copyright 2016 Igor Kozhukhov . * Copyright (c) 2017 Datto Inc. */ @@ -111,6 +112,8 @@ static int zpool_do_events(int, char **); static int zpool_do_get(int, char **); static int zpool_do_set(int, char **); +static int zpool_do_sync(int, char **); + /* * These libumem hooks provide a reasonable set of defaults for the allocator's * debugging facilities. @@ -156,6 +159,7 @@ typedef enum { HELP_GET, HELP_SET, HELP_SPLIT, + HELP_SYNC, HELP_REGUID, HELP_REOPEN } zpool_help_t; @@ -288,6 +292,7 @@ static zpool_command_t command_table[] = { { NULL }, { "get", zpool_do_get, HELP_GET }, { "set", zpool_do_set, HELP_SET }, + { "sync", zpool_do_sync, HELP_SYNC }, }; #define NCOMMAND (ARRAY_SIZE(command_table)) @@ -378,6 +383,8 @@ get_usage(zpool_help_t idx) { "[ ...]\n")); case HELP_REGUID: return (gettext("\treguid \n")); + case HELP_SYNC: + return (gettext("\tsync [pool] ...\n")); } abort(); @@ -2966,6 +2973,45 @@ zpool_do_import(int argc, char **argv) return (err ? 1 : 0); } +/* + * zpool sync [-f] [pool] ... + * + * -f (undocumented) force uberblock (and config including zpool cache file) + * update. + * + * Sync the specified pool(s). + * Without arguments "zpool sync" will sync all pools. + * This command initiates TXG sync(s) and will return after the TXG(s) commit. + * + */ +static int +zpool_do_sync(int argc, char **argv) +{ + int ret; + boolean_t force = B_FALSE; + + /* check options */ + while ((ret = getopt(argc, argv, "f")) != -1) { + switch (ret) { + case 'f': + force = B_TRUE; + break; + case '?': + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + optopt); + usage(B_FALSE); + } + } + + argc -= optind; + argv += optind; + + /* if argc == 0 we will execute zpool_sync_one on all pools */ + ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force); + + return (ret); +} + typedef struct iostat_cbdata { uint64_t cb_flags; int cb_name_flags; diff --git a/include/libzfs.h b/include/libzfs.h index 12aa42e05c..4330e9310f 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -295,6 +295,8 @@ 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_sync_one(zpool_handle_t *, void *); + extern int zpool_vdev_online(zpool_handle_t *, const char *, int, vdev_state_t *); extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t); diff --git a/include/libzfs_core.h b/include/libzfs_core.h index 9260e048e6..00f98a3aea 100644 --- a/include/libzfs_core.h +++ b/include/libzfs_core.h @@ -114,6 +114,8 @@ int lzc_channel_program_nosync(const char *, const char *, uint64_t, int lzc_sync(const char *, nvlist_t *, nvlist_t **); int lzc_reopen(const char *, boolean_t); +int lzc_sync(const char *, nvlist_t *, nvlist_t **); + #ifdef __cplusplus } #endif diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h index 5ebd74632c..fc17a9118e 100644 --- a/include/sys/zfs_ioctl.h +++ b/include/sys/zfs_ioctl.h @@ -591,6 +591,8 @@ typedef enum zfs_ioc { ZFS_IOC_POOL_INITIALIZE, ZFS_IOC_CHANNEL_PROGRAM, + ZFS_IOC_POOL_SYNC, + /* * Linux - 3/64 numbers reserved. */ diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index d47a763912..a2a3fa5092 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -3679,6 +3679,27 @@ zpool_reopen(zpool_handle_t *zhp) return (zpool_standard_error(hdl, errno, msg)); } +/* call into libzfs_core to execute the sync IOCTL per pool */ +int +zpool_sync_one(zpool_handle_t *zhp, void *data) +{ + int ret; + libzfs_handle_t *hdl = zpool_get_handle(zhp); + const char *pool_name = zpool_get_name(zhp); + boolean_t *force = data; + nvlist_t *innvl = fnvlist_alloc(); + + fnvlist_add_boolean_value(innvl, "force", *force); + if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) { + nvlist_free(innvl); + return (zpool_standard_error_fmt(hdl, ret, + dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name)); + } + nvlist_free(innvl); + + return (0); +} + /* * Convert from a devid string to a path. */ diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 1f802532f5..7bfad697ad 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) 2014 Integros [integros.com] * Copyright 2017 RackTop Systems. + * Copyright (c) 2017 Datto Inc. */ /* @@ -135,7 +136,8 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name, ASSERT3S(g_refcount, >, 0); VERIFY3S(g_fd, !=, -1); - (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); + if (name != NULL) + (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); if (source != NULL) { packed = fnvlist_pack(source, &size); @@ -410,6 +412,18 @@ lzc_exists(const char *dataset) return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0); } +/* + * outnvl is unused. + * It was added to preserve the function signature in case it is + * needed in the future. + */ +/*ARGSUSED*/ +int +lzc_sync(const char *pool_name, nvlist_t *innvl, nvlist_t **outnvl) +{ + return (lzc_ioctl(ZFS_IOC_POOL_SYNC, pool_name, innvl, NULL)); +} + /* * Create "user holds" on snapshots. If there is a hold on a snapshot, * the snapshot can not be destroyed. (However, it can be marked for deletion @@ -510,11 +524,7 @@ lzc_release(nvlist_t *holds, nvlist_t **errlist) int lzc_get_holds(const char *snapname, nvlist_t **holdsp) { - int error; - nvlist_t *innvl = fnvlist_alloc(); - error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp); - fnvlist_free(innvl); - return (error); + return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp)); } /* diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index 4df07ada30..84dc56f899 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -173,6 +173,9 @@ .Oo Ar pool Oc Ns ... .Op Ar interval Op Ar count .Nm +.Cm sync +.Oo Ar pool Oc Ns ... +.Nm .Cm upgrade .Nm .Cm upgrade @@ -1803,6 +1806,18 @@ Warnings about pools not using the latest on-disk format will not be included. .El .It Xo .Nm +.Cm sync +.Oo Ar pool Oc Ns ... +.Xc +This command forces all in-core dirty data to be written to the primary pool +storage and not the ZIL. +It will also update administrative information including quota reporting. +Without arguments, +.Sx zpool sync +will sync all pools on the system. +Otherwise, it will sync only the specified pool(s). +.It Xo +.Nm .Cm upgrade .Xc Displays pools which do not have all supported features enabled and pools diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 28ba993856..cab5947420 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -36,7 +36,8 @@ * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Toomas Soome * Copyright 2017 RackTop Systems. - * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2017, loli10K . All rights reserved. */ #define __APPLE_API_PRIVATE @@ -5315,6 +5316,7 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist) static int zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl) { + ASSERT3P(args, ==, NULL); return (dsl_dataset_get_holds(snapname, outnvl)); } @@ -5843,6 +5845,43 @@ zfs_ioc_osx_proxy_dataset(zfs_cmd_t *zc) return (error); } +/* + * Sync the currently open TXG to disk for the specified pool. + * This is somewhat similar to 'zfs_sync()'. + * For cases that do not result in error this ioctl will wait for + * the currently open TXG to commit before returning back to the caller. + * + * innvl: { + * "force" -> when true, force uberblock update even if there is no dirty data. + * In addition this will cause the vdev configuration to be written + * out including updating the zpool cache file. (boolean_t) + * } + * + * onvl is unused + */ +/* ARGSUSED */ +static int +zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl) +{ + int err; + boolean_t force; + spa_t *spa; + + if ((err = spa_open(pool, &spa, FTAG)) != 0) + return (err); + + force = fnvlist_lookup_boolean_value(innvl, "force"); + if (force) { + spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER); + vdev_config_dirty(spa->spa_root_vdev); + spa_config_exit(spa, SCL_CONFIG, FTAG); + } + txg_wait_synced(spa_get_dsl(spa), 0); + + spa_close(spa, FTAG); + + return (err); +} static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST]; @@ -6045,6 +6084,10 @@ zfs_ioctl_init(void) POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); + 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); + /* IOCTLS that use the legacy function signature */ zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 6a5ab5e1bc..50d0f13dc4 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -391,6 +391,9 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_006_neg', 'zpool_upgrade_008_pos', 'zpool_upgrade_009_neg'] +[tests/functional/cli_root/zpool_sync] +tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg'] + # DISABLED: # zfs_share_001_neg - requires additional dependencies # zfs_unshare_001_neg - requires additional dependencies diff --git a/tests/zfs-tests/include/libtest.shlib b/tests/zfs-tests/include/libtest.shlib index bff1d6cc55..abb4625e8c 100644 --- a/tests/zfs-tests/include/libtest.shlib +++ b/tests/zfs-tests/include/libtest.shlib @@ -24,6 +24,7 @@ # Use is subject to license terms. # Copyright (c) 2012, 2017 by Delphix. All rights reserved. # Copyright 2016 Nexenta Systems, Inc. +# Copyright (c) 2017 Lawrence Livermore National Security, LLC. # Copyright (c) 2017 Datto Inc. # @@ -3272,6 +3273,45 @@ function format_zvol # volume_name blockdev mountpoint log_fail "$NEWFS $ZVOL_DEVDIR/$VOL > /dev/null" fi fi + +# +# Sync data to the pool +# +# $1 pool name +# $2 boolean to force uberblock (and config including zpool cache file) update +# +function sync_pool #pool +{ + typeset pool=${1:-$TESTPOOL} + typeset force=${2:-false} + + if [[ $force == true ]]; then + log_must zpool sync -f $pool + else + log_must zpool sync $pool + fi + + return 0 +} + +# +# Sync data to the pool +# +# $1 pool name +# $2 boolean to force uberblock (and config including zpool cache file) update +# +function sync_pool #pool +{ + typeset pool=${1:-$TESTPOOL} + typeset force=${2:-false} + + if [[ $force == true ]]; then + log_must zpool sync -f $pool + else + log_must zpool sync $pool + fi + + return 0 } function unmount_fs_mountpoint # mountpoint diff --git a/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib b/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib index 9467a7c67a..e65c569076 100644 --- a/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib +++ b/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib @@ -25,9 +25,11 @@ # # -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2013, 2016 by Delphix. All rights reserved. +# Copyright (c) 2017 Datto Inc. # +. $STF_SUITE/include/libtest.shlib . $STF_SUITE/tests/functional/clean_mirror/default.cfg # Most of the code related to the clearing of mirrors is duplicated in all diff --git a/tests/zfs-tests/tests/functional/cli_root/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/Makefile.am new file mode 100644 index 0000000000..ff09514856 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/Makefile.am @@ -0,0 +1,49 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root +dist_pkgdata_SCRIPTS = \ + cli_common.kshlib + +SUBDIRS = \ + zdb \ + zfs \ + zfs_clone \ + zfs_copies \ + zfs_create \ + zfs_destroy \ + zfs_get \ + zfs_inherit \ + zfs_mount \ + zfs_promote \ + zfs_property \ + zfs_receive \ + zfs_rename \ + zfs_reservation \ + zfs_rollback \ + zfs_send \ + zfs_set \ + zfs_share \ + zfs_snapshot \ + zfs_unmount \ + zfs_unshare \ + zfs_upgrade \ + zpool \ + zpool_add \ + zpool_attach \ + zpool_clear \ + zpool_create \ + zpool_destroy \ + zpool_detach \ + zpool_expand \ + zpool_export \ + zpool_get \ + zpool_history \ + zpool_import \ + zpool_labelclear \ + zpool_offline \ + zpool_online \ + zpool_remove \ + zpool_replace \ + zpool_scrub \ + zpool_set \ + zpool_status \ + zpool_sync \ + zpool_upgrade diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_create/create-o_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_create/create-o_ashift.ksh new file mode 100755 index 0000000000..6449c8a913 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_create/create-o_ashift.ksh @@ -0,0 +1,133 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2016, loli10K. All rights reserved. +# Copyright (c) 2017 Datto Inc. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib + +# +# DESCRIPTION: +# 'zpool create -o ashift= ...' should work with different ashift +# values. +# +# STRATEGY: +# 1. Create various pools with different ashift values. +# 2. Verify -o ashift= works only with allowed values (9-16). +# Also verify that the lowest number of uberblocks in a label is 16 and +# smallest uberblock size is 8K even with higher ashift values. +# + +verify_runnable "global" + +function cleanup +{ + poolexists $TESTPOOL && destroy_pool $TESTPOOL + log_must rm -f $disk +} + +# +# Commit the specified number of TXGs to the provided pool +# We use 'zpool sync' here because we can't force it via sync(1) like on illumos +# $1 pool name +# $2 number of txg syncs +# +function txg_sync +{ + typeset pool=$1 + typeset -i count=$2 + typeset -i i=0; + + while [ $i -lt $count ] + do + log_must sync_pool $pool true + ((i = i + 1)) + done +} + +# +# Verify device $1 labels contains $2 valid uberblocks in every label +# $1 device +# $2 uberblocks count +# +function verify_device_uberblocks +{ + typeset device=$1 + typeset ubcount=$2 + + zdb -quuul $device | egrep '^(\s+)?Uberblock' | + egrep -v 'invalid$' | awk \ + -v ubcount=$ubcount '{ uberblocks[$0]++; } + END { for (i in uberblocks) { + count++; + if (uberblocks[i] != 4) { exit 1; } + } + if (count != ubcount) { exit 1; } }' + + return $? +} + +log_assert "zpool create -o ashift=' works with different ashift values" +log_onexit cleanup + +disk=$TEST_BASE_DIR/$FILEDISK0 +log_must mkfile $SIZE $disk + +typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16") +# since Illumos 4958 the largest uberblock is 8K so we have at least of 16/label +typeset ubcount=("128" "128" "64" "32" "16" "16" "16" "16") +typeset -i i=0; +while [ $i -lt "${#ashifts[@]}" ] +do + typeset ashift=${ashifts[$i]} + log_must zpool create -o ashift=$ashift $TESTPOOL $disk + typeset pprop=$(get_pool_prop ashift $TESTPOOL) + verify_ashift $disk $ashift + if [[ $? -ne 0 || "$pprop" != "$ashift" ]] + then + log_fail "Pool was created without setting ashift value to "\ + "$ashift (current = $pprop)" + fi + # force 128 txg sync to fill the uberblock ring + txg_sync $TESTPOOL 128 + verify_device_uberblocks $disk ${ubcount[$i]} + if [[ $? -ne 0 ]] + then + log_fail "Pool was created with unexpected number of uberblocks" + fi + # clean things for the next run + log_must zpool destroy $TESTPOOL + log_must zpool labelclear $disk + log_must eval "verify_device_uberblocks $disk 0" + ((i = i + 1)) +done + +typeset badvals=("off" "on" "1" "8" "17" "1b" "ff" "-") +for badval in ${badvals[@]} +do + log_mustnot zpool create -o ashift="$badval" $TESTPOOL $disk +done + +log_pass "zpool create -o ashift=' works with different ashift values" diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile.am new file mode 100644 index 0000000000..7f5f67d1f3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/Makefile.am @@ -0,0 +1,6 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_sync +dist_pkgdata_SCRIPTS = \ + cleanup.ksh \ + setup.ksh \ + zpool_sync_001_pos.ksh \ + zpool_sync_002_neg.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh new file mode 100755 index 0000000000..89c146249e --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/cleanup.ksh @@ -0,0 +1,32 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "global" + +default_cleanup diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh new file mode 100755 index 0000000000..181e62b113 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/setup.ksh @@ -0,0 +1,34 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "global" + +DISK=${DISKS%% *} + +default_setup $DISK diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh new file mode 100755 index 0000000000..4761bacffd --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_001_pos.ksh @@ -0,0 +1,88 @@ +#!/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 Datto Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Verify 'zpool sync' can sync txgs to the pool(s) main vdevs. +# +# STRATEGY: +# 1. Create a pool +# 2. Use zdb to obtain current txg +# 3. Create a file in the pool if we're not using force sync +# 4. Use zpool sync to sync pool +# 5. Verify the new txg is now bigger than the saved one +# + +verify_runnable "global" + +function get_txg { + typeset -i txg=$(zdb -u $1 | sed -n 's/^.*txg = \(.*\)$/\1/p') + echo $txg +} + +set -A args "sync $TESTPOOL" "sync -f $TESTPOOL" "sync" "sync -f" + +log_assert "Verify 'zpool sync' can sync a pool" + +typeset -i i=0 +typeset -i orig_txg=0 +typeset -i new_txg=0 +while [[ $i -lt ${#args[*]} ]]; do + orig_txg=$(get_txg $TESTPOOL) + if ! [[ "${args[i]}" =~ "-f" ]]; then + log_must touch /$TESTPOOL/$i + fi + log_must zpool ${args[i]} + new_txg=$(get_txg $TESTPOOL) + if [[ $orig_txg -ge $new_txg ]]; then + log_fail "'zpool ${args[i]}' failed: txg $orig_txg >= $new_txg" + fi + ((i = i + 1)) +done + +# sync_pool is implemented using 'zpool sync' so let's test it as well + +# make sure we can use sync_pool with force sync explicitly not used +orig_txg=$(get_txg $TESTPOOL) +log_must touch /$TESTPOOL/$i +log_must sync_pool $TESTPOOL false +new_txg=$(get_txg $TESTPOOL) +if [[ $orig_txg -ge $new_txg ]]; then + log_fail "'sync_pool $TESTPOOL false' failed: txg $orig_txg >= $new_txg" +fi + +# make sure we can use sync_pool with force sync explicitly enabled +orig_txg=$(get_txg $TESTPOOL) +log_must sync_pool $TESTPOOL true +new_txg=$(get_txg $TESTPOOL) +if [[ $orig_txg -ge $new_txg ]]; then + log_fail "'sync_pool $TESTPOOL true' failed: txg $orig_txg >= $new_txg" +fi + +# make sure we can use sync_pool with force sync implicitly not used +orig_txg=$(get_txg $TESTPOOL) +log_must touch /$TESTPOOL/$i +log_must sync_pool $TESTPOOL +new_txg=$(get_txg $TESTPOOL) +if [[ $orig_txg -ge $new_txg ]]; then + log_fail "'sync_pool $TESTPOOL' failed: txg $orig_txg >= $new_txg" +fi + +log_pass "'zpool sync' syncs pool as expected." diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh new file mode 100755 index 0000000000..e35a29130c --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_sync/zpool_sync_002_neg.ksh @@ -0,0 +1,44 @@ +#!/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 Datto Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# A badly formed parameter passed to 'zpool sync' should +# return an error. +# +# STRATEGY: +# 1. Create an array containing bad 'zpool sync' parameters. +# 2. For each element, execute the sub-command. +# 3. Verify it returns an error. +# + +verify_runnable "global" + +set -A args "1" "-a" "-?" "--%" "-123456" "0.5" "-o" "-b" "-b no" "-z 2" + +log_assert "Execute 'zpool sync' using invalid parameters." + +typeset -i i=0 +while [[ $i -lt ${#args[*]} ]]; do + log_mustnot zpool sync ${args[i]} + ((i = i + 1)) +done + +log_pass "Invalid parameters to 'zpool sync' fail as expected." diff --git a/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh b/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh new file mode 100755 index 0000000000..dda594f4e2 --- /dev/null +++ b/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh @@ -0,0 +1,100 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2013 by Jinshan Xiong. No rights reserved. +# Copyright (c) 2017 Datto Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# +# Check that zfs upgrade for object count accounting works. +# Since userobjaccounting is a per dataset feature, this test case +# will create multiple dataset and try different upgrade method. +# +# STRATEGY: +# 1. Create a pool with all features disabled +# 2. Create a few dataset for testing +# 3. Make sure automatic upgrade work +# 4. Make sure manual upgrade work +# + +function cleanup +{ + datasetexists $TESTPOOL/fs1 && log_must zfs destroy $TESTPOOL/fs1 + datasetexists $TESTPOOL/fs2 && log_must zfs destroy $TESTPOOL/fs2 +} + +verify_runnable "global" + +log_assert "pool upgrade for userobj accounting should work" +log_onexit cleanup + +log_must mkfiles $TESTDIR/tf $((RANDOM % 1000 + 1)) +log_must zfs create $TESTPOOL/fs1 +log_must mkfiles $TESTDIR/fs1/tf $((RANDOM % 1000 + 1)) +log_must zfs create $TESTPOOL/fs2 +log_must mkfiles $TESTDIR/fs2/tf $((RANDOM % 1000 + 1)) +log_must zfs umount $TESTPOOL/fs2 + +# Make sure userobj accounting is disabled +zfs userspace -o objused -H $TESTPOOL | head -n 1 | grep -q "-" || + log_fail "userobj accounting should be disabled initially" + +# Upgrade zpool to support all features +log_must zpool upgrade $TESTPOOL + +# Make sure userobj accounting is disabled again +zfs userspace -o objused -H $TESTPOOL | head -n 1 | grep -q "-" || + log_fail "userobj accounting should be disabled after pool upgrade" + +# Create a file in fs1 should trigger dataset upgrade +log_must mkfile 1m $TESTDIR/fs1/tf +log_must sleep 1 # upgrade done in the background so let's give it a sec + +# Make sure userobj accounting is working for fs1 +zfs userspace -o objused -H $TESTPOOL/fs1 | head -n 1 | grep -q "-" && + log_fail "userobj accounting should be enabled for $TESTPOOL/fs1" + +# Mount a dataset should trigger upgrade +log_must zfs mount $TESTPOOL/fs2 +log_must sleep 1 # upgrade done in the background so let's give it a sec + +# Make sure userobj accounting is working for fs2 +zfs userspace -o objused -H $TESTPOOL/fs2 | head -n 1 | grep -q "-" && + log_fail "userobj accounting should be enabled for $TESTPOOL/fs2" + +# All in all, after having been through this, the dataset for testpool +# still shouldn't be upgraded +zfs userspace -o objused -H $TESTPOOL | head -n 1 | grep -q "-" || + log_fail "userobj accounting should be disabled for $TESTPOOL" + +# Manual upgrade root dataset +# uses an ioctl which will wait for the upgrade to be done before returning +log_must zfs set version=current $TESTPOOL +zfs userspace -o objused -H $TESTPOOL | head -n 1 | grep -q "-" && + log_fail "userobj accounting should be enabled for $TESTPOOL" + +log_pass "all tests passed - what a lucky day!"