svn commit: r323530 - vendor-sys/illumos/dist/common/zfs vendor-sys/illumos/dist/uts/common vendor-sys/illumos/dist/uts/common/fs/zfs vendor-sys/illumos/dist/uts/common/fs/zfs/lua vendor-sys/illumo...

Andriy Gapon avg at FreeBSD.org
Wed Sep 13 10:45:50 UTC 2017


Author: avg
Date: Wed Sep 13 10:45:49 2017
New Revision: 323530
URL: https://svnweb.freebsd.org/changeset/base/323530

Log:
  7431 ZFS Channel Programs
  
  illumos/illumos-gate at dfc115332c94a2f62058ac7f2bce7631fbd20b3d
  https://github.com/illumos/illumos-gate/commit/dfc115332c94a2f62058ac7f2bce7631fbd20b3d
  
  https://www.illumos.org/issues/7431
    ZFS channel programs (ZCP) adds support for performing compound ZFS
    administrative actions via Lua scripts in a sandboxed environment (with time
    and memory limits).
    This initial commit includes both base support for running ZCP scripts, and a
    small initial library of API calls which support getting properties and
    listing, destroying, and promoting datasets.
    Testing: in addition to the included unit tests, channel programs have been in
    use at Delphix for several months for batch destroying filesystems. The
    dsl_destroy_snaps_nvl() call has also been replaced with
  
    For reference, the new zfs-program manpage is included below.
    ZFS-PROGRAM(1M)                       1M                       ZFS-PROGRAM(1M)
  
    NAME
         zfs program – executes ZFS channel programs
  
    SYNOPSIS
         zfs program [-t timeout] [-m memory-limit] pool script
  
    DESCRIPTION
         The ZFS channel program interface allows ZFS administrative operations to
         be run programmatically as a Lua script. The entire script is executed
         atomically, with no other administrative operations taking effect
         concurrently. A library of ZFS calls is made available to channel program
         scripts. Channel programs may only be run with root privileges.
  
         A modified version of the Lua 5.2 interpreter is used to run channel
         program scripts. The Lua 5.2 manual can be found at:
  
               http://www.lua.org/manual/5.2/
    ...
  
  Reviewed by: Matthew Ahrens <mahrens at delphix.com>
  Reviewed by: George Wilson <george.wilson at delphix.com>
  Reviewed by: John Kennedy <john.kennedy at delphix.com>
  Reviewed by: Dan Kimmel <dan.kimmel at delphix.com>
  Approved by: Garrett D'Amore <garrett at damore.org>
  Author: Chris Williamson <chris.williamson at delphix.com>

Added:
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/README.zfs
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lapi.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lapi.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lauxlib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lauxlib.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lbaselib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lbitlib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcode.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcode.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcompat.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lcorolib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lctype.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lctype.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldebug.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldebug.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldo.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldo.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ldump.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lfunc.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lfunc.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lgc.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lgc.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llex.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llex.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/llimits.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lmem.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lmem.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lobject.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lobject.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lopcodes.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lopcodes.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lparser.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lparser.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstate.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstate.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstring.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstring.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lstrlib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltable.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltable.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltablib.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltm.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/ltm.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lua.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/luaconf.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lualib.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lundump.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lundump.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lvm.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lvm.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lzio.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/lua/lzio.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_global.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_iter.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zcp_prop.h   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/zcp.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_get.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_global.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_iter.c   (contents, props changed)
  vendor-sys/illumos/dist/uts/common/fs/zfs/zcp_synctask.c   (contents, props changed)
Modified:
  vendor-sys/illumos/dist/common/zfs/zfs_prop.c
  vendor-sys/illumos/dist/uts/common/Makefile.files
  vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c
  vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c
  vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dir.c
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_dataset.h
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_destroy.h
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_dir.h
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zfs_ioctl.h
  vendor-sys/illumos/dist/uts/common/fs/zfs/sys/zfs_vfsops.h
  vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_ioctl.c
  vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vfsops.c
  vendor-sys/illumos/dist/uts/common/sys/fs/zfs.h

Changes in other areas also in this revision:
Added:
  vendor/illumos/dist/man/man1m/zfs-program.1m
Modified:
  vendor/illumos/dist/cmd/zfs/zfs_main.c
  vendor/illumos/dist/cmd/zpool/zpool_main.c
  vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c
  vendor/illumos/dist/lib/libzfs/common/libzfs_impl.h
  vendor/illumos/dist/lib/libzfs/common/libzfs_util.c
  vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.c
  vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.h
  vendor/illumos/dist/lib/libzpool/common/kernel.c
  vendor/illumos/dist/lib/libzpool/common/sys/zfs_context.h
  vendor/illumos/dist/man/man1m/zfs.1m

