summaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/zfs_ioctl.c')
-rw-r--r--module/zfs/zfs_ioctl.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index b132a6885..a8f37fe84 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -27,7 +27,7 @@
* Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
@@ -193,6 +193,7 @@
#include <sys/dsl_bookmark.h>
#include <sys/dsl_userhold.h>
#include <sys/zfeature.h>
+#include <sys/zcp.h>
#include <sys/zio_checksum.h>
#include <linux/miscdevice.h>
@@ -203,6 +204,9 @@
#include "zfs_deleg.h"
#include "zfs_comutil.h"
+#include <sys/lua/lua.h>
+#include <sys/lua/lauxlib.h>
+
/*
* Limit maximum nvlist size. We don't want users passing in insane values
* for zc->zc_nvlist_src_size, since we will need to allocate that much memory.
@@ -1414,17 +1418,11 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
return (error);
}
-static int
-getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
+int
+getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp)
{
- objset_t *os;
- int error;
-
- error = dmu_objset_hold(dsname, FTAG, &os);
- if (error != 0)
- return (error);
+ int error = 0;
if (dmu_objset_type(os) != DMU_OST_ZFS) {
- dmu_objset_rele(os, FTAG);
return (SET_ERROR(EINVAL));
}
@@ -1436,6 +1434,20 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
error = SET_ERROR(ESRCH);
}
mutex_exit(&os->os_user_ptr_lock);
+ return (error);
+}
+
+static int
+getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
+{
+ objset_t *os;
+ int error;
+
+ error = dmu_objset_hold(dsname, FTAG, &os);
+ if (error != 0)
+ return (error);
+
+ error = getzfsvfs_impl(os, zfvp);
dmu_objset_rele(os, FTAG);
return (error);
}
@@ -3660,6 +3672,36 @@ zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl,
return (error);
}
+static int
+zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl,
+ nvlist_t *outnvl)
+{
+ char *program;
+ uint64_t instrlimit, memlimit;
+ nvpair_t *nvarg = NULL;
+
+ if (0 != nvlist_lookup_string(innvl, ZCP_ARG_PROGRAM, &program)) {
+ return (EINVAL);
+ }
+ if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_INSTRLIMIT, &instrlimit)) {
+ instrlimit = ZCP_DEFAULT_INSTRLIMIT;
+ }
+ if (0 != nvlist_lookup_uint64(innvl, ZCP_ARG_MEMLIMIT, &memlimit)) {
+ memlimit = ZCP_DEFAULT_MEMLIMIT;
+ }
+ if (0 != nvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST, &nvarg)) {
+ return (EINVAL);
+ }
+
+ if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
+ return (EINVAL);
+ if (memlimit == 0 || memlimit > ZCP_MAX_MEMLIMIT)
+ return (EINVAL);
+
+ return (zcp_eval(poolname, program, instrlimit, memlimit,
+ nvarg, outnvl));
+}
+
/*
* inputs:
* zc_name name of dataset to destroy
@@ -6333,6 +6375,11 @@ zfs_ioctl_init(void)
zfs_secpolicy_config, POOL_NAME, POOL_CHECK_SUSPENDED, B_TRUE,
B_TRUE);
+ zfs_ioctl_register("channel_program", ZFS_IOC_CHANNEL_PROGRAM,
+ zfs_ioc_channel_program, zfs_secpolicy_config,
+ POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE,
+ B_TRUE);
+
/* IOCTLS that use the legacy function signature */
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
@@ -6803,12 +6850,23 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
error = vec->zvec_func(zc->zc_name, innvl, outnvl);
spl_fstrans_unmark(cookie);
- if (error == 0 && vec->zvec_allow_log &&
+ /*
+ * Some commands can partially execute, modify state, and still
+ * return an error. In these cases, attempt to record what
+ * was modified.
+ */
+ if ((error == 0 ||
+ (cmd == ZFS_IOC_CHANNEL_PROGRAM && error != EINVAL)) &&
+ vec->zvec_allow_log &&
spa_open(zc->zc_name, &spa, FTAG) == 0) {
if (!nvlist_empty(outnvl)) {
fnvlist_add_nvlist(lognv, ZPOOL_HIST_OUTPUT_NVL,
outnvl);
}
+ if (error != 0) {
+ fnvlist_add_int64(lognv, ZPOOL_HIST_ERRNO,
+ error);
+ }
(void) spa_history_log_nvl(spa, lognv);
spa_close(spa, FTAG);
}