Example #1
0
static int
zcp_clones_iter(lua_State *state)
{
	int err;
	char clonename[ZFS_MAX_DATASET_NAME_LEN];
	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	dsl_dataset_t *ds, *clone;
	zap_attribute_t za;
	zap_cursor_t zc;

	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
	if (err == ENOENT) {
		return (0);
	} else if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
		    err));
	}

	if (dsl_dataset_phys(ds)->ds_next_clones_obj == 0) {
		dsl_dataset_rele(ds, FTAG);
		return (0);
	}

	zap_cursor_init_serialized(&zc, dp->dp_meta_objset,
	    dsl_dataset_phys(ds)->ds_next_clones_obj, cursor);
	dsl_dataset_rele(ds, FTAG);

	err = zap_cursor_retrieve(&zc, &za);
	if (err != 0) {
		zap_cursor_fini(&zc);
		if (err != ENOENT) {
			return (luaL_error(state,
			    "unexpected error %d from zap_cursor_retrieve()",
			    err));
		}
		return (0);
	}
	zap_cursor_advance(&zc);
	cursor = zap_cursor_serialize(&zc);
	zap_cursor_fini(&zc);

	err = dsl_dataset_hold_obj(dp, za.za_first_integer, FTAG, &clone);
	if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from "
		    "dsl_dataset_hold_obj(za_first_integer)", err));
	}

	dsl_dir_name(clone->ds_dir, clonename);
	dsl_dataset_rele(clone, FTAG);

	lua_pushnumber(state, cursor);
	lua_replace(state, lua_upvalueindex(2));

	(void) lua_pushstring(state, clonename);
	return (1);
}
Example #2
0
/*
 * Generic synctask interface for channel program syncfuncs.
 *
 * To perform some action in syncing context, we'd generally call
 * dsl_sync_task(), but since the Lua script is already running inside a
 * synctask we need to leave out some actions (such as acquiring the config
 * rwlock and performing space checks).
 *
 * If 'sync' is false, executes a dry run and returns the error code.
 *
 * If we are not running in syncing context and we are not doing a dry run
 * (meaning we are running a zfs.sync function in open-context) then we
 * return a Lua error.
 *
 * This function also handles common fatal error cases for channel program
 * library functions. If a fatal error occurs, err_dsname will be the dataset
 * name reported in error messages, if supplied.
 */
static int
zcp_sync_task(lua_State *state, dsl_checkfunc_t *checkfunc,
    dsl_syncfunc_t *syncfunc, void *arg, boolean_t sync, const char *err_dsname)
{
	int err;
	zcp_run_info_t *ri = zcp_run_info(state);

	err = checkfunc(arg, ri->zri_tx);
	if (!sync)
		return (err);

	if (!ri->zri_sync) {
		return (luaL_error(state, "running functions from the zfs.sync "
		    "submodule requires passing sync=TRUE to "
		    "lzc_channel_program() (i.e. do not specify the \"-n\" "
		    "command line argument)"));
	}

	if (err == 0) {
		syncfunc(arg, ri->zri_tx);
	} else if (err == EIO) {
		if (err_dsname != NULL) {
			return (luaL_error(state,
			    "I/O error while accessing dataset '%s'",
			    err_dsname));
		} else {
			return (luaL_error(state,
			    "I/O error while accessing dataset."));
		}
	}

	return (err);
}
Example #3
0
static int
zcp_exists(lua_State *state)
{
	zcp_run_info_t *ri = zcp_run_info(state);
	dsl_pool_t *dp = ri->zri_pool;
	zcp_lib_info_t *libinfo = &zcp_exists_info;

	zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs);

	const char *dsname = lua_tostring(state, 1);

	dsl_dataset_t *ds;
	int error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
	if (error == 0) {
		dsl_dataset_rele(ds, FTAG);
		lua_pushboolean(state, B_TRUE);
	} else if (error == ENOENT) {
		lua_pushboolean(state, B_FALSE);
	} else if (error == EXDEV) {
		return (luaL_error(state, "dataset '%s' is not in the "
		    "target pool", dsname));
	} else if (error == EIO) {
		return (luaL_error(state, "I/O error opening dataset '%s'",
		    dsname));
	} else if (error != 0) {
		return (luaL_error(state, "unexpected error %d", error));
	}

	return (1);
}
Example #4
0
/*
 * Get a list of all visble properties and their values for a given dataset.
 * Returned on the stack as a Lua table.
 */