Modified: vendor-sys/illumos/dist/common/zfs/zfs_prop.c
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_prop.c	Wed Sep 13 10:41:47 2017	(r323529)
+++ vendor-sys/illumos/dist/common/zfs/zfs_prop.c	Wed Sep 13 10:45:49 2017	(r323530)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
@@ -381,7 +381,8 @@ zfs_prop_init(void)
 	zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY,
 	    ZFS_TYPE_DATASET, "<size>", "WRITTEN");
 	zprop_register_number(ZFS_PROP_LOGICALUSED, "logicalused", 0,
-	    PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LUSED");
+	    PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>",
+	    "LUSED");
 	zprop_register_number(ZFS_PROP_LOGICALREFERENCED, "logicalreferenced",
 	    0, PROP_READONLY, ZFS_TYPE_DATASET, "<size>", "LREFER");
 
@@ -582,6 +583,15 @@ zfs_prop_readonly(zfs_prop_t prop)
 {
 	return (zfs_prop_table[prop].pd_attr == PROP_READONLY ||
 	    zfs_prop_table[prop].pd_attr == PROP_ONETIME);
+}
+
+/*
+ * Returns TRUE if the property is visible (not hidden).
+ */
+boolean_t
+zfs_prop_visible(zfs_prop_t prop)
+{
+	return (zfs_prop_table[prop].pd_visible);
 }
 
 /*

Modified: vendor-sys/illumos/dist/uts/common/Makefile.files
==============================================================================
--- vendor-sys/illumos/dist/uts/common/Makefile.files	Wed Sep 13 10:41:47 2017	(r323529)
+++ vendor-sys/illumos/dist/uts/common/Makefile.files	Wed Sep 13 10:45:49 2017	(r323530)
@@ -1308,6 +1308,35 @@ SMBFS_OBJS +=	smbfs_vfsops.o	smbfs_vnops.o	smbfs_node.
 		$(SMBFS_COMMON_OBJS)
 
 
+LUA_OBJS +=			\
+	ldo.o			\
+	lvm.o			\
+	lbitlib.o		\
+	lopcodes.o		\
+	lstring.o		\
+	ltable.o		\
+	ltm.o			\
+	lcorolib.o		\
+	lauxlib.o		\
+	ldebug.o		\
+	lstate.o		\
+	lgc.o			\
+	lmem.o			\
+	lctype.o		\
+	lfunc.o			\
+	ldump.o			\
+	lundump.o		\
+	lstrlib.o		\
+	ltablib.o		\
+	lapi.o			\
+	lobject.o		\
+	lbaselib.o		\
+	lcompat.o		\
+	lzio.o			\
+	lcode.o			\
+	llex.o			\
+	lparser.o
+
 ZFS_COMMON_OBJS +=		\
 	abd.o			\
 	arc.o			\
@@ -1375,6 +1404,11 @@ ZFS_COMMON_OBJS +=		\
 	zap.o			\
 	zap_leaf.o		\
 	zap_micro.o		\
+	zcp.o			\
+	zcp_get.o		\
+	zcp_global.o		\
+	zcp_iter.o		\
+	zcp_synctask.o		\
 	zfs_byteswap.o		\
 	zfs_debug.o		\
 	zfs_fm.o		\
@@ -1958,7 +1992,7 @@ IXGBE_OBJS =    ixgbe_82598.o ixgbe_82599.o ixgbe_api.
 
 # illumos-written ones.
 I40E_OBJS =	i40e_main.o i40e_osdep.o i40e_intr.o i40e_transceiver.o \
-		i40e_stats.o i40e_gld.o 
+		i40e_stats.o i40e_gld.o
 # Intel-written ones.
 I40E_INTC_OBJS = i40e_adminq.o i40e_common.o i40e_hmc.o i40e_lan_hmc.o \
 		 i40e_nvm.o

Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c	Wed Sep 13 10:41:47 2017	(r323529)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c	Wed Sep 13 10:45:49 2017	(r323530)
@@ -1616,7 +1616,6 @@ dsl_dataset_snapshot_tmp(const char *fsname, const cha
 	return (error);
 }
 
-
 void
 dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
 {
@@ -1684,30 +1683,17 @@ dsl_dataset_sync_done(dsl_dataset_t *ds, dmu_tx_t *tx)
 	dmu_buf_rele(ds->ds_dbuf, ds);
 }
 
-static void
-get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
+int
+get_clones_stat_impl(dsl_dataset_t *ds, nvlist_t *val)
 {
 	uint64_t count = 0;
 	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
 	zap_cursor_t zc;
 	zap_attribute_t za;
-	nvlist_t *propval = fnvlist_alloc();
-	nvlist_t *val;
 
 	ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 
 	/*
-	 * We use nvlist_alloc() instead of fnvlist_alloc() because the
-	 * latter would allocate the list with NV_UNIQUE_NAME flag.
-	 * As a result, every time a clone name is appended to the list
-	 * it would be (linearly) searched for for a duplicate name.
-	 * We already know that all clone names must be unique and we
-	 * want avoid the quadratic complexity of double-checking that
-	 * because we can have a large number of clones.
-	 */
-	VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP));
-
-	/*
 	 * There may be missing entries in ds_next_clones_obj
 	 * due to a bug in a previous version of the code.
 	 * Only trust it if it has the right number of entries.
@@ -1716,8 +1702,9 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
 		VERIFY0(zap_count(mos, dsl_dataset_phys(ds)->ds_next_clones_obj,
 		    &count));
 	}
-	if (count != dsl_dataset_phys(ds)->ds_num_children - 1)
-		goto fail;
+	if (count != dsl_dataset_phys(ds)->ds_num_children - 1) {
+		return (ENOENT);
+	}
 	for (zap_cursor_init(&zc, mos,
 	    dsl_dataset_phys(ds)->ds_next_clones_obj);
 	    zap_cursor_retrieve(&zc, &za) == 0;
@@ -1731,16 +1718,43 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
 		dsl_dataset_rele(clone, FTAG);
 	}
 	zap_cursor_fini(&zc);
-	fnvlist_add_nvlist(propval, ZPROP_VALUE, val);
-	fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), propval);
-fail:
-	nvlist_free(val);
-	nvlist_free(propval);
+	return (0);
 }
 
-static void
-get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
+void
+get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
 {
+	nvlist_t *propval = fnvlist_alloc();
+	nvlist_t *val;
+
+	/*
+	 * We use nvlist_alloc() instead of fnvlist_alloc() because the
+	 * latter would allocate the list with NV_UNIQUE_NAME flag.
+	 * As a result, every time a clone name is appended to the list
+	 * it would be (linearly) searched for for a duplicate name.
+	 * We already know that all clone names must be unique and we
+	 * want avoid the quadratic complexity of double-checking that
+	 * because we can have a large number of clones.
+	 */
+	VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP));
+
+	if (get_clones_stat_impl(ds, val) == 0) {
+		fnvlist_add_nvlist(propval, ZPROP_VALUE, val);
+		fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES),
+		    propval);
+	} else {
+		nvlist_free(val);
+		nvlist_free(propval);
+	}
+}
+
+/*
+ * Returns a string that represents the receive resume stats token. It should
+ * be freed with strfree().
+ */
+char *
+get_receive_resume_stats_impl(dsl_dataset_t *ds)
+{
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 
 	if (dsl_dataset_has_resume_receive_state(ds)) {
@@ -1807,84 +1821,359 @@ get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *
 		    ZFS_SEND_RESUME_TOKEN_VERSION,
 		    (longlong_t)cksum.zc_word[0],
 		    (longlong_t)packed_size, str);
-		dsl_prop_nvlist_add_string(nv,
-		    ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
 		kmem_free(packed, packed_size);
 		kmem_free(str, compressed_size * 2 + 1);
 		kmem_free(compressed, packed_size);
-		strfree(propval);
+		return (propval);
 	}
+	return (strdup(""));
 }
 
