]> git.proxmox.com Git - mirror_zfs.git/commitdiff
OpenZFS 8600 - ZFS channel programs - snapshot
authorChris Williamson <chris.williamson@delphix.com>
Thu, 8 Feb 2018 16:24:39 +0000 (09:24 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 8 Feb 2018 23:29:24 +0000 (15:29 -0800)
Authored by: Chris Williamson <chris.williamson@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: Brad Lewis <brad.lewis@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Ported-by: Don Brady <don.brady@delphix.com>
ZFS channel programs should be able to create snapshots.
In addition to the base snapshot functionality, this entails extra
logic to handle edge cases which were formerly not possible, such as
creating then destroying a snapshot in the same transaction sync.

OpenZFS-issue: https://www.illumos.org/issues/8600
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/68089b8b

22 files changed:
include/sys/dsl_dataset.h
include/sys/zcp.h
lib/libzfs_core/libzfs_core.c
man/man8/zfs-program.8
module/zfs/dsl_dataset.c
module/zfs/zcp.c
module/zfs/zcp_global.c
module/zfs/zcp_synctask.c
module/zfs/zfs_ioctl.c
tests/runfiles/linux.run
tests/zfs-tests/tests/functional/channel_program/lua_core/Makefile.am
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile.am
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp [new file with mode: 0644]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp [new file with mode: 0644]

index ee822a2014078388ec85518c4ee31bb237617a6c..0030fca24444afcbc439025b5d7dd2a09c8a9d5e 100644 (file)
@@ -252,6 +252,13 @@ typedef struct dsl_dataset_rollback_arg {
        nvlist_t *ddra_result;
 } dsl_dataset_rollback_arg_t;
 
+typedef struct dsl_dataset_snapshot_arg {
+       nvlist_t *ddsa_snaps;
+       nvlist_t *ddsa_props;
+       nvlist_t *ddsa_errors;
+       cred_t *ddsa_cr;
+} dsl_dataset_snapshot_arg_t;
+
 /*
  * The max length of a temporary tag prefix is the number of hex digits
  * required to express UINT64_MAX plus one for the hyphen.
@@ -296,6 +303,8 @@ uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname,
     struct dsl_crypto_params *, dmu_tx_t *);
 uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
     struct dsl_crypto_params *dcp, uint64_t flags, dmu_tx_t *tx);
+void dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx);
+int dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx);
 int dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors);
 void dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx);
 int dsl_dataset_promote_check(void *arg, dmu_tx_t *tx);
index ca9719ecf896e2b392363eee66a388331894017f..df13bf2302af18e5f6424dd54aae654c52c12161 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 /*
- * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_ZCP_H
@@ -137,8 +137,6 @@ typedef struct zcp_lib_info {
        const zcp_arg_t kwargs[2];
 } zcp_lib_info_t;
 
-int zcp_nvlist_to_lua(lua_State *, nvlist_t *, char *, int);
-
 #ifdef __cplusplus
 }
 #endif
index 2fa035e671b25b0b0510d813c925fc2dda91f802..ca0b3cfb5d88890884d91ea4b6b1daa796cad3c9 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2017 Datto Inc.
  * Copyright 2017 RackTop Systems.
@@ -146,7 +146,12 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
 
        if (resultp != NULL) {
                *resultp = NULL;
-               zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
+               if (ioc == ZFS_IOC_CHANNEL_PROGRAM) {
+                       zc.zc_nvlist_dst_size = fnvlist_lookup_uint64(source,
+                           ZCP_ARG_MEMLIMIT);
+               } else {
+                       zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
+               }
                zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
                    malloc(zc.zc_nvlist_dst_size);
                if (zc.zc_nvlist_dst == (uint64_t)0) {
@@ -160,7 +165,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
                 * If ioctl exited with ENOMEM, we retry the ioctl after
                 * increasing the size of the destination nvlist.
                 *
-                * Channel programs that exit with ENOMEM probably ran over the
+                * Channel programs that exit with ENOMEM ran over the
                 * lua memory sandbox; they should not be retried.
                 */
                if (errno == ENOMEM && resultp != NULL &&
index 4c7d86ef12ecc0e754a1799345926097209fb659..b1d937b6e600426b3f2034667a685313558e8b7f 100644 (file)
@@ -372,6 +372,18 @@ filesystem (string)
 .Bd -ragged -compact -offset "xxxx"
 Filesystem to rollback.
 .Ed
+.It Em zfs.sync.snapshot(dataset)
+Create a snapshot of a filesystem.
+Returns 0 if the snapshot was successfully created,
+and a nonzero error code otherwise.
+.Pp
+Note: Taking a snapshot will fail on any pool older than legacy version 27.
+To enable taking snapshots from ZCP scripts, the pool must be upgraded.
+.Pp
+dataset (string)
+.Bd -ragged -compact -offset "xxxx"
+Name of snapshot to create.
+.Ed
 .El
 .It Sy zfs.check submodule
 For each function in the zfs.sync submodule, there is a corresponding zfs.check
@@ -392,6 +404,7 @@ The available zfs.check functions are:
 .It Em zfs.check.destroy(dataset, [defer=true|false])
 .It Em zfs.check.promote(dataset)
 .It Em zfs.check.rollback(filesystem)
+.It Em zfs.check.snapshot(dataset)
 .El
 .It Sy zfs.list submodule
 The zfs.list submodule provides functions for iterating over datasets and
index a35ba1f7ed6a04c966f7248911a2043fcdf36ca7..0bfc4cd7a24d24c457ab2f3d7ac48fbbbfa3dc8b 100644 (file)
@@ -1140,13 +1140,6 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
        return (0);
 }
 
-typedef struct dsl_dataset_snapshot_arg {
-       nvlist_t *ddsa_snaps;
-       nvlist_t *ddsa_props;
-       nvlist_t *ddsa_errors;
-       cred_t *ddsa_cr;
-} dsl_dataset_snapshot_arg_t;
-
 int
 dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
     dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr)
