1dfc1153Chris Williamson/*
2dfc1153Chris Williamson * CDDL HEADER START
3dfc1153Chris Williamson *
4dfc1153Chris Williamson * This file and its contents are supplied under the terms of the
5dfc1153Chris Williamson * Common Development and Distribution License ("CDDL"), version 1.0.
6dfc1153Chris Williamson * You may only use this file in accordance with the terms of version
7dfc1153Chris Williamson * 1.0 of the CDDL.
8dfc1153Chris Williamson *
9dfc1153Chris Williamson * A full copy of the text of the CDDL should have accompanied this
10dfc1153Chris Williamson * source.  A copy of the CDDL is also available via the Internet at
11dfc1153Chris Williamson * http://www.illumos.org/license/CDDL.
12dfc1153Chris Williamson *
13dfc1153Chris Williamson * CDDL HEADER END
14dfc1153Chris Williamson */
15dfc1153Chris Williamson
16dfc1153Chris Williamson/*
17000cce6Brad Lewis * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
182d85dedJason King * Copyright 2020 Joyent, Inc.
19dfc1153Chris Williamson */
20dfc1153Chris Williamson
21dfc1153Chris Williamson#include "lua.h"
22dfc1153Chris Williamson#include "lauxlib.h"
23dfc1153Chris Williamson
24dfc1153Chris Williamson#include <sys/zcp.h>
25b2d2f35Sara Hartse#include <sys/zcp_set.h>
26dfc1153Chris Williamson#include <sys/dsl_dir.h>
27dfc1153Chris Williamson#include <sys/dsl_pool.h>
28dfc1153Chris Williamson#include <sys/dsl_prop.h>
29dfc1153Chris Williamson#include <sys/dsl_synctask.h>
30dfc1153Chris Williamson#include <sys/dsl_dataset.h>
31dfc1153Chris Williamson#include <sys/dsl_bookmark.h>
32dfc1153Chris Williamson#include <sys/dsl_destroy.h>
33dfc1153Chris Williamson#include <sys/dmu_objset.h>
34dfc1153Chris Williamson#include <sys/zfs_znode.h>
35dfc1153Chris Williamson#include <sys/zfeature.h>
36dfc1153Chris Williamson#include <sys/metaslab.h>
37dfc1153Chris Williamson
38dfc1153Chris Williamson#define	DST_AVG_BLKSHIFT 14
39dfc1153Chris Williamson
402d85dedJason Kingtypedef struct zcp_inherit_prop_arg {
412d85dedJason King	lua_State		*zipa_state;
422d85dedJason King	const char		*zipa_prop;
432d85dedJason King	dsl_props_set_arg_t	zipa_dpsa;
442d85dedJason King} zcp_inherit_prop_arg_t;
452d85dedJason King
46dfc1153Chris Williamsontypedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *);
47dfc1153Chris Williamsontypedef struct zcp_synctask_info {
48dfc1153Chris Williamson	const char *name;
49dfc1153Chris Williamson	zcp_synctask_func_t *func;
50dfc1153Chris Williamson	const zcp_arg_t pargs[4];
51dfc1153Chris Williamson	const zcp_arg_t kwargs[2];
522840dceChris Williamson	zfs_space_check_t space_check;
532840dceChris Williamson	int blocks_modified;
54dfc1153Chris Williamson} zcp_synctask_info_t;
55dfc1153Chris Williamson
56dfc1153Chris Williamson/*
57dfc1153Chris Williamson * Generic synctask interface for channel program syncfuncs.
58dfc1153Chris Williamson *
59dfc1153Chris Williamson * To perform some action in syncing context, we'd generally call
60dfc1153Chris Williamson * dsl_sync_task(), but since the Lua script is already running inside a
61dfc1153Chris Williamson * synctask we need to leave out some actions (such as acquiring the config
62dfc1153Chris Williamson * rwlock and performing space checks).
63dfc1153Chris Williamson *
64dfc1153Chris Williamson * If 'sync' is false, executes a dry run and returns the error code.
65dfc1153Chris Williamson *
66a3b2868Serapheim Dimitropoulos * If we are not running in syncing context and we are not doing a dry run
67a3b2868Serapheim Dimitropoulos * (meaning we are running a zfs.sync function in open-context) then we
68a3b2868Serapheim Dimitropoulos * return a Lua error.
69a3b2868Serapheim Dimitropoulos *
70dfc1153Chris Williamson * This function also handles common fatal error cases for channel program
71dfc1153Chris Williamson * library functions. If a fatal error occurs, err_dsname will be the dataset
72dfc1153Chris Williamson * name reported in error messages, if supplied.
73dfc1153Chris Williamson */
74dfc1153Chris Williamsonstatic int
75dfc1153Chris Williamsonzcp_sync_task(lua_State *state, dsl_checkfunc_t *checkfunc,
76dfc1153Chris Williamson    dsl_syncfunc_t *syncfunc, void *arg, boolean_t sync, const char *err_dsname)
77dfc1153Chris Williamson{
78dfc1153Chris Williamson	int err;
79dfc1153Chris Williamson	zcp_run_info_t *ri = zcp_run_info(state);
80dfc1153Chris Williamson
81dfc1153Chris Williamson	err = checkfunc(arg, ri->zri_tx);
82dfc1153Chris Williamson	if (!sync)
83dfc1153Chris Williamson		return (err);
84dfc1153Chris Williamson
85a3b2868Serapheim Dimitropoulos	if (!ri->zri_sync) {
86a3b2868Serapheim Dimitropoulos		return (luaL_error(state, "running functions from the zfs.sync "
87a3b2868Serapheim Dimitropoulos		    "submodule requires passing sync=TRUE to "
88a3b2868Serapheim Dimitropoulos		    "lzc_channel_program() (i.e. do not specify the \"-n\" "
89a3b2868Serapheim Dimitropoulos		    "command line argument)"));
90a3b2868Serapheim Dimitropoulos	}
91a3b2868Serapheim Dimitropoulos
92dfc1153Chris Williamson	if (err == 0) {
93dfc1153Chris Williamson		syncfunc(arg, ri->zri_tx);
94dfc1153Chris Williamson	} else if (err == EIO) {
95dfc1153Chris Williamson		if (err_dsname != NULL) {
96dfc1153Chris Williamson			return (luaL_error(state,
97dfc1153Chris Williamson			    "I/O error while accessing dataset '%s'",
98dfc1153Chris Williamson			    err_dsname));
99dfc1153Chris Williamson		} else {
100dfc1153Chris Williamson			return (luaL_error(state,
101dfc1153Chris Williamson			    "I/O error while accessing dataset."));
102dfc1153Chris Williamson		}
103dfc1153Chris Williamson	}
104dfc1153Chris Williamson
105dfc1153Chris Williamson	return (err);
106dfc1153Chris Williamson}
107dfc1153Chris Williamson
108dfc1153Chris Williamson
109dfc1153Chris Williamsonstatic int zcp_synctask_destroy(lua_State *, boolean_t, nvlist_t *);
110dfc1153Chris Williamsonstatic zcp_synctask_info_t zcp_synctask_destroy_info = {
111dfc1153Chris Williamson	.name = "destroy",
112dfc1153Chris Williamson	.func = zcp_synctask_destroy,
113dfc1153Chris Williamson	.pargs = {
114dfc1153Chris Williamson	    {.za_name = "filesystem | snapshot", .za_lua_type = LUA_TSTRING},
115dd328bfToomas Soome	    {NULL, 0}
116dfc1153Chris Williamson	},
117dfc1153Chris Williamson	.kwargs = {
118dfc1153Chris Williamson	    {.za_name = "defer", .za_lua_type = LUA_TBOOLEAN},
119dd328bfToomas Soome	    {NULL, 0}
1202840dceChris Williamson	},
1218671400Serapheim Dimitropoulos	.space_check = ZFS_SPACE_CHECK_DESTROY,
1222840dceChris Williamson	.blocks_modified = 0
123dfc1153Chris Williamson};
124dfc1153Chris Williamson
125dfc1153Chris Williamson/* ARGSUSED */
126dfc1153Chris Williamsonstatic int
127dfc1153Chris Williamsonzcp_synctask_destroy(lua_State *state, boolean_t sync, nvlist_t *err_details)
128dfc1153Chris Williamson{
129dfc1153Chris Williamson	int err;
130dfc1153Chris Williamson	const char *dsname = lua_tostring(state, 1);
131dfc1153Chris Williamson
132dfc1153Chris Williamson	boolean_t issnap = (strchr(dsname, '@') != NULL);
133dfc1153Chris Williamson
134dfc1153Chris Williamson	if (!issnap && !lua_isnil(state, 2)) {
135dfc1153Chris Williamson		return (luaL_error(state,
136dfc1153Chris Williamson		    "'deferred' kwarg only supported for snapshots: %s",
137dfc1153Chris Williamson		    dsname));
138dfc1153Chris Williamson	}
139dfc1153Chris Williamson
140dfc1153Chris Williamson	if (issnap) {
141dfc1153Chris Williamson		dsl_destroy_snapshot_arg_t ddsa = { 0 };
142dfc1153Chris Williamson		ddsa.ddsa_name = dsname;
143dfc1153Chris Williamson		if (!lua_isnil(state, 2)) {
144dfc1153Chris Williamson			ddsa.ddsa_defer = lua_toboolean(state, 2);
145dfc1153Chris Williamson		} else {
146dfc1153Chris Williamson			ddsa.ddsa_defer = B_FALSE;
147dfc1153Chris Williamson		}
148dfc1153Chris Williamson
149dfc1153Chris Williamson		err = zcp_sync_task(state, dsl_destroy_snapshot_check,
150dfc1153Chris Williamson		    dsl_destroy_snapshot_sync, &ddsa, sync, dsname);
151dfc1153Chris Williamson	} else {
152dfc1153Chris Williamson		dsl_destroy_head_arg_t ddha = { 0 };
153dfc1153Chris Williamson		ddha.ddha_name = dsname;
154dfc1153Chris Williamson
155dfc1153Chris Williamson		err = zcp_sync_task(state, dsl_destroy_head_check,
156dfc1153Chris Williamson		    dsl_destroy_head_sync, &ddha, sync, dsname);
157dfc1153Chris Williamson	}
158dfc1153Chris Williamson
159dfc1153Chris Williamson	return (err);
160dfc1153Chris Williamson}
161dfc1153Chris Williamson
1622840dceChris Williamsonstatic int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *);
163dfc1153Chris Williamsonstatic zcp_synctask_info_t zcp_synctask_promote_info = {
164dfc1153Chris Williamson	.name = "promote",
165dfc1153Chris Williamson	.func = zcp_synctask_promote,
166dfc1153Chris Williamson	.pargs = {
167dfc1153Chris Williamson	    {.za_name = "clone", .za_lua_type = LUA_TSTRING},
168dd328bfToomas Soome	    {NULL, 0}
169dfc1153Chris Williamson	},
170dfc1153Chris Williamson	.kwargs = {
171dd328bfToomas Soome	    {NULL, 0}
1722840dceChris Williamson	},
1732840dceChris Williamson	.space_check = ZFS_SPACE_CHECK_RESERVED,
1742840dceChris Williamson	.blocks_modified = 3
175dfc1153Chris Williamson};
176dfc1153Chris Williamson
177dfc1153Chris Williamsonstatic int
178dfc1153Chris Williamsonzcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
179dfc1153Chris Williamson{
180dfc1153Chris Williamson	int err;
181dfc1153Chris Williamson	dsl_dataset_promote_arg_t ddpa = { 0 };
182dfc1153Chris Williamson	const char *dsname = lua_tostring(state, 1);
183dfc1153Chris Williamson	zcp_run_info_t *ri = zcp_run_info(state);
184dfc1153Chris Williamson
185dfc1153Chris Williamson	ddpa.ddpa_clonename = dsname;
186dfc1153Chris Williamson	ddpa.err_ds = err_details;
187dfc1153Chris Williamson	ddpa.cr = ri->zri_cred;
188dfc1153Chris Williamson
189dfc1153Chris Williamson	/*
190dfc1153Chris Williamson	 * If there was a snapshot name conflict, then err_ds will be filled
191dfc1153Chris Williamson	 * with a list of conflicting snapshot names.
192dfc1153Chris Williamson	 */
193dfc1153Chris Williamson	err = zcp_sync_task(state, dsl_dataset_promote_check,
194dfc1153Chris Williamson	    dsl_dataset_promote_sync, &ddpa, sync, dsname);
195dfc1153Chris Williamson
196dfc1153Chris Williamson	return (err);
197dfc1153Chris Williamson}
198dfc1153Chris Williamson
199000cce6Brad Lewisstatic int zcp_synctask_rollback(lua_State *, boolean_t, nvlist_t *err_details);
200000cce6Brad Lewisstatic zcp_synctask_info_t zcp_synctask_rollback_info = {
201000cce6Brad Lewis	.name = "rollback",
202000cce6Brad Lewis	.func = zcp_synctask_rollback,
203000cce6Brad Lewis	.space_check = ZFS_SPACE_CHECK_RESERVED,
204000cce6Brad Lewis	.blocks_modified = 1,
205000cce6Brad Lewis	.pargs = {
206000cce6Brad Lewis	    {.za_name = "filesystem", .za_lua_type = LUA_TSTRING},
207dd328bfToomas Soome	    {NULL, 0}
208000cce6Brad Lewis	},
209000cce6Brad Lewis	.kwargs = {
210dd328bfToomas Soome	    {NULL, 0}
211000cce6Brad Lewis	}
212000cce6Brad Lewis};
213000cce6Brad Lewis
214000cce6Brad Lewisstatic int
215000cce6Brad Lewiszcp_synctask_rollback(lua_State *state, boolean_t sync, nvlist_t *err_details)
216000cce6Brad Lewis{
217000cce6Brad Lewis	int err;
218000cce6Brad Lewis	const char *dsname = lua_tostring(state, 1);
219000cce6Brad Lewis	dsl_dataset_rollback_arg_t ddra = { 0 };
220000cce6Brad Lewis
221000cce6Brad Lewis	ddra.ddra_fsname = dsname;
222000cce6Brad Lewis	ddra.ddra_result = err_details;
223000cce6Brad Lewis
224000cce6Brad Lewis	err = zcp_sync_task(state, dsl_dataset_rollback_check,
225000cce6Brad Lewis	    dsl_dataset_rollback_sync, &ddra, sync, dsname);
226000cce6Brad Lewis
227000cce6Brad Lewis	return (err);
228000cce6Brad Lewis}
229000cce6Brad Lewis
2302840dceChris Williamsonstatic int zcp_synctask_snapshot(lua_State *, boolean_t, nvlist_t *);
2312840dceChris Williamsonstatic zcp_synctask_info_t zcp_synctask_snapshot_info = {
2322840dceChris Williamson	.name = "snapshot",
2332840dceChris Williamson	.func = zcp_synctask_snapshot,
2342840dceChris Williamson	.pargs = {
2352840dceChris Williamson	    {.za_name = "filesystem@snapname | volume@snapname",
2362840dceChris Williamson	    .za_lua_type = LUA_TSTRING},
237dd328bfToomas Soome	    {NULL, 0}
2382840dceChris Williamson	},
2392840dceChris Williamson	.kwargs = {
240dd328bfToomas Soome	    {NULL, 0}
2412840dceChris Williamson	},
2422840dceChris Williamson	.space_check = ZFS_SPACE_CHECK_NORMAL,
2432840dceChris Williamson	.blocks_modified = 3
2442840dceChris Williamson};
2452840dceChris Williamson
2462840dceChris Williamson/* ARGSUSED */
2472840dceChris Williamsonstatic int
2482840dceChris Williamsonzcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
2492840dceChris Williamson{
2502840dceChris Williamson	int err;
2512840dceChris Williamson	dsl_dataset_snapshot_arg_t ddsa = { 0 };
2522840dceChris Williamson	const char *dsname = lua_tostring(state, 1);
2532840dceChris Williamson	zcp_run_info_t *ri = zcp_run_info(state);
2542840dceChris Williamson
2552840dceChris Williamson	/*
256a3b2868Serapheim Dimitropoulos	 * On old pools, the ZIL must not be active when a snapshot is created,
257a3b2868Serapheim Dimitropoulos	 * but we can't suspend the ZIL because we're already in syncing
258a3b2868Serapheim Dimitropoulos	 * context.
259a3b2868Serapheim Dimitropoulos	 */
260a3b2868Serapheim Dimitropoulos	if (spa_version(ri->zri_pool->dp_spa) < SPA_VERSION_FAST_SNAP) {
261a3b2868Serapheim Dimitropoulos		return (ENOTSUP);
262a3b2868Serapheim Dimitropoulos	}
263a3b2868Serapheim Dimitropoulos
264a3b2868Serapheim Dimitropoulos	/*
2652840dceChris Williamson	 * We only allow for a single snapshot rather than a list, so the
2662840dceChris Williamson	 * error list output is unnecessary.
2672840dceChris Williamson	 */
2682840dceChris Williamson	ddsa.ddsa_errors = NULL;
2692840dceChris Williamson	ddsa.ddsa_props = NULL;
2702840dceChris Williamson	ddsa.ddsa_cr = ri->zri_cred;
2712840dceChris Williamson	ddsa.ddsa_snaps = fnvlist_alloc();
2722840dceChris Williamson	fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);
2732840dceChris Williamson
274a3b2868Serapheim Dimitropoulos	zcp_cleanup_handler_t *zch = zcp_register_cleanup(state,
275a3b2868Serapheim Dimitropoulos	    (zcp_cleanup_t *)&fnvlist_free, ddsa.ddsa_snaps);
2762840dceChris Williamson
2772840dceChris Williamson	err = zcp_sync_task(state, dsl_dataset_snapshot_check,
2782840dceChris Williamson	    dsl_dataset_snapshot_sync, &ddsa, sync, dsname);
2792840dceChris Williamson
280a3b2868Serapheim Dimitropoulos	zcp_deregister_cleanup(state, zch);
2812840dceChris Williamson	fnvlist_free(ddsa.ddsa_snaps);
2822840dceChris Williamson
2832840dceChris Williamson	return (err);
2842840dceChris Williamson}
2852840dceChris Williamson
2862d85dedJason Kingstatic int zcp_synctask_inherit_prop(lua_State *, boolean_t,
2872d85dedJason King    nvlist_t *err_details);
2882d85dedJason Kingstatic zcp_synctask_info_t zcp_synctask_inherit_prop_info = {
2892d85dedJason King	.name = "inherit",
2902d85dedJason King	.func = zcp_synctask_inherit_prop,
2912d85dedJason King	.space_check = ZFS_SPACE_CHECK_RESERVED,
2922d85dedJason King	.blocks_modified = 2, /* 2 * numprops */
2932d85dedJason King	.pargs = {
2942d85dedJason King		{ .za_name = "dataset", .za_lua_type = LUA_TSTRING },
2952d85dedJason King		{ .za_name = "property", .za_lua_type = LUA_TSTRING },
2962d85dedJason King		{ NULL, 0 }
2972d85dedJason King	},
2982d85dedJason King	.kwargs = {
2992d85dedJason King		{ NULL, 0 }
3002d85dedJason King	},
3012d85dedJason King};
3022d85dedJason King
3032d85dedJason Kingstatic int
3042d85dedJason Kingzcp_synctask_inherit_prop_check(void *arg, dmu_tx_t *tx)
3052d85dedJason King{
3062d85dedJason King	zcp_inherit_prop_arg_t *args = arg;
3072d85dedJason King	zfs_prop_t prop = zfs_name_to_prop(args->zipa_prop);
3082d85dedJason King
3092d85dedJason King	if (prop == ZPROP_INVAL) {
3102d85dedJason King		if (zfs_prop_user(args->zipa_prop))
3112d85dedJason King			return (0);
3122d85dedJason King
3132d85dedJason King		return (EINVAL);
3142d85dedJason King	}
3152d85dedJason King
3162d85dedJason King	if (zfs_prop_readonly(prop))
3172d85dedJason King		return (EINVAL);
3182d85dedJason King
3192d85dedJason King	if (!zfs_prop_inheritable(prop))
3202d85dedJason King		return (EINVAL);
3212d85dedJason King
3222d85dedJason King	return (dsl_props_set_check(&args->zipa_dpsa, tx));
3232d85dedJason King}
3242d85dedJason King
3252d85dedJason Kingstatic void
3262d85dedJason Kingzcp_synctask_inherit_prop_sync(void *arg, dmu_tx_t *tx)
3272d85dedJason King{
3282d85dedJason King	zcp_inherit_prop_arg_t *args = arg;
3292d85dedJason King	dsl_props_set_arg_t *dpsa = &args->zipa_dpsa;
3302d85dedJason King
3312d85dedJason King	dsl_props_set_sync(dpsa, tx);
3322d85dedJason King}
3332d85dedJason King
3342d85dedJason Kingstatic int
3352d85dedJason Kingzcp_synctask_inherit_prop(lua_State *state, boolean_t sync,
3362d85dedJason King    nvlist_t *err_details)
3372d85dedJason King{
3382d85dedJason King	int err;
3392d85dedJason King	zcp_inherit_prop_arg_t zipa = { 0 };
3402d85dedJason King	dsl_props_set_arg_t *dpsa = &zipa.zipa_dpsa;
3412d85dedJason King
3422d85dedJason King	const char *dsname = lua_tostring(state, 1);
3432d85dedJason King	const char *prop = lua_tostring(state, 2);
3442d85dedJason King
3452d85dedJason King	zipa.zipa_state = state;
3462d85dedJason King	zipa.zipa_prop = prop;
3472d85dedJason King	dpsa->dpsa_dsname = dsname;
3482d85dedJason King	dpsa->dpsa_source = ZPROP_SRC_INHERITED;
3492d85dedJason King	dpsa->dpsa_props = fnvlist_alloc();
3502d85dedJason King	fnvlist_add_boolean(dpsa->dpsa_props, prop);
3512d85dedJason King
3522d85dedJason King	zcp_cleanup_handler_t *zch = zcp_register_cleanup(state,
3532d85dedJason King	    (zcp_cleanup_t *)&fnvlist_free, dpsa->dpsa_props);
3542d85dedJason King
3552d85dedJason King	err = zcp_sync_task(state, zcp_synctask_inherit_prop_check,
3562d85dedJason King	    zcp_synctask_inherit_prop_sync, &zipa, sync, dsname);
3572d85dedJason King
3582d85dedJason King	zcp_deregister_cleanup(state, zch);
3592d85dedJason King	fnvlist_free(dpsa->dpsa_props);
3602d85dedJason King
3612d85dedJason King	return (err);
3622d85dedJason King}
3632d85dedJason King
364b2d2f35Sara Hartsestatic int zcp_synctask_set_prop(lua_State *, boolean_t, nvlist_t *err_details);
365b2d2f35Sara Hartsestatic zcp_synctask_info_t zcp_synctask_set_prop_info = {
366b2d2f35Sara Hartse	.name = "set_prop",
367b2d2f35Sara Hartse	.func = zcp_synctask_set_prop,
368b2d2f35Sara Hartse	.space_check = ZFS_SPACE_CHECK_RESERVED,
369b2d2f35Sara Hartse	.blocks_modified = 2,
370b2d2f35Sara Hartse	.pargs = {
371b2d2f35Sara Hartse		{ .za_name = "dataset", .za_lua_type = LUA_TSTRING},
372b2d2f35Sara Hartse		{ .za_name = "property", .za_lua_type =  LUA_TSTRING},
373b2d2f35Sara Hartse		{ .za_name = "value", .za_lua_type =  LUA_TSTRING},
374b2d2f35Sara Hartse		{ NULL, 0 }
375b2d2f35Sara Hartse	},
376b2d2f35Sara Hartse	.kwargs = {
377b2d2f35Sara Hartse		{ NULL, 0 }
378b2d2f35Sara Hartse	}
379b2d2f35Sara Hartse};
380b2d2f35Sara Hartse
381b2d2f35Sara Hartsestatic int
382b2d2f35Sara Hartsezcp_synctask_set_prop(lua_State *state, boolean_t sync, nvlist_t *err_details)
383b2d2f35Sara Hartse{
384b2d2f35Sara Hartse	int err;
385b2d2f35Sara Hartse	zcp_set_prop_arg_t args = { 0 };
386b2d2f35Sara Hartse
387b2d2f35Sara Hartse	const char *dsname = lua_tostring(state, 1);
388b2d2f35Sara Hartse	const char *prop = lua_tostring(state, 2);
389b2d2f35Sara Hartse	const char *val = lua_tostring(state, 3);
390b2d2f35Sara Hartse
391b2d2f35Sara Hartse	args.state = state;
392b2d2f35Sara Hartse	args.dsname = dsname;
393b2d2f35Sara Hartse	args.prop = prop;
394b2d2f35Sara Hartse	args.val = val;
395b2d2f35Sara Hartse
396b2d2f35Sara Hartse	err = zcp_sync_task(state, zcp_set_prop_check, zcp_set_prop_sync,
397b2d2f35Sara Hartse	    &args, sync, dsname);
398b2d2f35Sara Hartse
399b2d2f35Sara Hartse	return (err);
400b2d2f35Sara Hartse}
401b2d2f35Sara Hartse
402dfc1153Chris Williamsonstatic int
403dfc1153Chris Williamsonzcp_synctask_wrapper(lua_State *state)
404dfc1153Chris Williamson{
405dfc1153Chris Williamson	int err;
406a3b2868Serapheim Dimitropoulos	zcp_cleanup_handler_t *zch;
407dfc1153Chris Williamson	int num_ret = 1;
408dfc1153Chris Williamson	nvlist_t *err_details = fnvlist_alloc();
409dfc1153Chris Williamson
410dfc1153Chris Williamson	/*
411dfc1153Chris Williamson	 * Make sure err_details is properly freed, even if a fatal error is
412dfc1153Chris Williamson	 * thrown during the synctask.
413dfc1153Chris Williamson	 */
414a3b2868Serapheim Dimitropoulos	zch = zcp_register_cleanup(state,
415a3b2868Serapheim Dimitropoulos	    (zcp_cleanup_t *)&fnvlist_free, err_details);
416dfc1153Chris Williamson
417dfc1153Chris Williamson	zcp_synctask_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
418dfc1153Chris Williamson	boolean_t sync = lua_toboolean(state, lua_upvalueindex(2));
419dfc1153Chris Williamson
420dfc1153Chris Williamson	zcp_run_info_t *ri = zcp_run_info(state);
421dfc1153Chris Williamson	dsl_pool_t *dp = ri->zri_pool;
422dfc1153Chris Williamson
423dfc1153Chris Williamson	/* MOS space is triple-dittoed, so we multiply by 3. */
424dfc1153Chris Williamson	uint64_t funcspace = (info->blocks_modified << DST_AVG_BLKSHIFT) * 3;
425dfc1153Chris Williamson
426dfc1153Chris Williamson	zcp_parse_args(state, info->name, info->pargs, info->kwargs);
427dfc1153Chris Williamson
428dfc1153Chris Williamson	err = 0;
4298671400Serapheim Dimitropoulos	if (info->space_check != ZFS_SPACE_CHECK_NONE) {
4308671400Serapheim Dimitropoulos		uint64_t quota = dsl_pool_unreserved_space(dp,
4318671400Serapheim Dimitropoulos		    info->space_check);
432dfc1153Chris Williamson		uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes +
433dfc1153Chris Williamson		    ri->zri_space_used;
434dfc1153Chris Williamson
435dfc1153Chris Williamson		if (used + funcspace > quota) {
436dfc1153Chris Williamson			err = SET_ERROR(ENOSPC);
437dfc1153Chris Williamson		}
438dfc1153Chris Williamson	}
439dfc1153Chris Williamson
440dfc1153Chris Williamson	if (err == 0) {
441dfc1153Chris Williamson		err = info->func(state, sync, err_details);
442dfc1153Chris Williamson	}
443dfc1153Chris Williamson
444dfc1153Chris Williamson	if (err == 0) {
445dfc1153Chris Williamson		ri->zri_space_used += funcspace;
446dfc1153Chris Williamson	}
447dfc1153Chris Williamson
448dfc1153Chris Williamson	lua_pushnumber(state, (lua_Number)err);
449dfc1153Chris Williamson	if (fnvlist_num_pairs(err_details) > 0) {
450dfc1153Chris Williamson		(void) zcp_nvlist_to_lua(state, err_details, NULL, 0);
451dfc1153Chris Williamson		num_ret++;
452dfc1153Chris Williamson	}
453dfc1153Chris Williamson
454a3b2868Serapheim Dimitropoulos	zcp_deregister_cleanup(state, zch);
455dfc1153Chris Williamson	fnvlist_free(err_details);
456dfc1153Chris Williamson
457dfc1153Chris Williamson	return (num_ret);
458dfc1153Chris Williamson}
459dfc1153Chris Williamson
460dfc1153Chris Williamsonint
461dfc1153Chris Williamsonzcp_load_synctask_lib(lua_State *state, boolean_t sync)
462dfc1153Chris Williamson{
463dfc1153Chris Williamson	int i;
464dfc1153Chris Williamson	zcp_synctask_info_t *zcp_synctask_funcs[] = {
465dfc1153Chris Williamson		&zcp_synctask_destroy_info,
466dfc1153Chris Williamson		&zcp_synctask_promote_info,
467000cce6Brad Lewis		&zcp_synctask_rollback_info,
4682840dceChris Williamson		&zcp_synctask_snapshot_info,
4692d85dedJason King		&zcp_synctask_inherit_prop_info,
470b2d2f35Sara Hartse		&zcp_synctask_set_prop_info,
471dfc1153Chris Williamson		NULL
472dfc1153Chris Williamson	};
473dfc1153Chris Williamson
474dfc1153Chris Williamson	lua_newtable(state);
475dfc1153Chris Williamson
476dfc1153Chris Williamson	for (i = 0; zcp_synctask_funcs[i] != NULL; i++) {
477dfc1153Chris Williamson		zcp_synctask_info_t *info = zcp_synctask_funcs[i];
478dfc1153Chris Williamson		lua_pushlightuserdata(state, info);
479dfc1153Chris Williamson		lua_pushboolean(state, sync);
480dfc1153Chris Williamson		lua_pushcclosure(state, &zcp_synctask_wrapper, 2);
481dfc1153Chris Williamson		lua_setfield(state, -2, info->name);
482dfc1153Chris Williamson		info++;
483dfc1153Chris Williamson	}
484dfc1153Chris Williamson
485dfc1153Chris Williamson	return (1);
486dfc1153Chris Williamson}