From 2840dce1a029098fb784afd951d5f98089f850d8 Mon Sep 17 00:00:00 2001 From: Chris Williamson Date: Tue, 17 Jan 2017 10:30:18 -0800 Subject: [PATCH] 8600 ZFS channel programs - snapshot Reviewed by: Matthew Ahrens Reviewed by: John Kennedy Reviewed by: Brad Lewis Approved by: Robert Mustacchi --- usr/src/lib/libzfs_core/common/libzfs_core.c | 11 +++- usr/src/man/man1m/zfs-program.1m | 13 ++++ usr/src/pkg/manifests/system-test-zfstest.mf | 30 +++++++++ .../channel_program/lua_core/tst.return_large.ksh | 54 ++++++++++++++++ .../channel_program/lua_core/tst.return_large.zcp | 24 ++++++++ .../synctask_core/tst.snapshot_destroy.ksh | 39 ++++++++++++ .../synctask_core/tst.snapshot_destroy.zcp | 24 ++++++++ .../synctask_core/tst.snapshot_neg.ksh | 44 ++++++++++++++ .../synctask_core/tst.snapshot_neg.zcp | 35 +++++++++++ .../synctask_core/tst.snapshot_recursive.ksh | 61 +++++++++++++++++++ .../synctask_core/tst.snapshot_recursive.zcp | 28 +++++++++ .../synctask_core/tst.snapshot_simple.ksh | 40 ++++++++++++ .../synctask_core/tst.snapshot_simple.zcp | 26 ++++++++ usr/src/uts/common/fs/zfs/dsl_dataset.c | 11 +--- usr/src/uts/common/fs/zfs/sys/dsl_dataset.h | 9 +++ usr/src/uts/common/fs/zfs/sys/zcp.h | 4 +- usr/src/uts/common/fs/zfs/zcp.c | 9 ++- usr/src/uts/common/fs/zfs/zcp_global.c | 7 ++- usr/src/uts/common/fs/zfs/zcp_synctask.c | 71 +++++++++++++++++++--- usr/src/uts/common/fs/zfs/zfs_ioctl.c | 4 +- 20 files changed, 514 insertions(+), 30 deletions(-) create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh create mode 100644 usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp diff --git a/usr/src/lib/libzfs_core/common/libzfs_core.c b/usr/src/lib/libzfs_core/common/libzfs_core.c index c17ebcc58d..d3e92151f7 100644 --- a/usr/src/lib/libzfs_core/common/libzfs_core.c +++ b/usr/src/lib/libzfs_core/common/libzfs_core.c @@ -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) 2014 Integros [integros.com] * Copyright 2017 RackTop Systems. @@ -142,7 +142,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 == NULL) { @@ -156,7 +161,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 && diff --git a/usr/src/man/man1m/zfs-program.1m b/usr/src/man/man1m/zfs-program.1m index 2564df4d47..be42dae84b 100644 --- a/usr/src/man/man1m/zfs-program.1m +++ b/usr/src/man/man1m/zfs-program.1m @@ -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 diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf index 64b01a4e27..b955be4edb 100644 --- a/usr/src/pkg/manifests/system-test-zfstest.mf +++ b/usr/src/pkg/manifests/system-test-zfstest.mf @@ -457,6 +457,12 @@ file \ path=opt/zfs-tests/tests/functional/channel_program/lua_core/tst.recursive_pos \ mode=0555 file \ + path=opt/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large \ + mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp \ + mode=0444 +file \ path=opt/zfs-tests/tests/functional/channel_program/lua_core/tst.return_nvlist_neg \ mode=0555 file \ @@ -561,6 +567,30 @@ file \ file \ path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_one \ mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy \ + mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp \ + mode=0444 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg \ + mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp \ + mode=0444 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive \ + mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp \ + mode=0444 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple \ + mode=0555 +file \ + path=opt/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp \ + mode=0444 $(i386_ONLY)file path=opt/zfs-tests/tests/functional/checksum/edonr_test.amd64 \ mode=0555 $(i386_ONLY)file path=opt/zfs-tests/tests/functional/checksum/edonr_test.i386 \ diff --git a/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh b/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh new file mode 100644 index 0000000000..369ad846a0 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.ksh @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp b/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp new file mode 100644 index 0000000000..0ea9f8930e --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/lua_core/tst.return_large.zcp @@ -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 diff --git a/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh new file mode 100644 index 0000000000..98317db6e6 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.ksh @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp new file mode 100644 index 0000000000..6fbfb06ad4 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_destroy.zcp @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh new file mode 100644 index 0000000000..c3585c9386 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.ksh @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp new file mode 100644 index 0000000000..5cae324bc9 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_neg.zcp @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh new file mode 100644 index 0000000000..c0180d90c4 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.ksh @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp new file mode 100644 index 0000000000..097940d711 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_recursive.zcp @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh new file mode 100644 index 0000000000..e818ce9fcb --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.ksh @@ -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/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp new file mode 100644 index 0000000000..215e013df1 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_simple.zcp @@ -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 " + +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])) diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c index ab7aa0c146..de16398e36 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c @@ -1081,13 +1081,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) @@ -1147,7 +1140,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; @@ -1422,7 +1415,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; diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h index d9c62996bc..f01c33aea8 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h @@ -244,6 +244,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. @@ -276,6 +283,8 @@ uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname, dsl_dataset_t *origin, uint64_t flags, cred_t *, dmu_tx_t *); uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 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); diff --git a/usr/src/uts/common/fs/zfs/sys/zcp.h b/usr/src/uts/common/fs/zfs/sys/zcp.h index 443b94e26d..2e4ad7aac5 100644 --- a/usr/src/uts/common/fs/zfs/sys/zcp.h +++ b/usr/src/uts/common/fs/zfs/sys/zcp.h @@ -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 diff --git a/usr/src/uts/common/fs/zfs/zcp.c b/usr/src/uts/common/fs/zfs/zcp.c index 7736deddef..3410fac1a4 100644 --- a/usr/src/uts/common/fs/zfs/zcp.c +++ b/usr/src/uts/common/fs/zfs/zcp.c @@ -14,7 +14,7 @@ */ /* - * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright (c) 2016, 2017 by Delphix. All rights reserved. */ /* @@ -102,10 +102,15 @@ #include #include +#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); @@ -213,8 +218,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. diff --git a/usr/src/uts/common/fs/zfs/zcp_global.c b/usr/src/uts/common/fs/zfs/zcp_global.c index efc1cf92d3..9a869a6012 100644 --- a/usr/src/uts/common/fs/zfs/zcp_global.c +++ b/usr/src/uts/common/fs/zfs/zcp_global.c @@ -14,7 +14,7 @@ */ /* - * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright (c) 2016, 2017 by Delphix. All rights reserved. */ #include @@ -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}, {NULL, NULL} }; diff --git a/usr/src/uts/common/fs/zfs/zcp_synctask.c b/usr/src/uts/common/fs/zfs/zcp_synctask.c index a24d2cff21..6ec3f71f62 100644 --- a/usr/src/uts/common/fs/zfs/zcp_synctask.c +++ b/usr/src/uts/common/fs/zfs/zcp_synctask.c @@ -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, NULL} @@ -100,7 +98,9 @@ static zcp_synctask_info_t zcp_synctask_destroy_info = { .kwargs = { {.za_name = "defer", .za_lua_type = LUA_TBOOLEAN}, {NULL, NULL} - } + }, + .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, NULL} }, .kwargs = { {NULL, NULL} - } + }, + .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, NULL} + }, + .kwargs = { + {NULL, NULL} + }, + .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 }; diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index bcf58ff90a..52cf0145e3 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -26,7 +26,7 @@ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved. - * Copyright (c) 2011, 2016 by Delphix. All rights reserved. + * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014 Integros [integros.com] @@ -3623,7 +3623,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, -- 2.11.4.GIT