@@ -1206,7 +1199,7 @@ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
        return (0);
 }
 
-static int
+int
 dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_snapshot_arg_t *ddsa = arg;
@@ -1486,7 +1479,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
 }
 
-static void
+void
 dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_snapshot_arg_t *ddsa = arg;
index 83560309b3ad2c87a22b9bc7f2f8a29861175ee2..1a39330d363a069eccfe1974fab1dd1d52cbb348 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 /*
- * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
  */
 
 /*
 #define        KM_NORMALPRI    0
 #endif
 
+#define        ZCP_NVLIST_MAX_DEPTH 20
+
 uint64_t zfs_lua_check_instrlimit_interval = 100;
 uint64_t zfs_lua_max_instrlimit = ZCP_MAX_INSTRLIMIT;
 uint64_t zfs_lua_max_memlimit = ZCP_MAX_MEMLIMIT;
 
+/*
+ * Forward declarations for mutually recursive functions
+ */
 static int zcp_nvpair_value_to_lua(lua_State *, nvpair_t *, char *, int);
 static int zcp_lua_to_nvlist_impl(lua_State *, int, nvlist_t *, const char *,
     int);
@@ -217,8 +222,6 @@ zcp_cleanup(lua_State *state)
        }
 }
 
-#define        ZCP_NVLIST_MAX_DEPTH 20
-
 /*
  * Convert the lua table at the given index on the Lua stack to an nvlist
  * and return it.
index b6c3c3a4faf9b22a1faea763cf3e434b5c5ce18e..8e166e0736d6b3f5c339e48f57440b7267133443 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 /*
- * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
  */
 
 #include <sys/zcp_global.h>
@@ -62,7 +62,12 @@ static const zcp_errno_global_t errno_globals[] = {
        {"EPIPE", EPIPE},
        {"EDOM", EDOM},
        {"ERANGE", ERANGE},
+       {"EDEADLK", EDEADLK},
+       {"ENOLCK", ENOLCK},
+       {"ECANCELED", ECANCELED},
+       {"ENOTSUP", ENOTSUP},
        {"EDQUOT", EDQUOT},
+       {"ENAMETOOLONG", ENAMETOOLONG},
        {0, 0}
 };
 
