mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-27 04:32:16 +03:00
OpenZFS 7431 - ZFS Channel Programs
Authored by: Chris Williamson <chris.williamson@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: John Kennedy <john.kennedy@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Approved by: Garrett D'Amore <garrett@damore.org> Ported-by: Don Brady <don.brady@delphix.com> Ported-by: John Kennedy <john.kennedy@delphix.com> OpenZFS-issue: https://www.illumos.org/issues/7431 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/dfc11533 Porting Notes: * The CLI long option arguments for '-t' and '-m' don't parse on linux * Switched from kmem_alloc to vmem_alloc in zcp_lua_alloc * Lua implementation is built as its own module (zlua.ko) * Lua headers consumed directly by zfs code moved to 'include/sys/lua/' * There is no native setjmp/longjump available in stock Linux kernel. Brought over implementations from illumos and FreeBSD * The get_temporary_prop() was adapted due to VFS platform differences * Use of inline functions in lua parser to reduce stack usage per C call * Skip some ZFS Test Suite ZCP tests on sparc64 to avoid stack overflow
This commit is contained in:
committed by
Brian Behlendorf
parent
8824a7f133
commit
d99a015343
+114
-82
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2013 by Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <sys/dsl_dataset.h>
|
||||
#include <sys/dsl_synctask.h>
|
||||
#include <sys/dsl_destroy.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
#include <sys/dsl_pool.h>
|
||||
#include <sys/dsl_dir.h>
|
||||
@@ -42,13 +43,7 @@
|
||||
#include <sys/dsl_deleg.h>
|
||||
#include <sys/dmu_impl.h>
|
||||
#include <sys/zvol.h>
|
||||
|
||||
typedef struct dmu_snapshots_destroy_arg {
|
||||
nvlist_t *dsda_snaps;
|
||||
nvlist_t *dsda_successful_snaps;
|
||||
boolean_t dsda_defer;
|
||||
nvlist_t *dsda_errlist;
|
||||
} dmu_snapshots_destroy_arg_t;
|
||||
#include <sys/zcp.h>
|
||||
|
||||
int
|
||||
dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
|
||||
@@ -86,51 +81,33 @@ dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dmu_snapshots_destroy_arg_t *dsda = arg;
|
||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||
nvpair_t *pair;
|
||||
int error = 0;
|
||||
dsl_destroy_snapshot_arg_t *ddsa = arg;
|
||||
const char *dsname = ddsa->ddsa_name;
|
||||
boolean_t defer = ddsa->ddsa_defer;
|
||||
|
||||
if (!dmu_tx_is_syncing(tx))
|
||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||
int error = 0;
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
|
||||
|
||||
/*
|
||||
* If the snapshot does not exist, silently ignore it, and
|
||||
* dsl_destroy_snapshot_sync() will be a no-op
|
||||
* (it's "already destroyed").
|
||||
*/
|
||||
if (error == ENOENT)
|
||||
return (0);
|
||||
|
||||
for (pair = nvlist_next_nvpair(dsda->dsda_snaps, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(dsda->dsda_snaps, pair)) {
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
error = dsl_dataset_hold(dp, nvpair_name(pair),
|
||||
FTAG, &ds);
|
||||
|
||||
/*
|
||||
* If the snapshot does not exist, silently ignore it
|
||||
* (it's "already destroyed").
|
||||
*/
|
||||
if (error == ENOENT)
|
||||
continue;
|
||||
|
||||
if (error == 0) {
|
||||
error = dsl_destroy_snapshot_check_impl(ds,
|
||||
dsda->dsda_defer);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
if (error == 0) {
|
||||
fnvlist_add_boolean(dsda->dsda_successful_snaps,
|
||||
nvpair_name(pair));
|
||||
} else {
|
||||
fnvlist_add_int32(dsda->dsda_errlist,
|
||||
nvpair_name(pair), error);
|
||||
}
|
||||
if (error == 0) {
|
||||
error = dsl_destroy_snapshot_check_impl(ds, defer);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
pair = nvlist_next_nvpair(dsda->dsda_errlist, NULL);
|
||||
if (pair != NULL)
|
||||
return (fnvpair_value_int32(pair));
|
||||
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
struct process_old_arg {
|
||||
@@ -480,24 +457,23 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
|
||||
dmu_object_free_zapified(mos, obj, tx);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dmu_snapshots_destroy_arg_t *dsda = arg;
|
||||
dsl_destroy_snapshot_arg_t *ddsa = arg;
|
||||
const char *dsname = ddsa->ddsa_name;
|
||||
boolean_t defer = ddsa->ddsa_defer;
|
||||
|
||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||
nvpair_t *pair;
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
for (pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, NULL);
|
||||
pair != NULL;
|
||||
pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, pair)) {
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
|
||||
|
||||
dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx);
|
||||
zvol_remove_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
int error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
|
||||
if (error == ENOENT)
|
||||
return;
|
||||
ASSERT0(error);
|
||||
dsl_destroy_snapshot_sync_impl(ds, defer, tx);
|
||||
zvol_remove_minors(dp->dp_spa, dsname, B_TRUE);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -517,26 +493,86 @@ int
|
||||
dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer,
|
||||
nvlist_t *errlist)
|
||||
{
|
||||
dmu_snapshots_destroy_arg_t dsda;
|
||||
int error;
|
||||
nvpair_t *pair;
|
||||
|
||||
pair = nvlist_next_nvpair(snaps, NULL);
|
||||
if (pair == NULL)
|
||||
if (nvlist_next_nvpair(snaps, NULL) == NULL)
|
||||
return (0);
|
||||
|
||||
dsda.dsda_snaps = snaps;
|
||||
VERIFY0(nvlist_alloc(&dsda.dsda_successful_snaps,
|
||||
NV_UNIQUE_NAME, KM_SLEEP));
|
||||
dsda.dsda_defer = defer;
|
||||
dsda.dsda_errlist = errlist;
|
||||
nvlist_t *arg = fnvlist_alloc();
|
||||
nvlist_t *snaps_normalized = fnvlist_alloc();
|
||||
/*
|
||||
* lzc_destroy_snaps() is documented to take an nvlist whose
|
||||
* values "don't matter". We need to convert that nvlist to one
|
||||
* that we know can be converted to LUA.
|
||||
*/
|
||||
for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) {
|
||||
fnvlist_add_boolean_value(snaps_normalized,
|
||||
nvpair_name(pair), B_TRUE);
|
||||
}
|
||||
fnvlist_add_nvlist(arg, "snaps", snaps_normalized);
|
||||
fnvlist_free(snaps_normalized);
|
||||
fnvlist_add_boolean_value(arg, "defer", defer);
|
||||
|
||||
error = dsl_sync_task(nvpair_name(pair),
|
||||
dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync,
|
||||
&dsda, 0, ZFS_SPACE_CHECK_NONE);
|
||||
fnvlist_free(dsda.dsda_successful_snaps);
|
||||
nvlist_t *wrapper = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg);
|
||||
fnvlist_free(arg);
|
||||
|
||||
return (error);
|
||||
const char *program =
|
||||
"arg = ...\n"
|
||||
"snaps = arg['snaps']\n"
|
||||
"defer = arg['defer']\n"
|
||||
"errors = { }\n"
|
||||
"has_errors = false\n"
|
||||
"for snap, v in pairs(snaps) do\n"
|
||||
" errno = zfs.check.destroy{snap, defer=defer}\n"
|
||||
" zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n"
|
||||
" if errno == ENOENT then\n"
|
||||
" snaps[snap] = nil\n"
|
||||
" elseif errno ~= 0 then\n"
|
||||
" errors[snap] = errno\n"
|
||||
" has_errors = true\n"
|
||||
" end\n"
|
||||
"end\n"
|
||||
"if has_errors then\n"
|
||||
" return errors\n"
|
||||
"end\n"
|
||||
"for snap, v in pairs(snaps) do\n"
|
||||
" errno = zfs.sync.destroy{snap, defer=defer}\n"
|
||||
" assert(errno == 0)\n"
|
||||
"end\n"
|
||||
"return { }\n";
|
||||
|
||||
nvlist_t *result = fnvlist_alloc();
|
||||
int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)),
|
||||
program,
|
||||
0,
|
||||
zfs_lua_max_memlimit,
|
||||
fnvlist_lookup_nvpair(wrapper, ZCP_ARG_ARGLIST), result);
|
||||
if (error != 0) {
|
||||
char *errorstr = NULL;
|
||||
(void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr);
|
||||
if (errorstr != NULL) {
|
||||
zfs_dbgmsg(errorstr);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
fnvlist_free(wrapper);
|
||||
|
||||
/*
|
||||
* lzc_destroy_snaps() is documented to fill the errlist with
|
||||
* int32 values, so we need to covert the int64 values that are
|
||||
* returned from LUA.
|
||||
*/
|
||||
int rv = 0;
|
||||
nvlist_t *errlist_raw = fnvlist_lookup_nvlist(result, ZCP_RET_RETURN);
|
||||
for (nvpair_t *pair = nvlist_next_nvpair(errlist_raw, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(errlist_raw, pair)) {
|
||||
int32_t val = (int32_t)fnvpair_value_int64(pair);
|
||||
if (rv == 0)
|
||||
rv = val;
|
||||
fnvlist_add_int32(errlist, nvpair_name(pair), val);
|
||||
}
|
||||
fnvlist_free(result);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -607,10 +643,6 @@ old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
dsl_dataset_phys(ds)->ds_unique_bytes == 0);
|
||||
}
|
||||
|
||||
typedef struct dsl_destroy_head_arg {
|
||||
const char *ddha_name;
|
||||
} dsl_destroy_head_arg_t;
|
||||
|
||||
int
|
||||
dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds)
|
||||
{
|
||||
@@ -656,7 +688,7 @@ dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
dsl_destroy_head_check(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_destroy_head_arg_t *ddha = arg;
|
||||
@@ -894,7 +926,7 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
dsl_destroy_head_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_destroy_head_arg_t *ddha = arg;
|
||||
|
||||
Reference in New Issue
Block a user