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