+/*
+ * Returns a string that represents the receive resume stats token of the
+ * dataset's child. It should be freed with strfree().
+ */
+char *
+get_child_receive_stats(dsl_dataset_t *ds)
+{
+	char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+	dsl_dataset_t *recv_ds;
+	dsl_dataset_name(ds, recvname);
+	if (strlcat(recvname, "/", sizeof (recvname)) <
+	    sizeof (recvname) &&
+	    strlcat(recvname, recv_clone_name, sizeof (recvname)) <
+	    sizeof (recvname) &&
+	    dsl_dataset_hold(ds->ds_dir->dd_pool, recvname, FTAG,
+	    &recv_ds)  == 0) {
+		char *propval = get_receive_resume_stats_impl(recv_ds);
+		dsl_dataset_rele(recv_ds, FTAG);
+		return (propval);
+	}
+	return (strdup(""));
+}
+
+static void
+get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
+{
+	char *propval = get_receive_resume_stats_impl(ds);
+	if (strcmp(propval, "") != 0) {
+		dsl_prop_nvlist_add_string(nv,
+		    ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
+	} else {
+		char *childval = get_child_receive_stats(ds);
+		if (strcmp(childval, "") != 0) {
+			dsl_prop_nvlist_add_string(nv,
+			    ZFS_PROP_RECEIVE_RESUME_TOKEN, childval);
+		}
+		strfree(childval);
+	}
+	strfree(propval);
+}
+
+uint64_t
+dsl_get_refratio(dsl_dataset_t *ds)
+{
+	uint64_t ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 :
+	    (dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 /
+	    dsl_dataset_phys(ds)->ds_compressed_bytes);
+	return (ratio);
+}
+
+uint64_t
+dsl_get_logicalreferenced(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_uncompressed_bytes);
+}
+
+uint64_t
+dsl_get_compressratio(dsl_dataset_t *ds)
+{
+	if (ds->ds_is_snapshot) {
+		return (dsl_get_refratio(ds));
+	} else {
+		dsl_dir_t *dd = ds->ds_dir;
+		mutex_enter(&dd->dd_lock);
+		uint64_t val = dsl_dir_get_compressratio(dd);
+		mutex_exit(&dd->dd_lock);
+		return (val);
+	}
+}
+
+uint64_t
+dsl_get_used(dsl_dataset_t *ds)
+{
+	if (ds->ds_is_snapshot) {
+		return (dsl_dataset_phys(ds)->ds_unique_bytes);
+	} else {
+		dsl_dir_t *dd = ds->ds_dir;
+		mutex_enter(&dd->dd_lock);
+		uint64_t val = dsl_dir_get_used(dd);
+		mutex_exit(&dd->dd_lock);
+		return (val);
+	}
+}
+
+uint64_t
+dsl_get_creation(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_creation_time);
+}
+
+uint64_t
+dsl_get_creationtxg(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_creation_txg);
+}
+
+uint64_t
+dsl_get_refquota(dsl_dataset_t *ds)
+{
+	return (ds->ds_quota);
+}
+
+uint64_t
+dsl_get_refreservation(dsl_dataset_t *ds)
+{
+	return (ds->ds_reserved);
+}
+
+uint64_t
+dsl_get_guid(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_guid);
+}
+
+uint64_t
+dsl_get_unique(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_unique_bytes);
+}
+
+uint64_t
+dsl_get_objsetid(dsl_dataset_t *ds)
+{
+	return (ds->ds_object);
+}
+
+uint64_t
+dsl_get_userrefs(dsl_dataset_t *ds)
+{
+	return (ds->ds_userrefs);
+}
+
+uint64_t
+dsl_get_defer_destroy(dsl_dataset_t *ds)
+{
+	return (DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
+}
+
+uint64_t
+dsl_get_referenced(dsl_dataset_t *ds)
+{
+	return (dsl_dataset_phys(ds)->ds_referenced_bytes);
+}
+
+uint64_t
+dsl_get_numclones(dsl_dataset_t *ds)
+{
+	ASSERT(ds->ds_is_snapshot);
+	return (dsl_dataset_phys(ds)->ds_num_children - 1);
+}
+
+uint64_t
+dsl_get_inconsistent(dsl_dataset_t *ds)
+{
+	return ((dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT) ?
+	    1 : 0);
+}
+
+uint64_t
+dsl_get_available(dsl_dataset_t *ds)
+{
+	uint64_t refdbytes = dsl_get_referenced(ds);
+	uint64_t availbytes = dsl_dir_space_available(ds->ds_dir,
+	    NULL, 0, TRUE);
+	if (ds->ds_reserved > dsl_dataset_phys(ds)->ds_unique_bytes) {
+		availbytes +=
+		    ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes;
+	}
+	if (ds->ds_quota != 0) {
+		/*
+		 * Adjust available bytes according to refquota
+		 */
+		if (refdbytes < ds->ds_quota) {
+			availbytes = MIN(availbytes,
+			    ds->ds_quota - refdbytes);
+		} else {
+			availbytes = 0;
+		}
+	}
+	return (availbytes);
+}
+
+int
+dsl_get_written(dsl_dataset_t *ds, uint64_t *written)
+{
+	dsl_pool_t *dp = ds->ds_dir->dd_pool;
+	dsl_dataset_t *prev;
+	int err = dsl_dataset_hold_obj(dp,
+	    dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
+	if (err == 0) {
+		uint64_t comp, uncomp;
+		err = dsl_dataset_space_written(prev, ds, written,
+		    &comp, &uncomp);
+		dsl_dataset_rele(prev, FTAG);
+	}
+	return (err);
+}
+
+/*
+ * 'snap' should be a buffer of size ZFS_MAX_DATASET_NAME_LEN.
+ */
+int
+dsl_get_prev_snap(dsl_dataset_t *ds, char *snap)
+{
+	dsl_pool_t *dp = ds->ds_dir->dd_pool;
+	if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
+		dsl_dataset_name(ds->ds_prev, snap);
+		return (0);
+	} else {
+		return (ENOENT);
+	}
+}
+
+/*
+ * Returns the mountpoint property and source for the given dataset in the value
+ * and source buffers. The value buffer must be at least as large as MAXPATHLEN
+ * and the source buffer as least as large a ZFS_MAX_DATASET_NAME_LEN.
+ * Returns 0 on success and an error on failure.
+ */
+int
+dsl_get_mountpoint(dsl_dataset_t *ds, const char *dsname, char *value,
+    char *source)
+{
+	int error;
+	dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+	/* Retrieve the mountpoint value stored in the zap opbject */
+	error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1,
+	    ZAP_MAXVALUELEN, value, source);
+	if (error != 0) {
+		return (error);
+	}
+
+	/* Process the dsname and source to find the full mountpoint string */
+	if (value[0] == '/') {
+		char *buf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
+		char *root = buf;
+		const char *relpath;
+
+		/*
+		 * If we inherit the mountpoint, even from a dataset
+		 * with a received value, the source will be the path of
+		 * the dataset we inherit from. If source is
+		 * ZPROP_SOURCE_VAL_RECVD, the received value is not
+		 * inherited.
+		 */
+		if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
+			relpath = "";
+		} else {
+			ASSERT0(strncmp(dsname, source, strlen(source)));
+			relpath = dsname + strlen(source);
+			if (relpath[0] == '/')
+				relpath++;
+		}
+
+		spa_altroot(dp->dp_spa, root, ZAP_MAXVALUELEN);
+
+		/*
+		 * Special case an alternate root of '/'. This will
+		 * avoid having multiple leading slashes in the
+		 * mountpoint path.
+		 */
+		if (strcmp(root, "/") == 0)
+			root++;
+
+		/*
+		 * If the mountpoint is '/' then skip over this
+		 * if we are obtaining either an alternate root or
+		 * an inherited mountpoint.
+		 */
+		char *mnt = value;
+		if (value[1] == '\0' && (root[0] != '\0' ||
+		    relpath[0] != '\0'))
+			mnt = value + 1;
+
+		if (relpath[0] == '\0') {
+			(void) snprintf(value, ZAP_MAXVALUELEN, "%s%s",
+			    root, mnt);
+		} else {
+			(void) snprintf(value, ZAP_MAXVALUELEN, "%s%s%s%s",
+			    root, mnt, relpath[0] == '@' ? "" : "/",
+			    relpath);
+		}
+		kmem_free(buf, ZAP_MAXVALUELEN);
+	} else {
+		/* 'legacy' or 'none' */
+		(void) snprintf(value, ZAP_MAXVALUELEN, "%s", value);
+	}
+	return (0);
+}
+
 void
 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
 {
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
-	uint64_t refd, avail, uobjs, aobjs, ratio;
 
 	ASSERT(dsl_pool_config_held(dp));
 
-	ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 :
-	    (dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 /
-	    dsl_dataset_phys(ds)->ds_compressed_bytes);
-
-	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO,
+	    dsl_get_refratio(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALREFERENCED,
-	    dsl_dataset_phys(ds)->ds_uncompressed_bytes);
+	    dsl_get_logicalreferenced(ds));
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO,
+	    dsl_get_compressratio(ds));
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
+	    dsl_get_used(ds));
 
 	if (ds->ds_is_snapshot) {
-		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
-		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
-		    dsl_dataset_phys(ds)->ds_unique_bytes);
 		get_clones_stat(ds, nv);
 	} else {
-		if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
-			char buf[ZFS_MAX_DATASET_NAME_LEN];
-			dsl_dataset_name(ds->ds_prev, buf);
-			dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf);
-		}
-
+		char buf[ZFS_MAX_DATASET_NAME_LEN];
+		if (dsl_get_prev_snap(ds, buf) == 0)
+			dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP,
+			    buf);
 		dsl_dir_stats(ds->ds_dir, nv);
 	}
 