index 93797e9f354ac562151fc4c071e997ab9f92b6c3..ad9bffacb46c6a0a228aa3c91446553d140f9a0f 100644 (file)
@@ -39,10 +39,10 @@ typedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *);
 typedef struct zcp_synctask_info {
        const char *name;
        zcp_synctask_func_t *func;
-       zfs_space_check_t space_check;
-       int blocks_modified;
        const zcp_arg_t pargs[4];
        const zcp_arg_t kwargs[2];
+       zfs_space_check_t space_check;
+       int blocks_modified;
 } zcp_synctask_info_t;
 
 /*
@@ -91,8 +91,6 @@ static int zcp_synctask_destroy(lua_State *, boolean_t, nvlist_t *);
 static zcp_synctask_info_t zcp_synctask_destroy_info = {
        .name = "destroy",
        .func = zcp_synctask_destroy,
-       .space_check = ZFS_SPACE_CHECK_NONE,
-       .blocks_modified = 0,
        .pargs = {
            {.za_name = "filesystem | snapshot", .za_lua_type = LUA_TSTRING},
            {NULL, 0}
@@ -100,7 +98,9 @@ static zcp_synctask_info_t zcp_synctask_destroy_info = {
        .kwargs = {
            {.za_name = "defer", .za_lua_type = LUA_TBOOLEAN},
            {NULL, 0}
-       }
+       },
+       .space_check = ZFS_SPACE_CHECK_NONE,
+       .blocks_modified = 0
 };
 
 /* ARGSUSED */
@@ -140,19 +140,19 @@ zcp_synctask_destroy(lua_State *state, boolean_t sync, nvlist_t *err_details)
        return (err);
 }
 
-static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *err_details);
+static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *);
 static zcp_synctask_info_t zcp_synctask_promote_info = {
        .name = "promote",
        .func = zcp_synctask_promote,
-       .space_check = ZFS_SPACE_CHECK_RESERVED,
-       .blocks_modified = 3,
        .pargs = {
            {.za_name = "clone", .za_lua_type = LUA_TSTRING},
            {NULL, 0}
        },
        .kwargs = {
            {NULL, 0}
-       }
+       },
+       .space_check = ZFS_SPACE_CHECK_RESERVED,
+       .blocks_modified = 3
 };
 
 static int
@@ -208,6 +208,58 @@ zcp_synctask_rollback(lua_State *state, boolean_t sync, nvlist_t *err_details)
        return (err);
 }
 
+static int zcp_synctask_snapshot(lua_State *, boolean_t, nvlist_t *);
+static zcp_synctask_info_t zcp_synctask_snapshot_info = {
+       .name = "snapshot",
+       .func = zcp_synctask_snapshot,
+       .pargs = {
+           {.za_name = "filesystem@snapname | volume@snapname",
+           .za_lua_type = LUA_TSTRING},
+           {NULL, 0}
+       },
+       .kwargs = {
+           {NULL, 0}
+       },
+       .space_check = ZFS_SPACE_CHECK_NORMAL,
+       .blocks_modified = 3
+};
+
+/* ARGSUSED */
+static int
+zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
+{
+       int err;
+       dsl_dataset_snapshot_arg_t ddsa = { 0 };
+       const char *dsname = lua_tostring(state, 1);
+       zcp_run_info_t *ri = zcp_run_info(state);
+
+       /*
+        * We only allow for a single snapshot rather than a list, so the
+        * error list output is unnecessary.
+        */
+       ddsa.ddsa_errors = NULL;
+       ddsa.ddsa_props = NULL;
+       ddsa.ddsa_cr = ri->zri_cred;
+       ddsa.ddsa_snaps = fnvlist_alloc();
+       fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);
+
+       /*
+        * On old pools, the ZIL must not be active when a snapshot is created,
+        * but we can't suspend the ZIL because we're already in syncing
+        * context.
+        */
+       if (spa_version(ri->zri_pool->dp_spa) < SPA_VERSION_FAST_SNAP) {
+               return (ENOTSUP);
+       }
+
+       err = zcp_sync_task(state, dsl_dataset_snapshot_check,
+           dsl_dataset_snapshot_sync, &ddsa, sync, dsname);
+
+       fnvlist_free(ddsa.ddsa_snaps);
+
+       return (err);
+}
+
 void
 zcp_synctask_wrapper_cleanup(void *arg)
 {
@@ -279,6 +331,7 @@ zcp_load_synctask_lib(lua_State *state, boolean_t sync)
                &zcp_synctask_destroy_info,
                &zcp_synctask_promote_info,
                &zcp_synctask_rollback_info,
+               &zcp_synctask_snapshot_info,
                NULL
        };
 
