mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
OpenZFS 8600 - ZFS channel programs - snapshot
Authored by: Chris Williamson <chris.williamson@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: John Kennedy <john.kennedy@delphix.com> Reviewed by: Brad Lewis <brad.lewis@delphix.com> Approved by: Robert Mustacchi <rm@joyent.com> Ported-by: Don Brady <don.brady@delphix.com> ZFS channel programs should be able to create snapshots. In addition to the base snapshot functionality, this entails extra logic to handle edge cases which were formerly not possible, such as creating then destroying a snapshot in the same transaction sync. OpenZFS-issue: https://www.illumos.org/issues/8600 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/68089b8b
This commit is contained in:
committed by
Brian Behlendorf
parent
af07368986
commit
234c91c508
@@ -1140,13 +1140,6 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct dsl_dataset_snapshot_arg {
|
||||
nvlist_t *ddsa_snaps;
|
||||
nvlist_t *ddsa_props;
|
||||
nvlist_t *ddsa_errors;
|
||||
cred_t *ddsa_cr;
|
||||
} dsl_dataset_snapshot_arg_t;
|
||||
|
||||
int
|
||||
dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
|
||||
dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr)
|
||||
@@ -1206,7 +1199,7 @@ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_snapshot_arg_t *ddsa = arg;
|
||||
@@ -1486,7 +1479,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
|
||||
spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_snapshot_arg_t *ddsa = arg;
|
||||
|
||||
+6
-3
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -106,10 +106,15 @@
|
||||
#define KM_NORMALPRI 0
|
||||
#endif
|
||||
|
||||
#define ZCP_NVLIST_MAX_DEPTH 20
|
||||
|
||||
uint64_t zfs_lua_check_instrlimit_interval = 100;
|
||||
uint64_t zfs_lua_max_instrlimit = ZCP_MAX_INSTRLIMIT;
|
||||
uint64_t zfs_lua_max_memlimit = ZCP_MAX_MEMLIMIT;
|
||||
|
||||
/*
|
||||
* Forward declarations for mutually recursive functions
|
||||
*/
|
||||
static int zcp_nvpair_value_to_lua(lua_State *, nvpair_t *, char *, int);
|
||||
static int zcp_lua_to_nvlist_impl(lua_State *, int, nvlist_t *, const char *,
|
||||
int);
|
||||
@@ -217,8 +222,6 @@ zcp_cleanup(lua_State *state)
|
||||
}
|
||||
}
|
||||
|
||||
#define ZCP_NVLIST_MAX_DEPTH 20
|
||||
|
||||
/*
|
||||
* Convert the lua table at the given index on the Lua stack to an nvlist
|
||||
* and return it.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zcp_global.h>
|
||||
@@ -62,7 +62,12 @@ static const zcp_errno_global_t errno_globals[] = {
|
||||
{"EPIPE", EPIPE},
|
||||
{"EDOM", EDOM},
|
||||
{"ERANGE", ERANGE},
|
||||
{"EDEADLK", EDEADLK},
|
||||
{"ENOLCK", ENOLCK},
|
||||
{"ECANCELED", ECANCELED},
|
||||
{"ENOTSUP", ENOTSUP},
|
||||
{"EDQUOT", EDQUOT},
|
||||
{"ENAMETOOLONG", ENAMETOOLONG},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ typedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *);
|
||||
typedef struct zcp_synctask_info {
|
||||
const char *name;
|
||||
zcp_synctask_func_t *func;
|
||||
zfs_space_check_t space_check;
|
||||
int blocks_modified;
|
||||
const zcp_arg_t pargs[4];
|
||||
const zcp_arg_t kwargs[2];
|
||||
zfs_space_check_t space_check;
|
||||
int blocks_modified;
|
||||
} zcp_synctask_info_t;
|
||||
|
||||
/*
|
||||
@@ -91,8 +91,6 @@ static int zcp_synctask_destroy(lua_State *, boolean_t, nvlist_t *);
|
||||
static zcp_synctask_info_t zcp_synctask_destroy_info = {
|
||||
.name = "destroy",
|
||||
.func = zcp_synctask_destroy,
|
||||
.space_check = ZFS_SPACE_CHECK_NONE,
|
||||
.blocks_modified = 0,
|
||||
.pargs = {
|
||||
{.za_name = "filesystem | snapshot", .za_lua_type = LUA_TSTRING},
|
||||
{NULL, 0}
|
||||
@@ -100,7 +98,9 @@ static zcp_synctask_info_t zcp_synctask_destroy_info = {
|
||||
.kwargs = {
|
||||
{.za_name = "defer", .za_lua_type = LUA_TBOOLEAN},
|
||||
{NULL, 0}
|
||||
}
|
||||
},
|
||||
.space_check = ZFS_SPACE_CHECK_NONE,
|
||||
.blocks_modified = 0
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
@@ -140,19 +140,19 @@ zcp_synctask_destroy(lua_State *state, boolean_t sync, nvlist_t *err_details)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *err_details);
|
||||
static int zcp_synctask_promote(lua_State *, boolean_t, nvlist_t *);
|
||||
static zcp_synctask_info_t zcp_synctask_promote_info = {
|
||||
.name = "promote",
|
||||
.func = zcp_synctask_promote,
|
||||
.space_check = ZFS_SPACE_CHECK_RESERVED,
|
||||
.blocks_modified = 3,
|
||||
.pargs = {
|
||||
{.za_name = "clone", .za_lua_type = LUA_TSTRING},
|
||||
{NULL, 0}
|
||||
},
|
||||
.kwargs = {
|
||||
{NULL, 0}
|
||||
}
|
||||
},
|
||||
.space_check = ZFS_SPACE_CHECK_RESERVED,
|
||||
.blocks_modified = 3
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -208,6 +208,58 @@ zcp_synctask_rollback(lua_State *state, boolean_t sync, nvlist_t *err_details)
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int zcp_synctask_snapshot(lua_State *, boolean_t, nvlist_t *);
|
||||
static zcp_synctask_info_t zcp_synctask_snapshot_info = {
|
||||
.name = "snapshot",
|
||||
.func = zcp_synctask_snapshot,
|
||||
.pargs = {
|
||||
{.za_name = "filesystem@snapname | volume@snapname",
|
||||
.za_lua_type = LUA_TSTRING},
|
||||
{NULL, 0}
|
||||
},
|
||||
.kwargs = {
|
||||
{NULL, 0}
|
||||
},
|
||||
.space_check = ZFS_SPACE_CHECK_NORMAL,
|
||||
.blocks_modified = 3
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
err = zcp_sync_task(state, dsl_dataset_snapshot_check,
|
||||
dsl_dataset_snapshot_sync, &ddsa, sync, dsname);
|
||||
|
||||
fnvlist_free(ddsa.ddsa_snaps);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
void
|
||||
zcp_synctask_wrapper_cleanup(void *arg)
|
||||
{
|
||||
@@ -279,6 +331,7 @@ zcp_load_synctask_lib(lua_State *state, boolean_t sync)
|
||||
&zcp_synctask_destroy_info,
|
||||
&zcp_synctask_promote_info,
|
||||
&zcp_synctask_rollback_info,
|
||||
&zcp_synctask_snapshot_info,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -3695,7 +3695,7 @@ zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl,
|
||||
|
||||
if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
|
||||
return (EINVAL);
|
||||
if (memlimit == 0 || memlimit > ZCP_MAX_MEMLIMIT)
|
||||
if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
|
||||
return (EINVAL);
|
||||
|
||||
return (zcp_eval(poolname, program, instrlimit, memlimit,
|
||||
|
||||
Reference in New Issue
Block a user