-	dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
-	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
-	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
-
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE,
+	    dsl_get_available(ds));
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED,
+	    dsl_get_referenced(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION,
-	    dsl_dataset_phys(ds)->ds_creation_time);
+	    dsl_get_creation(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG,
-	    dsl_dataset_phys(ds)->ds_creation_txg);
+	    dsl_get_creationtxg(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA,
-	    ds->ds_quota);
+	    dsl_get_refquota(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION,
-	    ds->ds_reserved);
+	    dsl_get_refreservation(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID,
-	    dsl_dataset_phys(ds)->ds_guid);
+	    dsl_get_guid(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE,
-	    dsl_dataset_phys(ds)->ds_unique_bytes);
+	    dsl_get_unique(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID,
-	    ds->ds_object);
+	    dsl_get_objsetid(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS,
-	    ds->ds_userrefs);
+	    dsl_get_userrefs(ds));
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
-	    DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
+	    dsl_get_defer_destroy(ds));
 
 	if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
-		uint64_t written, comp, uncomp;
-		dsl_pool_t *dp = ds->ds_dir->dd_pool;
-		dsl_dataset_t *prev;
-
-		int err = dsl_dataset_hold_obj(dp,
-		    dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
-		if (err == 0) {
-			err = dsl_dataset_space_written(prev, ds, &written,
-			    &comp, &uncomp);
-			dsl_dataset_rele(prev, FTAG);
-			if (err == 0) {
-				dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
-				    written);
-			}
+		uint64_t written;
+		if (dsl_get_written(ds, &written) == 0) {
+			dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
+			    written);
 		}
 	}
 