index a8f37fe847e48d2e83bf85d4d6bdb54dd7591fc4..8b0cbb40b1214f7f5345264c49e35a4ae0ebd903 100644 (file)
@@ -3695,7 +3695,7 @@ zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl,
 
        if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
                return (EINVAL);
-       if (memlimit == 0 || memlimit > ZCP_MAX_MEMLIMIT)
+       if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
                return (EINVAL);
 
        return (zcp_eval(poolname, program, instrlimit, memlimit,
index 0320301d2473026e651d20cf6fbe49b2ff5b6cb2..a844d6b1bc2ed7122cb75164dfb37834d8465a9e 100644 (file)
@@ -67,8 +67,9 @@ tests = ['tst.args_to_lua', 'tst.divide_by_zero', 'tst.exists',
     'tst.integer_illegal', 'tst.integer_overflow', 'tst.language_functions_neg',
     'tst.language_functions_pos', 'tst.large_prog', 'tst.memory_limit',
     'tst.nested_neg', 'tst.nested_pos', 'tst.nvlist_to_lua',
-    'tst.recursive_neg', 'tst.recursive_pos', 'tst.return_nvlist_neg',
-    'tst.return_nvlist_pos', 'tst.return_recursive_table', 'tst.timeout']
+    'tst.recursive_neg', 'tst.recursive_pos', 'tst.return_large',
+    'tst.return_nvlist_neg', 'tst.return_nvlist_pos',
+    'tst.return_recursive_table', 'tst.timeout']
 tags = ['functional', 'channel_program', 'lua_core']
 
 [tests/functional/channel_program/synctask_core]
@@ -78,7 +79,9 @@ tests = ['tst.destroy_fs', 'tst.destroy_snap', 'tst.get_count_and_limit',
     'tst.get_userquota', 'tst.get_written', 'tst.list_children',
     'tst.list_clones', 'tst.list_snapshots', 'tst.list_system_props',
     'tst.parse_args_neg', 'tst.promote_conflict', 'tst.promote_multiple',
-    'tst.promote_simple', 'tst.rollback_mult', 'tst.rollback_one']
+    'tst.promote_simple', 'tst.rollback_mult', 'tst.rollback_one',
+    'tst.snapshot_destroy', 'tst.snapshot_neg', 'tst.snapshot_recursive',
+    'tst.snapshot_simple']
 tags = ['functional', 'channel_program', 'synctask_core']
 
 [tests/functional/chattr]
index d733acb0b5dfd256f45f955a5d0e6bcb857ff5cc..dba3da0f1c225c2b94afff94f78d1f7c94aa4ff3 100644 (file)
@@ -26,6 +26,8 @@ dist_pkgdata_SCRIPTS = \
        tst.recursive_neg.ksh \
        tst.recursive_pos.ksh \
        tst.recursive.zcp \
