mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +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
@@ -2479,6 +2479,73 @@ zfs_get_clones_nvl(zfs_handle_t *zhp)
|
||||
return (value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a property and value and checks that the value
|
||||
* matches the one found by the channel program. If they are
|
||||
* not equal, print both of them.
|
||||
*/
|
||||
static void
|
||||
zcp_check(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t intval,
|
||||
const char *strval)
|
||||
{
|
||||
if (!zhp->zfs_hdl->libzfs_prop_debug)
|
||||
return;
|
||||
int error;
|
||||
char *poolname = zhp->zpool_hdl->zpool_name;
|
||||
const char *prop_name = zfs_prop_to_name(prop);
|
||||
const char *program =
|
||||
"args = ...\n"
|
||||
"ds = args['dataset']\n"
|
||||
"prop = args['property']\n"
|
||||
"value, setpoint = zfs.get_prop(ds, prop)\n"
|
||||
"return {value=value, setpoint=setpoint}\n";
|
||||
nvlist_t *outnvl;
|
||||
nvlist_t *retnvl;
|
||||
nvlist_t *argnvl = fnvlist_alloc();
|
||||
|
||||
fnvlist_add_string(argnvl, "dataset", zhp->zfs_name);
|
||||
fnvlist_add_string(argnvl, "property", zfs_prop_to_name(prop));
|
||||
|
||||
error = lzc_channel_program(poolname, program,
|
||||
10 * 1000 * 1000, 10 * 1024 * 1024, argnvl, &outnvl);
|
||||
|
||||
if (error == 0) {
|
||||
retnvl = fnvlist_lookup_nvlist(outnvl, "return");
|
||||
if (zfs_prop_get_type(prop) == PROP_TYPE_NUMBER) {
|
||||
int64_t ans;
|
||||
error = nvlist_lookup_int64(retnvl, "value", &ans);
|
||||
if (error != 0) {
|
||||
(void) fprintf(stderr, "%s: zcp check error: "
|
||||
"%u\n", prop_name, error);
|
||||
return;
|
||||
}
|
||||
if (ans != intval) {
|
||||
(void) fprintf(stderr, "%s: zfs found %llu, "
|
||||
"but zcp found %llu\n", prop_name,
|
||||
(u_longlong_t)intval, (u_longlong_t)ans);
|
||||
}
|
||||
} else {
|
||||
char *str_ans;
|
||||
error = nvlist_lookup_string(retnvl, "value", &str_ans);
|
||||
if (error != 0) {
|
||||
(void) fprintf(stderr, "%s: zcp check error: "
|
||||
"%u\n", prop_name, error);
|
||||
return;
|
||||
}
|
||||
if (strcmp(strval, str_ans) != 0) {
|
||||
(void) fprintf(stderr,
|
||||
"%s: zfs found '%s', but zcp found '%s'\n",
|
||||
prop_name, strval, str_ans);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(void) fprintf(stderr, "%s: zcp check failed, channel program "
|
||||
"error: %u\n", prop_name, error);
|
||||
}
|
||||
nvlist_free(argnvl);
|
||||
nvlist_free(outnvl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve a property from the given object. If 'literal' is specified, then
|
||||
* numbers are left as exact values. Otherwise, numbers are converted to a
|
||||
@@ -2526,6 +2593,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
(void) snprintf(propbuf, proplen, "%llu",
|
||||
(u_longlong_t)val);
|
||||
}
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_MOUNTPOINT:
|
||||
@@ -2594,7 +2662,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
/* 'legacy' or 'none' */
|
||||
(void) strlcpy(propbuf, str, proplen);
|
||||
}
|
||||
|
||||
zcp_check(zhp, prop, 0, propbuf);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_ORIGIN:
|
||||
@@ -2602,6 +2670,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
(void) strlcpy(propbuf, str, proplen);
|
||||
zcp_check(zhp, prop, 0, str);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_CLONES:
|
||||
@@ -2616,7 +2685,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
|
||||
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* If quota or reservation is 0, we translate this into 'none'
|
||||
* (unless literal is set), and indicate that it's the default
|
||||
@@ -2635,6 +2703,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
else
|
||||
zfs_nicebytes(val, propbuf, proplen);
|
||||
}
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_FILESYSTEM_LIMIT:
|
||||
@@ -2659,6 +2728,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
} else {
|
||||
zfs_nicenum(val, propbuf, proplen);
|
||||
}
|
||||
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_REFRATIO:
|
||||
@@ -2673,6 +2744,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
(void) snprintf(propbuf, proplen, "%llu.%02llux",
|
||||
(u_longlong_t)(val / 100),
|
||||
(u_longlong_t)(val % 100));
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_TYPE:
|
||||
@@ -2693,6 +2765,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
abort();
|
||||
}
|
||||
(void) snprintf(propbuf, proplen, "%s", str);
|
||||
zcp_check(zhp, prop, 0, propbuf);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_MOUNTED:
|
||||
@@ -2718,6 +2791,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
* consumers.
|
||||
*/
|
||||
(void) strlcpy(propbuf, zhp->zfs_name, proplen);
|
||||
zcp_check(zhp, prop, 0, propbuf);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_MLSLABEL:
|
||||
@@ -2773,6 +2847,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||
return (-1);
|
||||
(void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_REFERENCED:
|
||||
@@ -2784,31 +2859,39 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
case ZFS_PROP_USEDCHILD:
|
||||
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||
return (-1);
|
||||
if (literal)
|
||||
if (literal) {
|
||||
(void) snprintf(propbuf, proplen, "%llu",
|
||||
(u_longlong_t)val);
|
||||
else
|
||||
} else {
|
||||
zfs_nicebytes(val, propbuf, proplen);
|
||||
}
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (zfs_prop_get_type(prop)) {
|
||||
case PROP_TYPE_NUMBER:
|
||||
if (get_numeric_property(zhp, prop, src,
|
||||
&source, &val) != 0)
|
||||
&source, &val) != 0) {
|
||||
return (-1);
|
||||
if (literal)
|
||||
}
|
||||
|
||||
if (literal) {
|
||||
(void) snprintf(propbuf, proplen, "%llu",
|
||||
(u_longlong_t)val);
|
||||
else
|
||||
} else {
|
||||
zfs_nicenum(val, propbuf, proplen);
|
||||
}
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case PROP_TYPE_STRING:
|
||||
str = getprop_string(zhp, prop, &source);
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) strlcpy(propbuf, str, proplen);
|
||||
zcp_check(zhp, prop, 0, str);
|
||||
break;
|
||||
|
||||
case PROP_TYPE_INDEX:
|
||||
@@ -2817,7 +2900,9 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
return (-1);
|
||||
if (zfs_prop_index_to_string(prop, val, &strval) != 0)
|
||||
return (-1);
|
||||
|
||||
(void) strlcpy(propbuf, strval, proplen);
|
||||
zcp_check(zhp, prop, 0, strval);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1053,6 +1053,10 @@ libzfs_init(void)
|
||||
libzfs_mnttab_init(hdl);
|
||||
fletcher_4_init();
|
||||
|
||||
if (getenv("ZFS_PROP_DEBUG") != NULL) {
|
||||
hdl->libzfs_prop_debug = B_TRUE;
|
||||
}
|
||||
|
||||
return (hdl);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ USER_C = \
|
||||
nodist_libzfs_core_la_SOURCES = $(USER_C)
|
||||
|
||||
libzfs_core_la_LIBADD = \
|
||||
$(top_builddir)/lib/libnvpair/libnvpair.la
|
||||
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||
$(top_builddir)/lib/libuutil/libuutil.la
|
||||
|
||||
libzfs_core_la_LDFLAGS = -version-info 1:0:0
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
* Copyright (c) 2017 Datto Inc.
|
||||
* Copyright 2017 RackTop Systems.
|
||||
@@ -156,7 +156,15 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
|
||||
}
|
||||
|
||||
while (ioctl(g_fd, ioc, &zc) != 0) {
|
||||
if (errno == ENOMEM && resultp != NULL) {
|
||||
/*
|
||||
* If ioctl exited with ENOMEM, we retry the ioctl after
|
||||
* increasing the size of the destination nvlist.
|
||||
*
|
||||
* Channel programs that exit with ENOMEM probably ran over the
|
||||
* lua memory sandbox; they should not be retried.
|
||||
*/
|
||||
if (errno == ENOMEM && resultp != NULL &&
|
||||
ioc != ZFS_IOC_CHANNEL_PROGRAM) {
|
||||
free((void *)(uintptr_t)zc.zc_nvlist_dst);
|
||||
zc.zc_nvlist_dst_size *= 2;
|
||||
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
@@ -1050,6 +1058,57 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes a channel program.
|
||||
*
|
||||
* If this function returns 0 the channel program was successfully loaded and
|
||||
* ran without failing. Note that individual commands the channel program ran
|
||||
* may have failed and the channel program is responsible for reporting such
|
||||
* errors through outnvl if they are important.
|
||||
*
|
||||
* This method may also return:
|
||||
*
|
||||
* EINVAL The program contains syntax errors, or an invalid memory or time
|
||||
* limit was given. No part of the channel program was executed.
|
||||
* If caused by syntax errors, 'outnvl' contains information about the
|
||||
* errors.
|
||||
*
|
||||
* ECHRNG The program was executed, but encountered a runtime error, such as
|
||||
* calling a function with incorrect arguments, invoking the error()
|
||||
* function directly, failing an assert() command, etc. Some portion
|
||||
* of the channel program may have executed and committed changes.
|
||||
* Information about the failure can be found in 'outnvl'.
|
||||
*
|
||||
* ENOMEM The program fully executed, but the output buffer was not large
|
||||
* enough to store the returned value. No output is returned through
|
||||
* 'outnvl'.
|
||||
*
|
||||
* ENOSPC The program was terminated because it exceeded its memory usage
|
||||
* limit. Some portion of the channel program may have executed and
|
||||
* committed changes to disk. No output is returned through 'outnvl'.
|
||||
*
|
||||
* ETIME The program was terminated because it exceeded its Lua instruction
|
||||
* limit. Some portion of the channel program may have executed and
|
||||
* committed changes to disk. No output is returned through 'outnvl'.
|
||||
*/
|
||||
int
|
||||
lzc_channel_program(const char *pool, const char *program, uint64_t instrlimit,
|
||||
uint64_t memlimit, nvlist_t *argnvl, nvlist_t **outnvl)
|
||||
{
|
||||
int error;
|
||||
nvlist_t *args;
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_string(args, ZCP_ARG_PROGRAM, program);
|
||||
fnvlist_add_nvlist(args, ZCP_ARG_ARGLIST, argnvl);
|
||||
fnvlist_add_uint64(args, ZCP_ARG_INSTRLIMIT, instrlimit);
|
||||
fnvlist_add_uint64(args, ZCP_ARG_MEMLIMIT, memlimit);
|
||||
error = lzc_ioctl(ZFS_IOC_CHANNEL_PROGRAM, pool, args, outnvl);
|
||||
fnvlist_free(args);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs key management functions
|
||||
*
|
||||
@@ -1110,6 +1169,7 @@ lzc_change_key(const char *fsname, uint64_t crypt_cmd, nvlist_t *props,
|
||||
error = lzc_ioctl(ZFS_IOC_CHANGE_KEY, fsname, ioc_args, NULL);
|
||||
nvlist_free(hidden_args);
|
||||
nvlist_free(ioc_args);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ include $(top_srcdir)/config/Rules.am
|
||||
VPATH = \
|
||||
$(top_srcdir)/module/zfs \
|
||||
$(top_srcdir)/module/zcommon \
|
||||
$(top_srcdir)/module/lua \
|
||||
$(top_srcdir)/lib/libzpool
|
||||
|
||||
# Suppress unused but set variable warnings often due to ASSERTs
|
||||
@@ -121,6 +122,11 @@ KERNEL_C = \
|
||||
zap.c \
|
||||
zap_leaf.c \
|
||||
zap_micro.c \
|
||||
zcp.c \
|
||||
zcp_get.c \
|
||||
zcp_global.c \
|
||||
zcp_iter.c \
|
||||
zcp_synctask.c \
|
||||
zfeature.c \
|
||||
zfs_byteswap.c \
|
||||
zfs_debug.c \
|
||||
@@ -139,9 +145,39 @@ KERNEL_C = \
|
||||
zle.c \
|
||||
zrlock.c
|
||||
|
||||
LUA_C = \
|
||||
lapi.c \
|
||||
lauxlib.c \
|
||||
lbaselib.c \
|
||||
lbitlib.c \
|
||||
lcode.c \
|
||||
lcompat.c \
|
||||
lcorolib.c \
|
||||
lctype.c \
|
||||
ldebug.c \
|
||||
ldo.c \
|
||||
ldump.c \
|
||||
lfunc.c \
|
||||
lgc.c \
|
||||
llex.c \
|
||||
lmem.c \
|
||||
lobject.c \
|
||||
lopcodes.c \
|
||||
lparser.c \
|
||||
lstate.c \
|
||||
lstring.c \
|
||||
lstrlib.c \
|
||||
ltable.c \
|
||||
ltablib.c \
|
||||
ltm.c \
|
||||
lundump.c \
|
||||
lvm.c \
|
||||
lzio.c
|
||||
|
||||
nodist_libzpool_la_SOURCES = \
|
||||
$(USER_C) \
|
||||
$(KERNEL_C)
|
||||
$(KERNEL_C) \
|
||||
$(LUA_C)
|
||||
|
||||
libzpool_la_LIBADD = \
|
||||
$(top_builddir)/lib/libavl/libavl.la \
|
||||
|
||||
Reference in New Issue
Block a user