@@ -1921,27 +2210,19 @@ dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_st
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 	ASSERT(dsl_pool_config_held(dp));
 
-	stat->dds_creation_txg = dsl_dataset_phys(ds)->ds_creation_txg;
-	stat->dds_inconsistent =
-	    dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT;
-	stat->dds_guid = dsl_dataset_phys(ds)->ds_guid;
+	stat->dds_creation_txg = dsl_get_creationtxg(ds);
+	stat->dds_inconsistent = dsl_get_inconsistent(ds);
+	stat->dds_guid = dsl_get_guid(ds);
 	stat->dds_origin[0] = '\0';
 	if (ds->ds_is_snapshot) {
 		stat->dds_is_snapshot = B_TRUE;
-		stat->dds_num_clones =
-		    dsl_dataset_phys(ds)->ds_num_children - 1;
+		stat->dds_num_clones = dsl_get_numclones(ds);
 	} else {
 		stat->dds_is_snapshot = B_FALSE;
 		stat->dds_num_clones = 0;
 
 		if (dsl_dir_is_clone(ds->ds_dir)) {
-			dsl_dataset_t *ods;
-
-			VERIFY0(dsl_dataset_hold_obj(dp,
-			    dsl_dir_phys(ds->ds_dir)->dd_origin_obj,
-			    FTAG, &ods));
-			dsl_dataset_name(ods, stat->dds_origin);
-			dsl_dataset_rele(ods, FTAG);
+			dsl_dir_get_origin(ds->ds_dir, stat->dds_origin);
 		}
 	}
 }