+       tst.return_large.ksh \
+       tst.return_large.zcp \
        tst.return_nvlist_neg.ksh \
        tst.return_nvlist_pos.ksh \
        tst.return_recursive_table.ksh \
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh
new file mode 100755 (executable)
index 0000000..369ad84
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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 Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+#
+# DESCRIPTION: Returning very large (up to the memory limit) lists should
+# function correctly.
+#
+
+verify_runnable "global"
+
+fs=$TESTPOOL/$TESTFS/testchild
+
+function cleanup
+{
+       datasetexists $fs && log_must zfs destroy -R $fs
+}
+
+log_onexit cleanup
+
+log_must zfs create $fs
+
+#
+# Actually checking in the ~500kb expected result of this program would be
+# awful, so we just make sure it was as long as we expected.
+#
+output_lines=$(log_must zfs program $TESTPOOL \
+    $ZCP_ROOT/lua_core/tst.return_large.zcp | wc -l)
+
+[[ $output_lines -lt 5000 ]] &&
+    log_fail "Expected return of full list but only got $output_lines lines"
+
+#
+# Make sure we fail if the return is over the memory limit
+#
+log_mustnot_program $TESTPOOL -m 10000 \
+    $ZCP_ROOT/lua_core/tst.return_large.zcp
+
+log_pass "Large return values work properly"
+
diff --git a/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp b/tests/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp
new file mode 100644 (file)
index 0000000..0ea9f89
--- /dev/null
@@ -0,0 +1,24 @@
+--
+-- 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 Delphix. All rights reserved.
+--
+
+basestring = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ..
+             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ret = {}
+for i=1,5000 do
+    table.insert(ret, basestring)
+end
+
+return ret
index 29bd68eeea3bd017f8481d4964fe39dc29a8cd0e..48b89b5782eb50bfcce21be04945a3f62605e2ec 100644 (file)
@@ -29,4 +29,12 @@ dist_pkgdata_SCRIPTS = \
        tst.promote_multiple.ksh \
        tst.promote_simple.ksh \
        tst.rollback_mult.ksh \
