Skip to content

Commit

Permalink
OpenZFS 7431 - ZFS Channel Programs
Browse files Browse the repository at this point in the history
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: openzfs/openzfs@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 implementation 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
  • Loading branch information
cwill authored and don-brady committed Aug 31, 2017
1 parent d22323e commit 9730797
Show file tree
Hide file tree
Showing 175 changed files with 26,739 additions and 274 deletions.
3 changes: 2 additions & 1 deletion Makefile.am
Expand Up @@ -47,7 +47,8 @@ commitcheck:

cstyle:
@find ${top_srcdir} -name '*.[hc]' ! -name 'zfs_config.*' \
! -name '*.mod.c' -type f -exec scripts/cstyle.pl -cpP {} \+
! -name '*.mod.c' ! -path '*/lua/l*.[hc]' \
-type f -exec scripts/cstyle.pl -cpP {} \+

shellcheck:
@if type shellcheck > /dev/null 2>&1; then \
Expand Down
215 changes: 214 additions & 1 deletion cmd/zfs/zfs_main.c
Expand Up @@ -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.
Expand All @@ -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>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -156,6 +158,7 @@ typedef enum {
HELP_RELEASE,
HELP_DIFF,
HELP_BOOKMARK,
HELP_CHANNEL_PROGRAM,
HELP_LOAD_KEY,
HELP_UNLOAD_KEY,
HELP_CHANGE_KEY,
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -7078,6 +7098,199 @@ zfs_do_bookmark(int argc, char **argv)
return (-1);
}

static int
zfs_do_channel_program(int argc, char **argv)
{
int ret, fd;
char 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 (-1 !=
(c = getopt(argc, argv, "t:m:"))) {
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;
Expand Down
7 changes: 6 additions & 1 deletion cmd/zpool/zpool_main.c
Expand Up @@ -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.
Expand Down Expand Up @@ -7299,6 +7299,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;
Expand Down
6 changes: 6 additions & 0 deletions configure.ac
Expand Up @@ -127,6 +127,7 @@ AC_CONFIG_FILES([
module/unicode/Makefile
module/zcommon/Makefile
module/zfs/Makefile
module/lua/Makefile
module/icp/Makefile
include/Makefile
include/linux/Makefile
Expand All @@ -136,6 +137,7 @@ AC_CONFIG_FILES([
include/sys/fm/fs/Makefile
include/sys/crypto/Makefile
include/sys/sysevent/Makefile
include/sys/lua/Makefile
scripts/Makefile
tests/Makefile
tests/test-runner/Makefile
Expand All @@ -159,6 +161,7 @@ AC_CONFIG_FILES([
tests/zfs-tests/cmd/mktree/Makefile
tests/zfs-tests/cmd/mmap_exec/Makefile
tests/zfs-tests/cmd/mmapwrite/Makefile
tests/zfs-tests/cmd/nvlist_to_lua/Makefile
tests/zfs-tests/cmd/randfree_file/Makefile
tests/zfs-tests/cmd/readmmap/Makefile
tests/zfs-tests/cmd/rename_dir/Makefile
Expand All @@ -177,6 +180,9 @@ AC_CONFIG_FILES([
tests/zfs-tests/tests/functional/cachefile/Makefile
tests/zfs-tests/tests/functional/casenorm/Makefile
tests/zfs-tests/tests/functional/checksum/Makefile
tests/zfs-tests/tests/functional/channel_program/Makefile
tests/zfs-tests/tests/functional/channel_program/lua_core/Makefile
tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile
tests/zfs-tests/tests/functional/chattr/Makefile
tests/zfs-tests/tests/functional/clean_mirror/Makefile
tests/zfs-tests/tests/functional/cli_root/Makefile
Expand Down
1 change: 1 addition & 0 deletions contrib/dracut/90zfs/module-setup.sh.in
Expand Up @@ -25,6 +25,7 @@ installkernel() {
instmods znvpair
instmods zavl
instmods zunicode
instmods zlua
instmods spl
instmods zlib_deflate
instmods zlib_inflate
Expand Down
2 changes: 1 addition & 1 deletion contrib/initramfs/hooks/zfs
Expand Up @@ -19,7 +19,7 @@ COPY_EXEC_LIST="$COPY_EXEC_LIST /bin/hostname /sbin/blkid"

# Explicitly specify all kernel modules because automatic dependency resolution
# is unreliable on many systems.
BASE_MODULES="zlib_deflate spl zavl zcommon znvpair zunicode zfs"
BASE_MODULES="zlib_deflate spl zavl zcommon znvpair zunicode zlua zfs"
CRPT_MODULES="sun-ccm sun-gcm sun-ctr"
MANUAL_ADD_MODULES_LIST="$BASE_MODULES"

Expand Down
2 changes: 1 addition & 1 deletion etc/init.d/zfs-zed.in
Expand Up @@ -71,7 +71,7 @@ do_stop()
# No pools imported, it is/should be safe/possible to
# unload modules.
zfs_action "Unloading modules" rmmod zfs zunicode \
zavl zcommon znvpair spl
zavl zcommon znvpair zlua spl
return "$?"
fi
else
Expand Down
5 changes: 4 additions & 1 deletion include/libzfs_core.h
Expand Up @@ -20,7 +20,7 @@
*/

/*
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2017 Datto Inc.
* Copyright 2017 RackTop Systems.
*/
Expand Down Expand Up @@ -100,6 +100,9 @@ boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int);
int lzc_rollback_to(const char *, const char *);

int lzc_channel_program(const char *, const char *, uint64_t, uint64_t,
nvlist_t *, nvlist_t **);

int lzc_sync(const char *, nvlist_t *, nvlist_t **);

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions include/libzfs_impl.h
Expand Up @@ -78,6 +78,7 @@ struct libzfs_handle {
libzfs_fru_t *libzfs_fru_list;
#endif /* HAVE_LIBTOPO */
char libzfs_chassis_id[256];
boolean_t libzfs_prop_debug;
};

#define ZFSSHARE_MISS 0x01 /* Didn't find entry in cache */
Expand Down

0 comments on commit 9730797

Please sign in to comment.