xref: /illumos-gate/usr/src/uts/common/fs/zfs/zcp_synctask.c (revision a92282e44f968185a6bba094d1e5fece2da819cf)
1 /*
2  * CDDL HEADER START
3  *
4  * This file and its contents are supplied under the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may only use this file in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.illumos.org/license/CDDL.
12  *
13  * CDDL HEADER END
14  */
15 
16 /*
17  * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
18  * Copyright 2020 Joyent, Inc.
19  */
20 
21 #include "lua.h"
22 #include "lauxlib.h"
23 
24 #include <sys/zcp.h>
25 #include <sys/zcp_set.h>
26 #include <sys/dsl_dir.h>
27 #include <sys/dsl_pool.h>
28 #include <sys/dsl_prop.h>
29 #include <sys/dsl_synctask.h>
30 #include <sys/dsl_dataset.h>
31 #include <sys/dsl_bookmark.h>
32 #include <sys/dsl_destroy.h>
33 #include <sys/dmu_objset.h>
34 #include <sys/zfs_znode.h>
35 #include <sys/zfeature.h>
36 #include <sys/metaslab.h>
37 
38 #define	DST_AVG_BLKSHIFT 14
39 
40 typedef struct zcp_inherit_prop_arg {
41 	lua_State		*zipa_state;
42 	const char		*zipa_prop;
43 	dsl_props_set_arg_t	zipa_dpsa;
44 } zcp_inherit_prop_arg_t;
45 
46 typedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *);
47 typedef struct zcp_synctask_info {
48 	const char *name;
49 	zcp_synctask_func_t *func;
50 	const zcp_arg_t pargs[4];
51 	const zcp_arg_t kwargs[2];
52 	zfs_space_check_t space_check;
53 	int blocks_modified;
54 } zcp_synctask_info_t;
55 
56 /*
57  * Generic synctask interface for channel program syncfuncs.
58  *
59  * To perform some action in syncing context, we'd generally call
60  * dsl_sync_task(), but since the Lua script is already running inside a
61  * synctask we need to leave out some actions (such as acquiring the config
62  * rwlock and performing space checks).
63  *
64  * If 'sync' is false, executes a dry run and returns the error code.
65  *
66  * If we are not running in syncing context and we are not doing a dry run
67  * (meaning we are running a zfs.sync function in open-context) then we
68  * return a Lua error.
69  *
70  * This function also handles common fatal error cases for channel program
71  * library functions. If a fatal error occurs, err_dsname will be the dataset
72  * name reported in error messages, if supplied.
73  */
74 static int
75 zcp_sync_task(lua_State *state, dsl_checkfunc_t *checkfunc,
76     dsl_syncfunc_t *syncfunc, void *arg, boolean_t sync, const char *err_dsname)
77 {
78 	int err;
79 	zcp_run_info_t *ri = zcp_run_info(state);
80 
81 	err = checkfunc(arg, ri->zri_tx);
82 	if (!sync)
83 		return (err);
84 
85 	if (!ri->zri_sync) {
86 		return (luaL_error(state, "running functions from the zfs.sync "
87 		    "submodule requires passing sync=TRUE to "
88 		    "lzc_channel_program() (i.e. do not specify the \"-n\" "
89 		    "command line argument)"));
90 	}
91 
92 	if (err == 0) {
93 		syncfunc(arg, ri->zri_tx);
94 	} else if (err == EIO) {
95 		if (err_dsname != NULL) {
96 			return (luaL_error(state,
97 			    "I/O error while accessing dataset '%s'",
98 			    err_dsname));
99 		} else {
100 			return (luaL_error(state,
101 			    "I/O error while accessing dataset."));
102 		}
103 	}
104 
105 	return (err);
106 }
107 
108 
109 static int zcp_synctask_destroy(lua_State *, boolean_t, nvlist_t *);
110 static zcp_synctask_info_t zcp_synctask_destroy_info = {
111 	.name = "destroy",
112 	.func = zcp_synctask_destroy,
113 	.pargs = {
114 	    {.za_name = "filesystem | snapshot", .za_lua_type = LUA_TSTRING},
115 	    {NULL, 0}
116 	},
117 	.kwargs = {
118 	    {.za_name = "defer", .za_lua_type = LUA_TBOOLEAN},
119 	    {NULL, 0}
120 	},
121 	.space_check = ZFS_SPACE_CHECK_DESTROY,
122 	.blocks_modified = 0
123 };
124 
125 /* ARGSUSED */
126 static int
127 zcp_synctask_destroy(lua_State *state, boolean_t sync, nvlist_t *err_details)
128 {
129 	int err;
130 	const char *dsname = lua_tostring(state, 1);
131 
132 	boolean_t issnap = (strchr(dsname, '@') != NULL);
133 
134 	if (!issnap && !lua_isnil(state, 2)) {
135 		return (luaL_error(state,
136 		    "'deferred' kwarg only supported for snapshots: %s",
137 		    dsname));
138 	}
139 
140 	if (issnap) {
141 		dsl_destroy_snapshot_arg_t ddsa = { 0 };
142 		ddsa.ddsa_name = dsname;
143 		if (!lua_isnil(state, 2)) {
144 			ddsa.ddsa_defer = lua_toboolean(state, 2);
145 		} else {
146 			ddsa.ddsa_defer = B_FALSE;
147 		}
148 
149 		err = zcp_sync_task(state, dsl_destroy_snapshot_check,
150 		    dsl_destroy_snapshot_sync, &ddsa, sync, dsname);
151 	} else {
152 		dsl_destroy_head_arg_t ddha = { 0 };
153 		ddha.ddha_name = dsname;
154 
155 		err = zcp_sync_task(state, dsl_destroy_head_check,
156 		    dsl_destroy_head_sync, &ddha, sync, dsname);
157 	}
158 
159 	return (err);
160 }
161 
162 static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *);
163 static zcp_synctask_info_t zcp_synctask_promote_info = {
164 	.name = "promote",
165 	.func = zcp_synctask_promote,
166 	.pargs = {
167 	    {.za_name = "clone", .za_lua_type = LUA_TSTRING},
168 	    {NULL, 0}
169 	},
170 	.kwargs = {
171 	    {NULL, 0}
172 	},
173 	.space_check = ZFS_SPACE_CHECK_RESERVED,
174 	.blocks_modified = 3
175 };
176 
177 static int
178 zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
179 {
180 	int err;
181 	dsl_dataset_promote_arg_t ddpa = { 0 };
182 	const char *dsname = lua_tostring(state, 1);
183 	zcp_run_info_t *ri = zcp_run_info(state);
184 
185 	ddpa.ddpa_clonename = dsname;
186 	ddpa.err_ds = err_details;
187 	ddpa.cr = ri->zri_cred;
188 
189 	/*
190 	 * If there was a snapshot name conflict, then err_ds will be filled
191 	 * with a list of conflicting snapshot names.
192 	 */
193 	err = zcp_sync_task(state, dsl_dataset_promote_check,
194 	    dsl_dataset_promote_sync, &ddpa, sync, dsname);
195 
196 	return (err);
197 }
198 
199 static int zcp_synctask_rollback(lua_State *, boolean_t, nvlist_t *err_details);
200 static zcp_synctask_info_t zcp_synctask_rollback_info = {
201 	.name = "rollback",
202 	.func = zcp_synctask_rollback,
203 	.space_check = ZFS_SPACE_CHECK_RESERVED,
204 	.blocks_modified = 1,
205 	.pargs = {
206 	    {.za_name = "filesystem", .za_lua_type = LUA_TSTRING},
207 	    {NULL, 0}
208 	},
209 	.kwargs = {
210 	    {NULL, 0}
211 	}
212 };
213 
214 static int
215 zcp_synctask_rollback(lua_State *state, boolean_t sync, nvlist_t *err_details)
216 {
217 	int err;
218 	const char *dsname = lua_tostring(state, 1);
219 	dsl_dataset_rollback_arg_t ddra = { 0 };
220 
221 	ddra.ddra_fsname = dsname;
222 	ddra.ddra_result = err_details;
223 
224 	err = zcp_sync_task(state, dsl_dataset_rollback_check,
225 	    dsl_dataset_rollback_sync, &ddra, sync, dsname);
226 
227 	return (err);
228 }
229 
230 static int zcp_synctask_snapshot(lua_State *, boolean_t, nvlist_t *);
231 static zcp_synctask_info_t zcp_synctask_snapshot_info = {
232 	.name = "snapshot",
233 	.func = zcp_synctask_snapshot,
234 	.pargs = {
235 	    {.za_name = "filesystem@snapname | volume@snapname",
236 	    .za_lua_type = LUA_TSTRING},
237 	    {NULL, 0}
238 	},
239 	.kwargs = {
240 	    {NULL, 0}
241 	},
242 	.space_check = ZFS_SPACE_CHECK_NORMAL,
243 	.blocks_modified = 3
244 };
245 
246 /* ARGSUSED */
247 static int
248 zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
249 {
250 	int err;
251 	dsl_dataset_snapshot_arg_t ddsa = { 0 };
252 	const char *dsname = lua_tostring(state, 1);
253 	zcp_run_info_t *ri = zcp_run_info(state);
254 
255 	/*
256 	 * On old pools, the ZIL must not be active when a snapshot is created,
257 	 * but we can't suspend the ZIL because we're already in syncing
258 	 * context.
259 	 */
260 	if (spa_version(ri->zri_pool->dp_spa) < SPA_VERSION_FAST_SNAP) {
261 		return (ENOTSUP);
262 	}
263 
264 	/*
265 	 * We only allow for a single snapshot rather than a list, so the
266 	 * error list output is unnecessary.
267 	 */
268 	ddsa.ddsa_errors = NULL;
269 	ddsa.ddsa_props = NULL;
270 	ddsa.ddsa_cr = ri->zri_cred;
271 	ddsa.ddsa_snaps = fnvlist_alloc();
272 	fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);
273 
274 	zcp_cleanup_handler_t *zch = zcp_register_cleanup(state,
275 	    (zcp_cleanup_t *)&fnvlist_free, ddsa.ddsa_snaps);
276 
277 	err = zcp_sync_task(state, dsl_dataset_snapshot_check,
278 	    dsl_dataset_snapshot_sync, &ddsa, sync, dsname);
279 
280 	zcp_deregister_cleanup(state, zch);
281 	fnvlist_free(ddsa.ddsa_snaps);
282 
283 	return (err);
284 }
285 
286 static int zcp_synctask_inherit_prop(lua_State *, boolean_t,
287     nvlist_t *err_details);
288 static zcp_synctask_info_t zcp_synctask_inherit_prop_info = {
289 	.name = "inherit",
290 	.func = zcp_synctask_inherit_prop,
291 	.space_check = ZFS_SPACE_CHECK_RESERVED,
292 	.blocks_modified = 2, /* 2 * numprops */
293 	.pargs = {
294 		{ .za_name = "dataset", .za_lua_type = LUA_TSTRING },
295 		{ .za_name = "property", .za_lua_type = LUA_TSTRING },
296 		{ NULL, 0 }
297 	},
298 	.kwargs = {
299 		{ NULL, 0 }
300 	},
301 };
302 
303 static int
304 zcp_synctask_inherit_prop_check(void *arg, dmu_tx_t *tx)
305 {
306 	zcp_inherit_prop_arg_t *args = arg;
307 	zfs_prop_t prop = zfs_name_to_prop(args->zipa_prop);
308 
309 	if (prop == ZPROP_INVAL) {
310 		if (zfs_prop_user(args->zipa_prop))
311 			return (0);
312 
313 		return (EINVAL);
314 	}
315 
316 	if (zfs_prop_readonly(prop))
317 		return (EINVAL);
318 
319 	if (!zfs_prop_inheritable(prop))
320 		return (EINVAL);
321 
322 	return (dsl_props_set_check(&args->zipa_dpsa, tx));
323 }
324 
325 static void
326 zcp_synctask_inherit_prop_sync(void *arg, dmu_tx_t *tx)
327 {
328 	zcp_inherit_prop_arg_t *args = arg;
329 	dsl_props_set_arg_t *dpsa = &args->zipa_dpsa;
330 
331 	dsl_props_set_sync(dpsa, tx);
332 }
333 
334 static int
335 zcp_synctask_inherit_prop(lua_State *state, boolean_t sync,
336     nvlist_t *err_details)
337 {
338 	int err;
339 	zcp_inherit_prop_arg_t zipa = { 0 };
340 	dsl_props_set_arg_t *dpsa = &zipa.zipa_dpsa;
341 
342 	const char *dsname = lua_tostring(state, 1);
343 	const char *prop = lua_tostring(state, 2);
344 
345 	zipa.zipa_state = state;
346 	zipa.zipa_prop = prop;
347 	dpsa->dpsa_dsname = dsname;
348 	dpsa->dpsa_source = ZPROP_SRC_INHERITED;
349 	dpsa->dpsa_props = fnvlist_alloc();
350 	fnvlist_add_boolean(dpsa->dpsa_props, prop);
351 
352 	zcp_cleanup_handler_t *zch = zcp_register_cleanup(state,
353 	    (zcp_cleanup_t *)&fnvlist_free, dpsa->dpsa_props);
354 
355 	err = zcp_sync_task(state, zcp_synctask_inherit_prop_check,
356 	    zcp_synctask_inherit_prop_sync, &zipa, sync, dsname);
357 
358 	zcp_deregister_cleanup(state, zch);
359 	fnvlist_free(dpsa->dpsa_props);
360 
361 	return (err);
362 }
363 
364 static int zcp_synctask_set_prop(lua_State *, boolean_t, nvlist_t *err_details);
365 static zcp_synctask_info_t zcp_synctask_set_prop_info = {
366 	.name = "set_prop",
367 	.func = zcp_synctask_set_prop,
368 	.space_check = ZFS_SPACE_CHECK_RESERVED,
369 	.blocks_modified = 2,
370 	.pargs = {
371 		{ .za_name = "dataset", .za_lua_type = LUA_TSTRING},
372 		{ .za_name = "property", .za_lua_type =  LUA_TSTRING},
373 		{ .za_name = "value", .za_lua_type =  LUA_TSTRING},
374 		{ NULL, 0 }
375 	},
376 	.kwargs = {
377 		{ NULL, 0 }
378 	}
379 };
380 
381 static int
382 zcp_synctask_set_prop(lua_State *state, boolean_t sync, nvlist_t *err_details)
383 {
384 	int err;
385 	zcp_set_prop_arg_t args = { 0 };
386 
387 	const char *dsname = lua_tostring(state, 1);
388 	const char *prop = lua_tostring(state, 2);
389 	const char *val = lua_tostring(state, 3);
390 
391 	args.state = state;
392 	args.dsname = dsname;
393 	args.prop = prop;
394 	args.val = val;
395 
396 	err = zcp_sync_task(state, zcp_set_prop_check, zcp_set_prop_sync,
397 	    &args, sync, dsname);
398 
399 	return (err);
400 }
401 
402 static int
403 zcp_synctask_wrapper(lua_State *state)
404 {
405 	int err;
406 	zcp_cleanup_handler_t *zch;
407 	int num_ret = 1;
408 	nvlist_t *err_details = fnvlist_alloc();
409 
410 	/*
411 	 * Make sure err_details is properly freed, even if a fatal error is
412 	 * thrown during the synctask.
413 	 */
414 	zch = zcp_register_cleanup(state,
415 	    (zcp_cleanup_t *)&fnvlist_free, err_details);
416 
417 	zcp_synctask_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
418 	boolean_t sync = lua_toboolean(state, lua_upvalueindex(2));
419 
420 	zcp_run_info_t *ri = zcp_run_info(state);
421 	dsl_pool_t *dp = ri->zri_pool;
422 
423 	/* MOS space is triple-dittoed, so we multiply by 3. */
424 	uint64_t funcspace = (info->blocks_modified << DST_AVG_BLKSHIFT) * 3;
425 
426 	zcp_parse_args(state, info->name, info->pargs, info->kwargs);
427 
428 	err = 0;
429 	if (info->space_check != ZFS_SPACE_CHECK_NONE) {
430 		uint64_t quota = dsl_pool_unreserved_space(dp,
431 		    info->space_check);
432 		uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes +
433 		    ri->zri_space_used;
434 
435 		if (used + funcspace > quota) {
436 			err = SET_ERROR(ENOSPC);
437 		}
438 	}
439 
440 	if (err == 0) {
441 		err = info->func(state, sync, err_details);
442 	}
443 
444 	if (err == 0) {
445 		ri->zri_space_used += funcspace;
446 	}
447 
448 	lua_pushnumber(state, (lua_Number)err);
449 	if (fnvlist_num_pairs(err_details) > 0) {
450 		(void) zcp_nvlist_to_lua(state, err_details, NULL, 0);
451 		num_ret++;
452 	}
453 
454 	zcp_deregister_cleanup(state, zch);
455 	fnvlist_free(err_details);
456 
457 	return (num_ret);
458 }
459 
460 int
461 zcp_load_synctask_lib(lua_State *state, boolean_t sync)
462 {
463 	int i;
464 	zcp_synctask_info_t *zcp_synctask_funcs[] = {
465 		&zcp_synctask_destroy_info,
466 		&zcp_synctask_promote_info,
467 		&zcp_synctask_rollback_info,
468 		&zcp_synctask_snapshot_info,
469 		&zcp_synctask_inherit_prop_info,
470 		&zcp_synctask_set_prop_info,
471 		NULL
472 	};
473 
474 	lua_newtable(state);
475 
476 	for (i = 0; zcp_synctask_funcs[i] != NULL; i++) {
477 		zcp_synctask_info_t *info = zcp_synctask_funcs[i];
478 		lua_pushlightuserdata(state, info);
479 		lua_pushboolean(state, sync);
480 		lua_pushcclosure(state, &zcp_synctask_wrapper, 2);
481 		lua_setfield(state, -2, info->name);
482 		info++;
483 	}
484 
485 	return (1);
486 }
487