-       tst.rollback_one.ksh
+       tst.rollback_one.ksh \
+       tst.snapshot_destroy.ksh \
+       tst.snapshot_destroy.zcp \
+       tst.snapshot_neg.ksh \
+       tst.snapshot_neg.zcp \
+       tst.snapshot_recursive.ksh \
+       tst.snapshot_recursive.zcp \
+       tst.snapshot_simple.ksh \
+       tst.snapshot_simple.zcp
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh
new file mode 100755 (executable)
index 0000000..98317db
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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 Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+#
+# DESCRIPTION: Creating and destroying snapshots in the same txg should work.
+#
+
+verify_runnable "global"
+
+fs=$TESTPOOL/$TESTFS/testchild
+
+function cleanup
+{
+       datasetexists $fs && log_must zfs destroy -R $fs
+}
+
+log_onexit cleanup
+
+log_must zfs create $fs
+
+log_must_program $TESTPOOL \
+    $ZCP_ROOT/synctask_core/tst.snapshot_destroy.zcp $fs
+
+log_pass "Creating/destroying snapshots in one channel program works"
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp
new file mode 100644 (file)
index 0000000..6fbfb06
--- /dev/null
@@ -0,0 +1,24 @@
+--
+-- 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 Delphix. All rights reserved.
+--
+
+args = ...
+argv = args["argv"]
+
+assert(zfs.sync.snapshot(argv[1] .. "@snap1") == 0)
+assert(zfs.sync.destroy(argv[1] .. "@snap1") == 0)
+
+for s in zfs.list.snapshots(argv[1]) do
+       assert(false)
+end
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh
new file mode 100755 (executable)
index 0000000..c3585c9
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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 Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+#
+# DESCRIPTION: Check various invalid snapshot error cases
+#
+
+verify_runnable "global"
+
+fs1=$TESTPOOL/$TESTFS/testchild1
+fs2=$TESTPOOL/$TESTFS/testchild2
+
+function cleanup
+{
+       for fs in $fs1 $fs2; do
+               datasetexists $fs && log_must zfs destroy -R $fs
+       done
+}
+
+log_onexit cleanup
+
+log_must zfs create $fs1
+log_must zfs create $fs2
+log_must zfs snapshot $fs1@snap1
+
+log_must_program $TESTPOOL $ZCP_ROOT/synctask_core/tst.snapshot_neg.zcp $fs1 $fs2
+
+log_pass "zfs.sync.snapshot returns correct errors on invalid input"
+
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp
new file mode 100644 (file)
index 0000000..5cae324
--- /dev/null
@@ -0,0 +1,35 @@
+--
+-- 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 Delphix. All rights reserved.
+--
+
+args = ...
+argv = args["argv"]
+fs1 = argv[1]
+fs2 = argv[2]
+
+longstring = "a"
+for i=1,9 do
+    longstring = longstring .. longstring
+end
+
+-- invalid snapshot names
+assert(zfs.sync.snapshot("ceci_nest_pas_une_dataset") == EINVAL);
+assert(zfs.sync.snapshot(fs1) == EINVAL)
+assert(zfs.sync.snapshot(fs1 .. "@" .. longstring) == ENAMETOOLONG)
+
+assert(zfs.sync.snapshot(fs2 .. "@snap1") == 0)
+-- only one snapshot of a filesystem is allowed per TXG.
+assert(zfs.sync.snapshot(fs2 .. "@snap2") == EAGAIN)
+-- snapshot already exists
+assert(zfs.sync.snapshot(fs1 .. "@snap1") == EEXIST)
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh
new file mode 100755 (executable)
index 0000000..c0180d9
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+#
+# DESCRIPTION: Construct a set of nested filesystems, then recursively snapshot
+# all of them.
+#
+
+verify_runnable "global"
+
+rootfs=$TESTPOOL/$TESTFS/root
+snapname=snap
+
+function cleanup
+{
+       datasetexists $rootfs && log_must zfs destroy -R $rootfs
+}
+
+log_onexit cleanup
+
+filesystems="$rootfs \
+$rootfs/child1 \
+$rootfs/child1/subchild1 \
+$rootfs/child1/subchild2 \
+$rootfs/child1/subchild3 \
+$rootfs/child2 \
+$rootfs/child2/subchild4 \
+$rootfs/child2/subchild5"
+
+for fs in $filesystems; do
+    log_must zfs create $fs
+done
+
+log_must_program $TESTPOOL \
+    $ZCP_ROOT/synctask_core/tst.snapshot_recursive.zcp $rootfs $snapname
+
+#
+# Make sure all of the snapshots we expect were created.
+#
+for fs in $filesystems; do
+    log_must snapexists $fs@$snapname
+done
+
+log_pass "Recursively snapshotting multiple filesystems works."
+
+
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp
new file mode 100644 (file)
index 0000000..097940d
--- /dev/null
@@ -0,0 +1,28 @@
+--
+-- 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 Delphix. All rights reserved.
+--
+
+args = ...
+argv = args["argv"]
+fs = argv[1]
+snap = argv[2]
+
+function snapshot_recursive(root)
+    assert(zfs.sync.snapshot(root .. "@" .. snap) == 0)
+    for child in zfs.list.children(root) do
+        snapshot_recursive(child)
+    end
+end
+
+snapshot_recursive(fs)
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh
new file mode 100755 (executable)
index 0000000..e818ce9
--- /dev/null
@@ -0,0 +1,40 @@
+#!/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 Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib
+
+#
+# DESCRIPTION: Make sure basic snapshot functionality works in channel programs
+#
+
+verify_runnable "global"
+
+fs=$TESTPOOL/$TESTFS/testchild
+snapname=testsnap
+
+function cleanup
+{
+       datasetexists $fs && log_must zfs destroy -R $fs
+}
+
+log_onexit cleanup
+
+log_must zfs create $fs
+
+log_must_program $TESTPOOL \
+    $ZCP_ROOT/synctask_core/tst.snapshot_simple.zcp $fs $snapname
+
+log_pass "Simple snapshotting works"
diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp
new file mode 100644 (file)
index 0000000..215e013
--- /dev/null
@@ -0,0 +1,26 @@
+--
+-- 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 Delphix. All rights reserved.
+--
+
+-- This program should be invoked as "zfs program <pool> <prog> <fs> <snap>"
+
+args = ...
+argv = args["argv"]
+assert(zfs.sync.snapshot(argv[1] .. "@" .. argv[2]) == 0)
+snaps = {}
+for s in zfs.list.snapshots(argv[1]) do
+       table.insert(snaps, s)
+end
+assert(#snaps == 1)
+assert(snaps[1] == (argv[1] .. "@" .. argv[2]))