static int
zcp_system_props_list(lua_State *state)
{
	int error;
	char errbuf[128];
	const char *dataset_name;
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	zcp_list_info_t *libinfo = &zcp_system_props_list_info;
	zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs);
	dataset_name = lua_tostring(state, 1);
	nvlist_t *nv = fnvlist_alloc();

	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dataset_name, FTAG);
	if (ds == NULL)
		return (1); /* not reached; zcp_dataset_hold() longjmp'd */

	/* Get the names of all valid properties for this dataset */
	zcp_dataset_props(ds, nv);
	dsl_dataset_rele(ds, FTAG);

	/* push list as lua table */
	error = zcp_nvlist_to_lua(state, nv, errbuf, sizeof (errbuf));
	nvlist_free(nv);
	if (error != 0) {
		return (luaL_error(state,
		    "Error returning nvlist: %s", errbuf));
	}
	return (1);
}
Example #5
0
static int
zcp_props_list(lua_State *state)
{
	const char *dsname = lua_tostring(state, 1);
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	objset_t *os;
	nvlist_t **props = lua_newuserdata(state, sizeof (nvlist_t *));

	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dsname, FTAG);
	if (ds == NULL)
		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
	VERIFY0(dmu_objset_from_ds(ds, &os));
	VERIFY0(dsl_prop_get_all(os, props));
	dsl_dataset_rele(ds, FTAG);

	/*
	 * Set the metatable for the properties list to free it on completion.
	 */
	luaL_getmetatable(state, zcp_props_list_info.name);
	(void) lua_setmetatable(state, -2);

	lua_pushlightuserdata(state, NULL);
	lua_pushcclosure(state, &zcp_props_iter, 2);
	return (1);
}
Example #6
0
static int
zcp_children_list(lua_State *state)
{
	const char *fsname = lua_tostring(state, 1);
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	boolean_t issnap;
	uint64_t dsobj;

	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, fsname, FTAG);
	if (ds == NULL)
		return (1); /* not reached; zcp_dataset_hold() longjmp'd */

	issnap = ds->ds_is_snapshot;
	dsobj = ds->ds_object;
	dsl_dataset_rele(ds, FTAG);

	if (issnap) {
		return (zcp_argerror(state, 1,
		    "argument %s cannot be a snapshot", fsname));
	}

	lua_pushnumber(state, dsobj);
	lua_pushnumber(state, 0);
	lua_pushcclosure(state, &zcp_children_iter, 2);
	return (1);
}
Example #7
0
static int
zcp_clones_list(lua_State *state)
{
	const char *snapname = lua_tostring(state, 1);
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	boolean_t issnap;
	uint64_t dsobj, cursor;

	/*
	 * zcp_dataset_hold will either successfully return the requested
	 * dataset or throw a lua error and longjmp out of the zfs.list.clones
	 * call without returning.
	 */
	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, snapname, FTAG);
	if (ds == NULL)
		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
	cursor = 0;
	issnap = ds->ds_is_snapshot;
	dsobj = ds->ds_object;
	dsl_dataset_rele(ds, FTAG);

	if (!issnap) {
		return (zcp_argerror(state, 1, "%s is not a snapshot",
		    snapname));
	}

	lua_pushnumber(state, dsobj);
	lua_pushnumber(state, cursor);
	lua_pushcclosure(state, &zcp_clones_iter, 2);
	return (1);
}
Example #8
0
void
zcp_clear_cleanup(lua_State *state)
{
	zcp_run_info_t *ri = zcp_run_info(state);

	ri->zri_cleanup = NULL;
	ri->zri_cleanup_arg = NULL;
}
Example #9
0
static int
zcp_synctask_wrapper(lua_State *state)
{
	int err;
	zcp_cleanup_handler_t *zch;
	int num_ret = 1;
	nvlist_t *err_details = fnvlist_alloc();

	/*
	 * Make sure err_details is properly freed, even if a fatal error is
	 * thrown during the synctask.
	 */
	zch = zcp_register_cleanup(state,
	    (zcp_cleanup_t *)&fnvlist_free, err_details);

	zcp_synctask_info_t *info = lua_touserdata(state, lua_upvalueindex(1));
	boolean_t sync = lua_toboolean(state, lua_upvalueindex(2));

	zcp_run_info_t *ri = zcp_run_info(state);
	dsl_pool_t *dp = ri->zri_pool;

	/* MOS space is triple-dittoed, so we multiply by 3. */
	uint64_t funcspace = (info->blocks_modified << DST_AVG_BLKSHIFT) * 3;

	zcp_parse_args(state, info->name, info->pargs, info->kwargs);

	err = 0;
	if (info->space_check != ZFS_SPACE_CHECK_NONE && funcspace > 0) {
		uint64_t quota = dsl_pool_adjustedsize(dp,
		    info->space_check == ZFS_SPACE_CHECK_RESERVED) -
		    metaslab_class_get_deferred(spa_normal_class(dp->dp_spa));
		uint64_t used = dsl_dir_phys(dp->dp_root_dir)->dd_used_bytes +
		    ri->zri_space_used;

		if (used + funcspace > quota) {
			err = SET_ERROR(ENOSPC);
		}
	}

	if (err == 0) {
		err = info->func(state, sync, err_details);
	}

	if (err == 0) {
		ri->zri_space_used += funcspace;
	}

	lua_pushnumber(state, (lua_Number)err);
	if (fnvlist_num_pairs(err_details) > 0) {
		(void) zcp_nvlist_to_lua(state, err_details, NULL, 0);
		num_ret++;
	}

	zcp_deregister_cleanup(state, zch);
	fnvlist_free(err_details);

	return (num_ret);
}
Example #10
0
/*
 * If it exists, execute the currently set cleanup function then unregister it.
 */
