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
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.
17 * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
24 #include <sys/dsl_dir.h>
25 #include <sys/dsl_pool.h>
26 #include <sys/dsl_prop.h>
27 #include <sys/dsl_synctask.h>
28 #include <sys/dsl_dataset.h>
29 #include <sys/dsl_bookmark.h>
30 #include <sys/dsl_destroy.h>
31 #include <sys/dmu_objset.h>
32 #include <sys/zfs_znode.h>
33 #include <sys/zfeature.h>
34 #include <sys/metaslab.h>
36 #define DST_AVG_BLKSHIFT 14
38 typedef int (zcp_synctask_func_t
)(lua_State
*, boolean_t
, nvlist_t
*);
39 typedef struct zcp_synctask_info
{
41 zcp_synctask_func_t
*func
;
42 zfs_space_check_t space_check
;
44 const zcp_arg_t pargs
[4];
45 const zcp_arg_t kwargs
[2];
46 } zcp_synctask_info_t
;
49 * Generic synctask interface for channel program syncfuncs.
51 * To perform some action in syncing context, we'd generally call
52 * dsl_sync_task(), but since the Lua script is already running inside a
53 * synctask we need to leave out some actions (such as acquiring the config
54 * rwlock and performing space checks).
56 * If 'sync' is false, executes a dry run and returns the error code.
58 * This function also handles common fatal error cases for channel program
59 * library functions. If a fatal error occurs, err_dsname will be the dataset
60 * name reported in error messages, if supplied.
63 zcp_sync_task(lua_State
*state
, dsl_checkfunc_t
*checkfunc
,
64 dsl_syncfunc_t
*syncfunc
, void *arg
, boolean_t sync
, const char *err_dsname
)
67 zcp_run_info_t
*ri
= zcp_run_info(state
);
69 err
= checkfunc(arg
, ri
->zri_tx
);
74 syncfunc(arg
, ri
->zri_tx
);
75 } else if (err
== EIO
) {
76 if (err_dsname
!= NULL
) {
77 return (luaL_error(state
,
78 "I/O error while accessing dataset '%s'",
81 return (luaL_error(state
,
82 "I/O error while accessing dataset."));
90 static int zcp_synctask_destroy(lua_State
*, boolean_t
, nvlist_t
*);
91 static zcp_synctask_info_t zcp_synctask_destroy_info
= {
93 .func
= zcp_synctask_destroy
,
94 .space_check
= ZFS_SPACE_CHECK_NONE
,
97 {.za_name
= "filesystem | snapshot", .za_lua_type
= LUA_TSTRING
},
101 {.za_name
= "defer", .za_lua_type
= LUA_TBOOLEAN
},
108 zcp_synctask_destroy(lua_State
*state
, boolean_t sync
, nvlist_t
*err_details
)
111 const char *dsname
= lua_tostring(state
, 1);
113 boolean_t issnap
= (strchr(dsname
, '@') != NULL
);
115 if (!issnap
&& !lua_isnil(state
, 2)) {
116 return (luaL_error(state
,
117 "'deferred' kwarg only supported for snapshots: %s",
122 dsl_destroy_snapshot_arg_t ddsa
= { 0 };
123 ddsa
.ddsa_name
= dsname
;
124 if (!lua_isnil(state
, 2)) {
125 ddsa
.ddsa_defer
= lua_toboolean(state
, 2);
127 ddsa
.ddsa_defer
= B_FALSE
;
130 err
= zcp_sync_task(state
, dsl_destroy_snapshot_check
,
131 dsl_destroy_snapshot_sync
, &ddsa
, sync
, dsname
);
133 dsl_destroy_head_arg_t ddha
= { 0 };
134 ddha
.ddha_name
= dsname
;
136 err
= zcp_sync_task(state
, dsl_destroy_head_check
,
137 dsl_destroy_head_sync
, &ddha
, sync
, dsname
);
143 static int zcp_synctask_promote(lua_State
*, boolean_t
, nvlist_t
*err_details
);
144 static zcp_synctask_info_t zcp_synctask_promote_info
= {
146 .func
= zcp_synctask_promote
,
147 .space_check
= ZFS_SPACE_CHECK_RESERVED
,
148 .blocks_modified
= 3,
150 {.za_name
= "clone", .za_lua_type
= LUA_TSTRING
},
159 zcp_synctask_promote(lua_State
*state
, boolean_t sync
, nvlist_t
*err_details
)
162 dsl_dataset_promote_arg_t ddpa
= { 0 };
163 const char *dsname
= lua_tostring(state
, 1);
164 zcp_run_info_t
*ri
= zcp_run_info(state
);
166 ddpa
.ddpa_clonename
= dsname
;
167 ddpa
.err_ds
= err_details
;
168 ddpa
.cr
= ri
->zri_cred
;
171 * If there was a snapshot name conflict, then err_ds will be filled
172 * with a list of conflicting snapshot names.
174 err
= zcp_sync_task(state
, dsl_dataset_promote_check
,
175 dsl_dataset_promote_sync
, &ddpa
, sync
, dsname
);
180 static int zcp_synctask_rollback(lua_State
*, boolean_t
, nvlist_t
*err_details
);
181 static zcp_synctask_info_t zcp_synctask_rollback_info
= {
183 .func
= zcp_synctask_rollback
,
184 .space_check
= ZFS_SPACE_CHECK_RESERVED
,
185 .blocks_modified
= 1,
187 {.za_name
= "filesystem", .za_lua_type
= LUA_TSTRING
},
196 zcp_synctask_rollback(lua_State
*state
, boolean_t sync
, nvlist_t
*err_details
)
199 const char *dsname
= lua_tostring(state
, 1);
200 dsl_dataset_rollback_arg_t ddra
= { 0 };
202 ddra
.ddra_fsname
= dsname
;
203 ddra
.ddra_result
= err_details
;
205 err
= zcp_sync_task(state
, dsl_dataset_rollback_check
,
206 dsl_dataset_rollback_sync
, &ddra
, sync
, dsname
);
212 zcp_synctask_wrapper_cleanup(void *arg
)
218 zcp_synctask_wrapper(lua_State
*state
)
222 nvlist_t
*err_details
= fnvlist_alloc();
225 * Make sure err_details is properly freed, even if a fatal error is
226 * thrown during the synctask.
228 zcp_register_cleanup(state
, &zcp_synctask_wrapper_cleanup
, err_details
);
230 zcp_synctask_info_t
*info
= lua_touserdata(state
, lua_upvalueindex(1));
231 boolean_t sync
= lua_toboolean(state
, lua_upvalueindex(2));
233 zcp_run_info_t
*ri
= zcp_run_info(state
);
234 dsl_pool_t
*dp
= ri
->zri_pool
;
236 /* MOS space is triple-dittoed, so we multiply by 3. */
237 uint64_t funcspace
= (info
->blocks_modified
<< DST_AVG_BLKSHIFT
) * 3;
239 zcp_parse_args(state
, info
->name
, info
->pargs
, info
->kwargs
);
242 if (info
->space_check
!= ZFS_SPACE_CHECK_NONE
&& funcspace
> 0) {
243 uint64_t quota
= dsl_pool_adjustedsize(dp
,
244 info
->space_check
== ZFS_SPACE_CHECK_RESERVED
) -
245 metaslab_class_get_deferred(spa_normal_class(dp
->dp_spa
));
246 uint64_t used
= dsl_dir_phys(dp
->dp_root_dir
)->dd_used_bytes
+
249 if (used
+ funcspace
> quota
) {
250 err
= SET_ERROR(ENOSPC
);
255 err
= info
->func(state
, sync
, err_details
);
259 ri
->zri_space_used
+= funcspace
;
262 lua_pushnumber(state
, (lua_Number
)err
);
263 if (fnvlist_num_pairs(err_details
) > 0) {
264 (void) zcp_nvlist_to_lua(state
, err_details
, NULL
, 0);
268 zcp_clear_cleanup(state
);
269 fnvlist_free(err_details
);
275 zcp_load_synctask_lib(lua_State
*state
, boolean_t sync
)
278 zcp_synctask_info_t
*zcp_synctask_funcs
[] = {
279 &zcp_synctask_destroy_info
,
280 &zcp_synctask_promote_info
,
281 &zcp_synctask_rollback_info
,
287 for (i
= 0; zcp_synctask_funcs
[i
] != NULL
; i
++) {
288 zcp_synctask_info_t
*info
= zcp_synctask_funcs
[i
];
289 lua_pushlightuserdata(state
, info
);
290 lua_pushboolean(state
, sync
);
291 lua_pushcclosure(state
, &zcp_synctask_wrapper
, 2);
292 lua_setfield(state
, -2, info
->name
);