@@ -2348,22 +2629,12 @@ struct promotenode {
 	dsl_dataset_t *ds;
 };
 
-typedef struct dsl_dataset_promote_arg {
-	const char *ddpa_clonename;
-	dsl_dataset_t *ddpa_clone;
-	list_t shared_snaps, origin_snaps, clone_snaps;
-	dsl_dataset_t *origin_origin; /* origin of the origin */
-	uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
-	char *err_ds;
-	cred_t *cr;
-} dsl_dataset_promote_arg_t;
-
 static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
 static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp,
     void *tag);
 static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag);
 
-static int
+int
 dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 {
 	dsl_dataset_promote_arg_t *ddpa = arg;
@@ -2375,14 +2646,19 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 	uint64_t unused;
 	uint64_t ss_mv_cnt;
 	size_t max_snap_len;
+	boolean_t conflicting_snaps;
 
 	err = promote_hold(ddpa, dp, FTAG);
 	if (err != 0)
 		return (err);
 
 	hds = ddpa->ddpa_clone;
+	snap = list_head(&ddpa->shared_snaps);
+	origin_ds = snap->ds;
 	max_snap_len = MAXNAMELEN - strlen(ddpa->ddpa_clonename) - 1;
 
+	snap = list_head(&ddpa->origin_snaps);
+
 	if (dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE) {
 		promote_rele(ddpa, FTAG);
 		return (SET_ERROR(EXDEV));
@@ -2397,9 +2673,6 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 		return (0);
 	}
 
-	snap = list_head(&ddpa->shared_snaps);
-	origin_ds = snap->ds;
-
 	/* compute origin's new unique space */
 	snap = list_tail(&ddpa->clone_snaps);
 	ASSERT3U(dsl_dataset_phys(snap->ds)->ds_prev_snap_obj, ==,
@@ -2423,6 +2696,7 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 	 * Note however, if we stop before we reach the ORIGIN we get:
 	 * uN + kN + kN-1 + ... + kM - uM-1
 	 */
+	conflicting_snaps = B_FALSE;
 	ss_mv_cnt = 0;
 	ddpa->used = dsl_dataset_phys(origin_ds)->ds_referenced_bytes;
 	ddpa->comp = dsl_dataset_phys(origin_ds)->ds_compressed_bytes;
@@ -2451,12 +2725,12 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 		}
 		err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val);
 		if (err == 0) {
-			(void) strcpy(ddpa->err_ds, snap->ds->ds_snapname);
-			err = SET_ERROR(EEXIST);
+			fnvlist_add_boolean(ddpa->err_ds,
+			    snap->ds->ds_snapname);
+			conflicting_snaps = B_TRUE;
+		} else if (err != ENOENT) {
 			goto out;
 		}
-		if (err != ENOENT)
-			goto out;
 
 		/* The very first snapshot does not have a deadlist */
 		if (dsl_dataset_phys(ds)->ds_prev_snap_obj == 0)
