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
+212
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
|
||||
* Copyright 2012 Milan Jurik. All rights reserved.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/list.h>
|
||||
#include <sys/mkdev.h>
|
||||
#include <sys/mntent.h>
|
||||
@@ -106,6 +107,7 @@ static int zfs_do_holds(int argc, char **argv);
|
||||
static int zfs_do_release(int argc, char **argv);
|
||||
static int zfs_do_diff(int argc, char **argv);
|
||||
static int zfs_do_bookmark(int argc, char **argv);
|
||||
static int zfs_do_channel_program(int argc, char **argv);
|
||||
static int zfs_do_load_key(int argc, char **argv);
|
||||
static int zfs_do_unload_key(int argc, char **argv);
|
||||
static int zfs_do_change_key(int argc, char **argv);
|
||||
@@ -156,6 +158,7 @@ typedef enum {
|
||||
HELP_RELEASE,
|
||||
HELP_DIFF,
|
||||
HELP_BOOKMARK,
|
||||
HELP_CHANNEL_PROGRAM,
|
||||
HELP_LOAD_KEY,
|
||||
HELP_UNLOAD_KEY,
|
||||
HELP_CHANGE_KEY,
|
||||
@@ -186,6 +189,7 @@ static zfs_command_t command_table[] = {
|
||||
{ "promote", zfs_do_promote, HELP_PROMOTE },
|
||||
{ "rename", zfs_do_rename, HELP_RENAME },
|
||||
{ "bookmark", zfs_do_bookmark, HELP_BOOKMARK },
|
||||
{ "program", zfs_do_channel_program, HELP_CHANNEL_PROGRAM },
|
||||
{ NULL },
|
||||
{ "list", zfs_do_list, HELP_LIST },
|
||||
{ NULL },
|
||||
@@ -335,6 +339,10 @@ get_usage(zfs_help_t idx)
|
||||
"[snapshot|filesystem]\n"));
|
||||
case HELP_BOOKMARK:
|
||||
return (gettext("\tbookmark <snapshot> <bookmark>\n"));
|
||||
case HELP_CHANNEL_PROGRAM:
|
||||
return (gettext("\tprogram [-t <instruction limit>] "
|
||||
"[-m <memory limit (b)>] <pool> <program file> "
|
||||
"[lua args...]\n"));
|
||||
case HELP_LOAD_KEY:
|
||||
return (gettext("\tload-key [-rn] [-L <keylocation>] "
|
||||
"<-a | filesystem|volume>\n"));
|
||||
@@ -374,6 +382,18 @@ safe_malloc(size_t size)
|
||||
return (data);
|
||||
}
|
||||
|
||||
void *
|
||||
safe_realloc(void *data, size_t size)
|
||||
{
|
||||
void *newp;
|
||||
if ((newp = realloc(data, size)) == NULL) {
|
||||
free(data);
|
||||
nomem();
|
||||
}
|
||||
|
||||
return (newp);
|
||||
}
|
||||
|
||||
static char *
|
||||
safe_strdup(char *str)
|
||||
{
|
||||
@@ -7069,6 +7089,197 @@ usage:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_do_channel_program(int argc, char **argv)
|
||||
{
|
||||
int ret, fd, c;
|
||||
char *progbuf, *filename, *poolname;
|
||||
size_t progsize, progread;
|
||||
nvlist_t *outnvl;
|
||||
uint64_t instrlimit = ZCP_DEFAULT_INSTRLIMIT;
|
||||
uint64_t memlimit = ZCP_DEFAULT_MEMLIMIT;
|
||||
zpool_handle_t *zhp;
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, "t:m:")) != -1) {
|
||||
switch (c) {
|
||||
case 't':
|
||||
case 'm': {
|
||||
uint64_t arg;
|
||||
char *endp;
|
||||
|
||||
errno = 0;
|
||||
arg = strtoull(optarg, &endp, 0);
|
||||
if (errno != 0 || *endp != '\0') {
|
||||
(void) fprintf(stderr, gettext(
|
||||
"invalid argument "
|
||||
"'%s': expected integer\n"), optarg);
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (c == 't') {
|
||||
if (arg > ZCP_MAX_INSTRLIMIT || arg == 0) {
|
||||
(void) fprintf(stderr, gettext(
|
||||
"Invalid instruction limit: "
|
||||
"%s\n"), optarg);
|
||||
return (1);
|
||||
} else {
|
||||
instrlimit = arg;
|
||||
}
|
||||
} else {
|
||||
ASSERT3U(c, ==, 'm');
|
||||
if (arg > ZCP_MAX_MEMLIMIT || arg == 0) {
|
||||
(void) fprintf(stderr, gettext(
|
||||
"Invalid memory limit: "
|
||||
"%s\n"), optarg);
|
||||
return (1);
|
||||
} else {
|
||||
memlimit = arg;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||
optopt);
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 2) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("invalid number of arguments\n"));
|
||||
goto usage;
|
||||
}
|
||||
|
||||
poolname = argv[0];
|
||||
filename = argv[1];
|
||||
if (strcmp(filename, "-") == 0) {
|
||||
fd = 0;
|
||||
filename = "standard input";
|
||||
} else if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
(void) fprintf(stderr, gettext("cannot open '%s': %s\n"),
|
||||
filename, strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
|
||||
(void) fprintf(stderr, gettext("cannot open pool '%s'"),
|
||||
poolname);
|
||||
return (1);
|
||||
}
|
||||
zpool_close(zhp);
|
||||
|
||||
/*
|
||||
* Read in the channel program, expanding the program buffer as
|
||||
* necessary.
|
||||
*/
|
||||
progread = 0;
|
||||
progsize = 1024;
|
||||
progbuf = safe_malloc(progsize);
|
||||
do {
|
||||
ret = read(fd, progbuf + progread, progsize - progread);
|
||||
progread += ret;
|
||||
if (progread == progsize && ret > 0) {
|
||||
progsize *= 2;
|
||||
progbuf = safe_realloc(progbuf, progsize);
|
||||
}
|
||||
} while (ret > 0);
|
||||
|
||||
if (fd != 0)
|
||||
(void) close(fd);
|
||||
if (ret < 0) {
|
||||
free(progbuf);
|
||||
(void) fprintf(stderr,
|
||||
gettext("cannot read '%s': %s\n"),
|
||||
filename, strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
progbuf[progread] = '\0';
|
||||
|
||||
/*
|
||||
* Any remaining arguments are passed as arguments to the lua script as
|
||||
* a string array:
|
||||
* {
|
||||
* "argv" -> [ "arg 1", ... "arg n" ],
|
||||
* }
|
||||
*/
|
||||
nvlist_t *argnvl = fnvlist_alloc();
|
||||
fnvlist_add_string_array(argnvl, ZCP_ARG_CLIARGV, argv + 2, argc - 2);
|
||||
|
||||
ret = lzc_channel_program(poolname, progbuf, instrlimit, memlimit,
|
||||
argnvl, &outnvl);
|
||||
|
||||
if (ret != 0) {
|
||||
/*
|
||||
* On error, report the error message handed back by lua if one
|
||||
* exists. Otherwise, generate an appropriate error message,
|
||||
* falling back on strerror() for an unexpected return code.
|
||||
*/
|
||||
char *errstring = NULL;
|
||||
uint64_t instructions = 0;
|
||||
if (nvlist_exists(outnvl, ZCP_RET_ERROR)) {
|
||||
(void) nvlist_lookup_string(outnvl,
|
||||
ZCP_RET_ERROR, &errstring);
|
||||
if (errstring == NULL)
|
||||
errstring = strerror(ret);
|
||||
if (ret == ETIME) {
|
||||
(void) nvlist_lookup_uint64(outnvl,
|
||||
ZCP_ARG_INSTRLIMIT, &instructions);
|
||||
}
|
||||
} else {
|
||||
switch (ret) {
|
||||
case EINVAL:
|
||||
errstring =
|
||||
"Invalid instruction or memory limit.";
|
||||
break;
|
||||
case ENOMEM:
|
||||
errstring = "Return value too large.";
|
||||
break;
|
||||
case ENOSPC:
|
||||
errstring = "Memory limit exhausted.";
|
||||
break;
|
||||
case ETIME:
|
||||
errstring = "Timed out.";
|
||||
break;
|
||||
case EPERM:
|
||||
errstring = "Permission denied. Channel "
|
||||
"programs must be run as root.";
|
||||
break;
|
||||
default:
|
||||
errstring = strerror(ret);
|
||||
}
|
||||
}
|
||||
(void) fprintf(stderr,
|
||||
gettext("Channel program execution failed:\n%s\n"),
|
||||
errstring);
|
||||
if (ret == ETIME && instructions != 0)
|
||||
(void) fprintf(stderr, "%llu Lua instructions\n",
|
||||
(u_longlong_t)instructions);
|
||||
} else {
|
||||
(void) printf("Channel program fully executed ");
|
||||
if (nvlist_empty(outnvl)) {
|
||||
(void) printf("with no return value.\n");
|
||||
} else {
|
||||
(void) printf("with return value:\n");
|
||||
dump_nvlist(outnvl, 4);
|
||||
}
|
||||
}
|
||||
|
||||
free(progbuf);
|
||||
fnvlist_free(outnvl);
|
||||
fnvlist_free(argnvl);
|
||||
return (ret != 0);
|
||||
|
||||
usage:
|
||||
usage(B_FALSE);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
typedef struct loadkey_cbdata {
|
||||
boolean_t cb_loadkey;
|
||||
boolean_t cb_recursive;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
|
||||
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
|
||||
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
|
||||
@@ -7344,6 +7344,11 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
||||
dump_nvlist(fnvlist_lookup_nvlist(rec,
|
||||
ZPOOL_HIST_OUTPUT_NVL), 8);
|
||||
}
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
|
||||
(void) printf(" errno: %lld\n",
|
||||
(longlong_t)fnvlist_lookup_int64(rec,
|
||||
ZPOOL_HIST_ERRNO));
|
||||
}
|
||||
} else {
|
||||
if (!cb->internal)
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user