void
zcp_cleanup(lua_State *state)
{
	zcp_run_info_t *ri = zcp_run_info(state);

	if (ri->zri_cleanup != NULL) {
		ri->zri_cleanup(ri->zri_cleanup_arg);
		zcp_clear_cleanup(state);
	}
}
Example #11
0
/*
 * Install a new cleanup function, which will be invoked with the given
 * opaque argument if a fatal error causes the Lua interpreter to longjump out
 * of a function call.
 *
 * If an error occurs, the cleanup function will be invoked exactly once and
 * then unreigstered.
 */
void
zcp_register_cleanup(lua_State *state, zcp_cleanup_t cleanfunc, void *cleanarg)
{
	zcp_run_info_t *ri = zcp_run_info(state);
	/*
	 * A cleanup function should always be explicitly removed before
	 * installing a new one to avoid accidental clobbering.
	 */
	ASSERT3P(ri->zri_cleanup, ==, NULL);

	ri->zri_cleanup = cleanfunc;
	ri->zri_cleanup_arg = cleanarg;
}
Example #12
0
static int
zcp_debug(lua_State *state)
{
	const char *dbgstring;
	zcp_run_info_t *ri = zcp_run_info(state);
	zcp_lib_info_t *libinfo = &zcp_debug_info;

	zcp_parse_args(state, libinfo->name, libinfo->pargs, libinfo->kwargs);

	dbgstring = lua_tostring(state, 1);

	zfs_dbgmsg("txg %lld ZCP: %s", ri->zri_tx->tx_txg, dbgstring);

	return (0);
}
Example #13
0
static int
zcp_children_iter(lua_State *state)
{
	int err;
	char childname[ZFS_MAX_DATASET_NAME_LEN];
	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
	zcp_run_info_t *ri = zcp_run_info(state);
	dsl_pool_t *dp = ri->zri_pool;
	dsl_dataset_t *ds;
	objset_t *os;
	char *p;

	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
	if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
		    err));
	}

	dsl_dataset_name(ds, childname);
	VERIFY3U(sizeof (childname), >,
	    strlcat(childname, "/", sizeof (childname)));
	p = strchr(childname, '\0');

	VERIFY0(dmu_objset_from_ds(ds, &os));
	do {
		err = dmu_dir_list_next(os,
		    sizeof (childname) - (p - childname), p, NULL, &cursor);
	} while (err == 0 && dataset_name_hidden(childname));
	dsl_dataset_rele(ds, FTAG);

	if (err == ENOENT) {
		return (0);
	} else if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from dmu_dir_list_next()",
		    err));
	}

	lua_pushnumber(state, cursor);
	lua_replace(state, lua_upvalueindex(2));

	(void) lua_pushstring(state, childname);
	return (1);
}
Example #14
0
static int
zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
{
	int err;
	dsl_dataset_promote_arg_t ddpa = { 0 };
	const char *dsname = lua_tostring(state, 1);
	zcp_run_info_t *ri = zcp_run_info(state);

	ddpa.ddpa_clonename = dsname;
	ddpa.err_ds = err_details;
	ddpa.cr = ri->zri_cred;

	/*
	 * If there was a snapshot name conflict, then err_ds will be filled
	 * with a list of conflicting snapshot names.
	 */
	err = zcp_sync_task(state, dsl_dataset_promote_check,
	    dsl_dataset_promote_sync, &ddpa, sync, dsname);

	return (err);
}
Example #15
0
/* ARGSUSED */
static int
zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
{
	int err;
	dsl_dataset_snapshot_arg_t ddsa = { 0 };
	const char *dsname = lua_tostring(state, 1);
	zcp_run_info_t *ri = zcp_run_info(state);

	/*
	 * On old pools, the ZIL must not be active when a snapshot is created,
	 * but we can't suspend the ZIL because we're already in syncing
	 * context.
	 */
	if (spa_version(ri->zri_pool->dp_spa) < SPA_VERSION_FAST_SNAP) {
		return (ENOTSUP);
	}

	/*
	 * We only allow for a single snapshot rather than a list, so the
	 * error list output is unnecessary.
	 */
	ddsa.ddsa_errors = NULL;
	ddsa.ddsa_props = NULL;
	ddsa.ddsa_cr = ri->zri_cred;
	ddsa.ddsa_snaps = fnvlist_alloc();
	fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);

	zcp_cleanup_handler_t *zch = zcp_register_cleanup(state,
	    (zcp_cleanup_t *)&fnvlist_free, ddsa.ddsa_snaps);

	err = zcp_sync_task(state, dsl_dataset_snapshot_check,
	    dsl_dataset_snapshot_sync, &ddsa, sync, dsname);

	zcp_deregister_cleanup(state, zch);
	fnvlist_free(ddsa.ddsa_snaps);

	return (err);
}