@@ -2470,6 +2744,15 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
 	}
 
 	/*
+	 * In order to return the full list of conflicting snapshots, we check
+	 * whether there was a conflict after traversing all of them.
+	 */
+	if (conflicting_snaps) {
+		err = SET_ERROR(EEXIST);
+		goto out;
+	}
+
+	/*
 	 * If we are a clone of a clone then we never reached ORIGIN,
 	 * so we need to subtract out the clone origin's used space.
 	 */
@@ -2531,7 +2814,7 @@ out:
 	return (err);
 }
 
-static void
+void
 dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
 {
 	dsl_dataset_promote_arg_t *ddpa = arg;
@@ -2856,6 +3139,7 @@ dsl_dataset_promote(const char *name, char *conflsnap)
 	dsl_dataset_promote_arg_t ddpa = { 0 };
 	uint64_t numsnaps;
 	int error;
+	nvpair_t *snap_pair;
 	objset_t *os;
 
 	/*
@@ -2873,12 +3157,22 @@ dsl_dataset_promote(const char *name, char *conflsnap)
 		return (error);
 
 	ddpa.ddpa_clonename = name;
-	ddpa.err_ds = conflsnap;
+	ddpa.err_ds = fnvlist_alloc();
 	ddpa.cr = CRED();
 
-	return (dsl_sync_task(name, dsl_dataset_promote_check,
+	error = dsl_sync_task(name, dsl_dataset_promote_check,
 	    dsl_dataset_promote_sync, &ddpa,
-	    2 + numsnaps, ZFS_SPACE_CHECK_RESERVED));
+	    2 + numsnaps, ZFS_SPACE_CHECK_RESERVED);
+
+	/*
+	 * Return the first conflicting snapshot found.
+	 */
+	snap_pair = nvlist_next_nvpair(ddpa.err_ds, NULL);
+	if (snap_pair != NULL && conflsnap != NULL)
+		(void) strcpy(conflsnap, nvpair_name(snap_pair));
+
+	fnvlist_free(ddpa.err_ds);
+	return (error);
 }
 
 int

Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c	Wed Sep 13 10:41:47 2017	(r323529)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c	Wed Sep 13 10:45:49 2017	(r323530)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
@@ -30,6 +30,7 @@
 #include <sys/dsl_userhold.h>
 #include <sys/dsl_dataset.h>
 #include <sys/dsl_synctask.h>
+#include <sys/dsl_destroy.h>
 #include <sys/dmu_tx.h>
 #include <sys/dsl_pool.h>
 #include <sys/dsl_dir.h>
@@ -41,14 +42,8 @@
 #include <sys/zfs_ioctl.h>
 #include <sys/dsl_deleg.h>
 #include <sys/dmu_impl.h>
+#include <sys/zcp.h>
 
-typedef struct dmu_snapshots_destroy_arg {
-	nvlist_t *dsda_snaps;
-	nvlist_t *dsda_successful_snaps;
-	boolean_t dsda_defer;
-	nvlist_t *dsda_errlist;
-} dmu_snapshots_destroy_arg_t;
-
 int
 dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
 {
@@ -85,51 +80,33 @@ dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boo
 	return (0);
 }
 
