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!"