xref: /illumos-gate/usr/src/uts/common/fs/zfs/zcp_synctask.c (revision dfc115332c94a2f62058ac7f2bce7631fbd20b3d)
1*dfc11533SChris Williamson /*
2*dfc11533SChris Williamson  * CDDL HEADER START
3*dfc11533SChris Williamson  *
4*dfc11533SChris Williamson  * This file and its contents are supplied under the terms of the
5*dfc11533SChris Williamson  * Common Development and Distribution License ("CDDL"), version 1.0.
6*dfc11533SChris Williamson  * You may only use this file in accordance with the terms of version
7*dfc11533SChris Williamson  * 1.0 of the CDDL.
8*dfc11533SChris Williamson  *
9*dfc11533SChris Williamson  * A full copy of the text of the CDDL should have accompanied this
10*dfc11533SChris Williamson  * source.  A copy of the CDDL is also available via the Internet at
11*dfc11533SChris Williamson  * http://www.illumos.org/license/CDDL.
12*dfc11533SChris Williamson  *
13*dfc11533SChris Williamson  * CDDL HEADER END
14*dfc11533SChris Williamson  */
15*dfc11533SChris Williamson 
16*dfc11533SChris Williamson /*
17*dfc11533SChris Williamson  * Copyright (c) 2016 by Delphix. All rights reserved.
18*dfc11533SChris Williamson  */
19*dfc11533SChris Williamson 
20*dfc11533SChris Williamson #include "lua.h"
21*dfc11533SChris Williamson #include "lauxlib.h"
22*dfc11533SChris Williamson 
23*dfc11533SChris Williamson #include <sys/zcp.h>
24*dfc11533SChris Williamson #include <sys/dsl_dir.h>
25*dfc11533SChris Williamson #include <sys/dsl_pool.h>
26*dfc11533SChris Williamson #include <sys/dsl_prop.h>
27*dfc11533SChris Williamson #include <sys/dsl_synctask.h>
28*dfc11533SChris Williamson #include <sys/dsl_dataset.h>
29*dfc11533SChris Williamson #include <sys/dsl_bookmark.h>
30*dfc11533SChris Williamson #include <sys/dsl_destroy.h>
31*dfc11533SChris Williamson #include <sys/dmu_objset.h>
32*dfc11533SChris Williamson #include <sys/zfs_znode.h>
33*dfc11533SChris Williamson #include <sys/zfeature.h>
34*dfc11533SChris Williamson #include <sys/metaslab.h>
35*dfc11533SChris Williamson 
36*dfc11533SChris Williamson #define	DST_AVG_BLKSHIFT 14
37*dfc11533SChris Williamson 
38*dfc11533SChris Williamson typedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *);
39*dfc11533SChris Williamson typedef struct zcp_synctask_info {
40*dfc11533SChris Williamson 	const char *name;
41*dfc11533SChris Williamson 	zcp_synctask_func_t *func;
42*dfc11533SChris Williamson 	zfs_space_check_t space_check;
43*dfc11533SChris Williamson 	int blocks_modified;
44*dfc11533SChris Williamson 	const zcp_arg_t pargs[4];
45*dfc11533SChris Williamson 	const zcp_arg_t kwargs[2];
46*dfc11533SChris Williamson } zcp_synctask_info_t;
47*dfc11533SChris Williamson 
48*dfc11533SChris Williamson /*
49*dfc11533SChris Williamson  * Generic synctask interface for channel program syncfuncs.
50*dfc11533SChris Williamson  *
51*dfc11533SChris Williamson  * To perform some action in syncing context, we'd generally call
52*dfc11533SChris Williamson  * dsl_sync_task(), but since the Lua script is already running inside a
53*dfc11533SChris Williamson  * synctask we need to leave out some actions (such as acquiring the config
54*dfc11533SChris Williamson  * rwlock and performing space checks).
55*dfc11533SChris Williamson  *
56*dfc11533SChris Williamson  * If 'sync' is false, executes a dry run and returns the error code.
57*dfc11533SChris Williamson  *
58*dfc11533SChris Williamson  * This function also handles common fatal error cases for channel program
59*dfc11533SChris Williamson  * library functions. If a fatal error occurs, err_dsname will be the dataset
60*dfc11533SChris Williamson  * name reported in error messages, if supplied.
61*dfc11533SChris Williamson  */
62*dfc11533SChris Williamson static int
63*dfc11533SChris Williamson zcp_sync_task(lua_State *state, dsl_checkfunc_t *checkfunc,
64*dfc11533SChris Williamson     dsl_syncfunc_t *syncfunc, void *arg, boolean_t sync, const char *err_dsname)
65*dfc11533SChris Williamson {
66*dfc11533SChris Williamson 	int err;
67*dfc11533SChris Williamson 	zcp_run_info_t *ri = zcp_run_info(state);
68*dfc11533SChris Williamson 
69*dfc11533SChris Williamson 	err = checkfunc(arg, ri->zri_tx);
70*dfc11533SChris Williamson 	if (!sync)
71*dfc11533SChris Williamson 		return (err);
72*dfc11533SChris Williamson 
73*dfc11533SChris Williamson 	if (err == 0) {
74*dfc11533SChris Williamson 		syncfunc(arg, ri->zri_tx);
75*dfc11533SChris Williamson 	} else if (err == EIO) {
76*dfc11533SChris Williamson 		if (err_dsname != NULL) {
77*dfc11533SChris Williamson 			return (luaL_error(state,
78*dfc11533SChris Williamson 			    "I/O error while accessing dataset '%s'",
79*dfc11533SChris Williamson 			    err_dsname));
80*dfc11533SChris Williamson 		} else {
81*dfc11533SChris Williamson 			return (luaL_error(state,
82*dfc11533SChris Williamson 			    "I/O error while accessing dataset."));
83*dfc11533SChris Williamson 		}
84*dfc11533SChris Williamson 	}
85*dfc11533SChris Williamson 
86*dfc11533SChris Williamson 	return (err);
87*dfc11533SChris Williamson }
88*dfc11533SChris Williamson 
89*dfc11533SChris Williamson 
90*dfc11533SChris Williamson static int zcp_synctask_destroy(lua_State *, boolean_t, nvlist_t *);
91*dfc11533SChris Williamson static zcp_synctask_info_t zcp_synctask_destroy_info = {
92*dfc11533SChris Williamson 	.name = "destroy",
93*dfc11533SChris Williamson 	.func = zcp_synctask_destroy,
94*dfc11533SChris Williamson 	.space_check = ZFS_SPACE_CHECK_NONE,
95*dfc11533SChris Williamson 	.blocks_modified = 0,
96*dfc11533SChris Williamson 	.pargs = {
97*dfc11533SChris Williamson 	    {.za_name = "filesystem | snapshot", .za_lua_type = LUA_TSTRING},
98*dfc11533SChris Williamson 	    {NULL, NULL}
99*dfc11533SChris Williamson 	},
100*dfc11533SChris Williamson 	.kwargs = {
101*dfc11533SChris Williamson 	    {.za_name = "defer", .za_lua_type = LUA_TBOOLEAN},
102*dfc11533SChris Williamson 	    {NULL, NULL}
103*dfc11533SChris Williamson 	}
104*dfc11533SChris Williamson };
105*dfc11533SChris Williamson 
106*dfc11533SChris Williamson /* ARGSUSED */
107*dfc11533SChris Williamson static int
108*dfc11533SChris Williamson zcp_synctask_destroy(lua_State *state, boolean_t sync, nvlist_t *err_details)
109*dfc11533SChris Williamson {
110*dfc11533SChris Williamson 	int err;
111*dfc11533SChris Williamson 	const char *dsname = lua_tostring(state, 1);
112*dfc11533SChris Williamson 
113*dfc11533SChris Williamson 	boolean_t issnap = (strchr(dsname, '@') != NULL);
114*dfc11533SChris Williamson 
115*dfc11533SChris Williamson 	if (!issnap && !lua_isnil(state, 2)) {
116*dfc11533SChris Williamson 		return (luaL_error(state,
117*dfc11533SChris Williamson 		    "'deferred' kwarg only supported for snapshots: %s",
118*dfc11533SChris Williamson 		    dsname));
119*dfc11533SChris Williamson 	}
120*dfc11533SChris Williamson 
121*dfc11533SChris Williamson 	if (issnap) {
122*dfc11533SChris Williamson 		dsl_destroy_snapshot_arg_t ddsa = { 0 };
123*dfc11533SChris Williamson 		ddsa.ddsa_name = dsname;
124*dfc11533SChris Williamson 		if (!lua_isnil(state, 2)) {
125*dfc11533SChris Williamson 			ddsa.ddsa_defer = lua_toboolean(state, 2);
126*dfc11533SChris Williamson 		} else {
127*dfc11533SChris Williamson 			ddsa.ddsa_defer = B_FALSE;
128*dfc11533SChris Williamson 		}
129*dfc11533SChris Williamson 
130*dfc11533SChris Williamson 		err = zcp_sync_task(state, dsl_destroy_snapshot_check,
131*dfc11533SChris Williamson 		    dsl_destroy_snapshot_sync, &ddsa, sync, dsname);
132*dfc11533SChris Williamson 	} else {
133*dfc11533SChris Williamson 		dsl_destroy_head_arg_t ddha = { 0 };
134*dfc11533SChris Williamson 		ddha.ddha_name = dsname;
135*dfc11533SChris Williamson 
136*dfc11533SChris Williamson 		err = zcp_sync_task(state, dsl_destroy_head_check,
137*dfc11533SChris Williamson 		    dsl_destroy_head_sync, &ddha, sync, dsname);
138*dfc11533SChris Williamson 	}
139*dfc11533SChris Williamson 
140*dfc11533SChris Williamson 	return (err);
141*dfc11533SChris Williamson }
142*dfc11533SChris Williamson 
143*dfc11533SChris Williamson static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *err_details);
144*dfc11533SChris Williamson static zcp_synctask_info_t zcp_synctask_promote_info = {
145*dfc11533SChris Williamson 	.name = "promote",
146*dfc11533SChris Williamson 	.func = zcp_synctask_promote,
147*dfc11533SChris Williamson 	.space_check = ZFS_SPACE_CHECK_RESERVED,
148*dfc11533SChris Williamson 	.blocks_modified = 3,
149*dfc11533SChris Williamson 	.pargs = {
150*dfc11533SChris Williamson 	    {.za_name = "clone", .za_lua_type = LUA_TSTRING},
151*dfc11533SChris Williamson 	    {NULL, NULL}
152*dfc11533SChris Williamson 	},
153*dfc11533SChris Williamson 	.kwargs = {
154*dfc11533SChris Williamson 	    {NULL, NULL}
155*dfc11533SChris Williamson 	}
156*dfc11533SChris Williamson };
157*dfc11533SChris Williamson 
158*dfc11533SChris Williamson static int
159*dfc11533SChris Williamson zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
160*dfc11533SChris Williamson {
161*dfc11533SChris Williamson 	int err;
162*dfc11533SChris Williamson 	dsl_dataset_promote_arg_t ddpa = { 0 };
163*dfc11533SChris Williamson 	const char *dsname = lua_tostring(state, 1);
164*dfc11533SChris Williamson 	zcp_run_info_t *ri = zcp_run_info(state);
165*dfc11533SChris Williamson 
166*dfc11533SChris Williamson 	ddpa.ddpa_clonename = dsname;
167*dfc11533SChris Williamson 	ddpa.err_ds = err_details;
168*dfc11533SChris Williamson 	ddpa.cr = ri->zri_cred;
169*dfc11533SChris Williamson 
170*dfc11533SChris Williamson 	/*
171*dfc11533SChris Williamson 	 * If there was a snapshot name conflict, then err_ds will be filled
172*dfc11533SChris Williamson 	 * with a list of conflicting snapshot names.
173*dfc11533SChris Williamson 	 */
174*dfc11533SChris Williamson 	err = zcp_sync_task(state, dsl_dataset_promote_check,
175*dfc11533SChris Williamson 	    dsl_dataset_promote_sync, &ddpa, sync, dsname);
176*dfc11533SChris Williamson 
177*dfc11533SChris Williamson 	return (err);
178*dfc11533SChris Williamson }
179*dfc11533SChris Williamson 
180*dfc11533SChris Williamson void
181*dfc11533SChris Williamson zcp_synctask_wrapper_cleanup(void *arg)
182*dfc11533SChris Williamson {
183*dfc11533SChris Williamson 	fnvlist_free(arg);
184*dfc11533SChris Williamson }
185*dfc11533SChris Williamson 
186*dfc11533SChris Williamson static int
187*dfc11533SChris Williamson zcp_synctask_wrapper(lua_State *state)
188*dfc11533SChris Williamson {
189*dfc11533SChris Williamson 	int err;
190*dfc11533SChris Williamson 	int num_ret = 1;
191*dfc11533SChris Williamson 	nvlist_t *err_details = fnvlist_alloc();
192*dfc11533SChris Williamson 
193*dfc11533SChris Williamson 	/*
194*dfc11533SChris Williamson 	 * Make sure err_details is properly freed, even if a fatal error is
195*dfc11533SChris Williamson 	 * thrown during the synctask.
196*dfc11533SChris Williamson 	 */
197*dfc11533SChris Williamson 	zcp_register_cleanup(state, &zcp_synctask_wrapper_cleanup, err_details);
198*dfc11533SChris Williamson 
199*dfc11533SChris Williamson 	zcp_synctask_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
200*dfc11533SChris Williamson 	boolean_t sync = lua_toboolean(state, lua_upvalueindex(2));
201*dfc11533SChris Williamson 
202*dfc11533SChris Williamson 	zcp_run_info_t *ri = zcp_run_info(state);
203*dfc11533SChris Williamson 	dsl_pool_t *dp = ri->zri_pool;
204*dfc11533SChris Williamson 
205*dfc11533SChris Williamson 	/* MOS space is triple-dittoed, so we multiply by 3. */
206*dfc11533SChris Williamson 	uint64_t funcspace = (info->blocks_modified << DST_AVG_BLKSHIFT) * 3;
207*dfc11533SChris Williamson 
208*dfc11533SChris Williamson 	zcp_parse_args(state, info->name, info->pargs, info->kwargs);
209*dfc11533SChris Williamson 
210*dfc11533SChris Williamson 	err = 0;
211*dfc11533SChris Williamson 	if (info->space_check != ZFS_SPACE_CHECK_NONE && funcspace > 0) {
212*dfc11533SChris Williamson 		uint64_t quota = dsl_pool_adjustedsize(dp,
213*dfc11533SChris Williamson 		    info->space_check == ZFS_SPACE_CHECK_RESERVED) -
214*dfc11533SChris Williamson 		    metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
215*dfc11533SChris Williamson 		uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes +
216*dfc11533SChris Williamson 		    ri->zri_space_used;
217*dfc11533SChris Williamson 
218*dfc11533SChris Williamson 		if (used + funcspace > quota) {
219*dfc11533SChris Williamson 			err = SET_ERROR(ENOSPC);
220*dfc11533SChris Williamson 		}
221*dfc11533SChris Williamson 	}
222*dfc11533SChris Williamson 
223*dfc11533SChris Williamson 	if (err == 0) {
224*dfc11533SChris Williamson 		err = info->func(state, sync, err_details);
225*dfc11533SChris Williamson 	}
226*dfc11533SChris Williamson 
227*dfc11533SChris Williamson 	if (err == 0) {
228*dfc11533SChris Williamson 		ri->zri_space_used += funcspace;
229*dfc11533SChris Williamson 	}
230*dfc11533SChris Williamson 
231*dfc11533SChris Williamson 	lua_pushnumber(state, (lua_Number)err);
232*dfc11533SChris Williamson 	if (fnvlist_num_pairs(err_details) > 0) {
233*dfc11533SChris Williamson 		(void) zcp_nvlist_to_lua(state, err_details, NULL, 0);
234*dfc11533SChris Williamson 		num_ret++;
235*dfc11533SChris Williamson 	}
236*dfc11533SChris Williamson 
237*dfc11533SChris Williamson 	zcp_clear_cleanup(state);
238*dfc11533SChris Williamson 	fnvlist_free(err_details);
239*dfc11533SChris Williamson 
240*dfc11533SChris Williamson 	return (num_ret);
241*dfc11533SChris Williamson }
242*dfc11533SChris Williamson 
243*dfc11533SChris Williamson int
244*dfc11533SChris Williamson zcp_load_synctask_lib(lua_State *state, boolean_t sync)
245*dfc11533SChris Williamson {
246*dfc11533SChris Williamson 	int i;
247*dfc11533SChris Williamson 	zcp_synctask_info_t *zcp_synctask_funcs[] = {
248*dfc11533SChris Williamson 		&zcp_synctask_destroy_info,
249*dfc11533SChris Williamson 		&zcp_synctask_promote_info,
250*dfc11533SChris Williamson 		NULL
251*dfc11533SChris Williamson 	};
252*dfc11533SChris Williamson 
253*dfc11533SChris Williamson 	lua_newtable(state);
254*dfc11533SChris Williamson 
255*dfc11533SChris Williamson 	for (i = 0; zcp_synctask_funcs[i] != NULL; i++) {
256*dfc11533SChris Williamson 		zcp_synctask_info_t *info = zcp_synctask_funcs[i];
257*dfc11533SChris Williamson 		lua_pushlightuserdata(state, info);
258*dfc11533SChris Williamson 		lua_pushboolean(state, sync);
259*dfc11533SChris Williamson 		lua_pushcclosure(state, &zcp_synctask_wrapper, 2);
260*dfc11533SChris Williamson 		lua_setfield(state, -2, info->name);
261*dfc11533SChris Williamson 		info++;
262*dfc11533SChris Williamson 	}
263*dfc11533SChris Williamson 
264*dfc11533SChris Williamson 	return (1);
265*dfc11533SChris Williamson }
266