-static int
+int
 dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx)
 {
-	dmu_snapshots_destroy_arg_t *dsda = arg;
+	dsl_destroy_snapshot_arg_t *ddsa = arg;
+	const char *dsname = ddsa->ddsa_name;
+	boolean_t defer = ddsa->ddsa_defer;
+
 	dsl_pool_t *dp = dmu_tx_pool(tx);
-	nvpair_t *pair;
 	int error = 0;
+	dsl_dataset_t *ds;
 
-	if (!dmu_tx_is_syncing(tx))
+	error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+
+	/*
+	 * If the snapshot does not exist, silently ignore it, and
+	 * dsl_destroy_snapshot_sync() will be a no-op
+	 * (it's "already destroyed").
+	 */
+	if (error == ENOENT)
 		return (0);
 
-	for (pair = nvlist_next_nvpair(dsda->dsda_snaps, NULL);
-	    pair != NULL; pair = nvlist_next_nvpair(dsda->dsda_snaps, pair)) {
-		dsl_dataset_t *ds;
-
-		error = dsl_dataset_hold(dp, nvpair_name(pair),
-		    FTAG, &ds);
-
-		/*
-		 * If the snapshot does not exist, silently ignore it
-		 * (it's "already destroyed").
-		 */
-		if (error == ENOENT)
-			continue;
-
-		if (error == 0) {
-			error = dsl_destroy_snapshot_check_impl(ds,
-			    dsda->dsda_defer);
-			dsl_dataset_rele(ds, FTAG);
-		}
-
-		if (error == 0) {
-			fnvlist_add_boolean(dsda->dsda_successful_snaps,
-			    nvpair_name(pair));
-		} else {
-			fnvlist_add_int32(dsda->dsda_errlist,
-			    nvpair_name(pair), error);
-		}
+	if (error == 0) {
+		error = dsl_destroy_snapshot_check_impl(ds, defer);
+		dsl_dataset_rele(ds, FTAG);
 	}
 
-	pair = nvlist_next_nvpair(dsda->dsda_errlist, NULL);
-	if (pair != NULL)
-		return (fnvpair_value_int32(pair));
-
-	return (0);
+	return (error);
 }
 
 struct process_old_arg {
@@ -473,23 +450,22 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, bool
 	dmu_object_free_zapified(mos, obj, tx);
 }
 
-static void
+void
 dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx)
 {
-	dmu_snapshots_destroy_arg_t *dsda = arg;
+	dsl_destroy_snapshot_arg_t *ddsa = arg;
+	const char *dsname = ddsa->ddsa_name;
+	boolean_t defer = ddsa->ddsa_defer;
+
 	dsl_pool_t *dp = dmu_tx_pool(tx);
-	nvpair_t *pair;
+	dsl_dataset_t *ds;
 
-	for (pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, NULL);
-	    pair != NULL;
-	    pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, pair)) {
-		dsl_dataset_t *ds;
-
-		VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
-
-		dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx);
-		dsl_dataset_rele(ds, FTAG);
-	}
+	int error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+	if (error == ENOENT)
+		return;
+	ASSERT0(error);
+	dsl_destroy_snapshot_sync_impl(ds, defer, tx);
+	dsl_dataset_rele(ds, FTAG);
 }
 
 /*
@@ -509,25 +485,85 @@ int
 dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer,
     nvlist_t *errlist)
 {
-	dmu_snapshots_destroy_arg_t dsda;
-	int error;
-	nvpair_t *pair;
-
-	pair = nvlist_next_nvpair(snaps, NULL);
-	if (pair == NULL)
+	if (nvlist_next_nvpair(snaps, NULL) == NULL)
 		return (0);
 
-	dsda.dsda_snaps = snaps;
-	dsda.dsda_successful_snaps = fnvlist_alloc();
-	dsda.dsda_defer = defer;
-	dsda.dsda_errlist = errlist;
+	nvlist_t *arg = fnvlist_alloc();
+	nvlist_t *snaps_normalized = fnvlist_alloc();
+	/*
+	 * lzc_destroy_snaps() is documented to take an nvlist whose
+	 * values "don't matter".  We need to convert that nvlist to one
+	 * that we know can be converted to LUA.
+	 */
+	for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL);
+	    pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) {
+		fnvlist_add_boolean_value(snaps_normalized,
+		    nvpair_name(pair), B_TRUE);
+	}
+	fnvlist_add_nvlist(arg, "snaps", snaps_normalized);
+	fnvlist_add_boolean_value(arg, "defer", defer);
 
-	error = dsl_sync_task(nvpair_name(pair),
-	    dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync,
-	    &dsda, 0, ZFS_SPACE_CHECK_NONE);
-	fnvlist_free(dsda.dsda_successful_snaps);
+	nvlist_t *wrapper = fnvlist_alloc();
+	fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg);
+	fnvlist_free(arg);
 
-	return (error);
+	const char *program =
+	    "arg = ...\n"
+	    "snaps = arg['snaps']\n"
+	    "defer = arg['defer']\n"
+	    "errors = { }\n"
+	    "has_errors = false\n"
+	    "for snap, v in pairs(snaps) do\n"
+	    "    errno = zfs.check.destroy{snap, defer=defer}\n"
+	    "    zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n"
+	    "    if errno == ENOENT then\n"
+	    "        snaps[snap] = nil\n"
+	    "    elseif errno ~= 0 then\n"
+	    "        errors[snap] = errno\n"
+	    "        has_errors = true\n"
+	    "    end\n"
+	    "end\n"
+	    "if has_errors then\n"
+	    "    return errors\n"
+	    "end\n"
+	    "for snap, v in pairs(snaps) do\n"
+	    "    errno = zfs.sync.destroy{snap, defer=defer}\n"
+	    "    assert(errno == 0)\n"
+	    "end\n"
+	    "return { }\n";
+
+	nvlist_t *result = fnvlist_alloc();
+	int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)),
+	    program,
+	    0,
+	    zfs_lua_max_memlimit,
+	    fnvlist_lookup_nvpair(wrapper, ZCP_ARG_ARGLIST), result);
+	if (error != 0) {
+		char *errorstr = NULL;
+		(void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr);
+		if (errorstr != NULL) {
+			zfs_dbgmsg(errorstr);
+		}
+		return (error);
+	}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list