Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154304001
D25393.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
D25393.id.diff
View Options
Index: head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
===================================================================
--- head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
+++ head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -7235,7 +7235,7 @@
fnvlist_free(nvl);
if (ret != 0) {
- const char *err_msg;
+ const char *err_msg = NULL;
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf),
@@ -7259,11 +7259,13 @@
err_msg = "out of space";
break;
default:
- err_msg = "unknown error";
+ (void) zfs_standard_error(g_zfs, ret, errbuf);
break;
}
- (void) fprintf(stderr, "%s: %s\n", errbuf,
- dgettext(TEXT_DOMAIN, err_msg));
+ if (err_msg != NULL) {
+ (void) fprintf(stderr, "%s: %s\n", errbuf,
+ dgettext(TEXT_DOMAIN, err_msg));
+ }
}
return (ret != 0);
@@ -7280,7 +7282,7 @@
char c;
char *progbuf, *filename, *poolname;
size_t progsize, progread;
- nvlist_t *outnvl;
+ nvlist_t *outnvl = NULL;
uint64_t instrlimit = ZCP_DEFAULT_INSTRLIMIT;
uint64_t memlimit = ZCP_DEFAULT_MEMLIMIT;
boolean_t sync_flag = B_TRUE, json_output = B_FALSE;
@@ -7420,7 +7422,8 @@
* falling back on strerror() for an unexpected return code.
*/
char *errstring = NULL;
- if (nvlist_exists(outnvl, ZCP_RET_ERROR)) {
+ const char *msg = gettext("Channel program execution failed");
+ if (outnvl != NULL && nvlist_exists(outnvl, ZCP_RET_ERROR)) {
(void) nvlist_lookup_string(outnvl,
ZCP_RET_ERROR, &errstring);
if (errstring == NULL)
@@ -7449,12 +7452,11 @@
"programs must be run as root.";
break;
default:
- errstring = strerror(ret);
+ (void) zfs_standard_error(g_zfs, ret, msg);
}
}
- (void) fprintf(stderr,
- gettext("Channel program execution failed:\n%s\n"),
- errstring);
+ if (errstring != NULL)
+ (void) fprintf(stderr, "%s:\n%s\n", msg, errstring);
} else {
if (json_output) {
(void) nvlist_print_json(stdout, outnvl);
Index: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
===================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright 2019 Joyent, Inc.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
@@ -142,6 +142,7 @@
EZFS_INITIALIZING, /* currently initializing */
EZFS_NO_INITIALIZE, /* no active initialize */
EZFS_WRONG_PARENT, /* invalid parent dataset (e.g ZVOL) */
+ EZFS_IOC_NOTSUPPORTED, /* operation not supported by zfs module */
EZFS_UNKNOWN
} zfs_error_t;
Index: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
===================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019 Joyent, Inc.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2017 Datto Inc.
*/
@@ -207,6 +207,9 @@
case EZFS_NOTSUP:
return (dgettext(TEXT_DOMAIN, "operation not supported "
"on this dataset"));
+ case EZFS_IOC_NOTSUPPORTED:
+ return (dgettext(TEXT_DOMAIN, "operation not supported by "
+ "zfs kernel module"));
case EZFS_ACTIVE_SPARE:
return (dgettext(TEXT_DOMAIN, "pool has active shared spare "
"device"));
@@ -433,6 +436,22 @@
case EREMOTEIO:
zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
break;
+ case ZFS_ERR_IOC_CMD_UNAVAIL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "
+ "module does not support this operation. A reboot may "
+ "be required to enable this operation."));
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
+ break;
+ case ZFS_ERR_IOC_ARG_UNAVAIL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "
+ "module does not support an option for this operation. "
+ "A reboot may be required to enable this option."));
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
+ break;
+ case ZFS_ERR_IOC_ARG_REQUIRED:
+ case ZFS_ERR_IOC_ARG_BADTYPE:
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
+ break;
default:
zfs_error_aux(hdl, strerror(error));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
@@ -541,6 +560,22 @@
break;
case ZFS_ERR_WRONG_PARENT:
zfs_verror(hdl, EZFS_WRONG_PARENT, fmt, ap);
+ break;
+ case ZFS_ERR_IOC_CMD_UNAVAIL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "
+ "module does not support this operation. A reboot may "
+ "be required to enable this operation."));
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
+ break;
+ case ZFS_ERR_IOC_ARG_UNAVAIL:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "
+ "module does not support an option for this operation. "
+ "A reboot may be required to enable this option."));
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
+ break;
+ case ZFS_ERR_IOC_ARG_REQUIRED:
+ case ZFS_ERR_IOC_ARG_BADTYPE:
+ zfs_verror(hdl, EZFS_IOC_NOTSUPPORTED, fmt, ap);
break;
default:
zfs_error_aux(hdl, strerror(error));
Index: head/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
===================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
+++ head/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
@@ -80,6 +80,9 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#ifdef ZFS_DEBUG
+#include <stdio.h>
+#endif
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
@@ -99,6 +102,42 @@
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_refcount;
+#ifdef ZFS_DEBUG
+static zfs_ioc_t fail_ioc_cmd;
+static zfs_errno_t fail_ioc_err;
+
+static void
+libzfs_core_debug_ioc(void)
+{
+ /*
+ * To test running newer user space binaries with kernel's
+ * that don't yet support an ioctl or a new ioctl arg we
+ * provide an override to intentionally fail an ioctl.
+ *
+ * USAGE:
+ * The override variable, ZFS_IOC_TEST, is of the form "cmd:err"
+ *
+ * For example, to fail a ZFS_IOC_POOL_CHECKPOINT with a
+ * ZFS_ERR_IOC_CMD_UNAVAIL, the string would be "0x5a4d:1029"
+ *
+ * $ sudo sh -c "ZFS_IOC_TEST=0x5a4d:1029 zpool checkpoint tank"
+ * cannot checkpoint 'tank': the loaded zfs module does not support
+ * this operation. A reboot may be required to enable this operation.
+ */
+ if (fail_ioc_cmd == 0) {
+ char *ioc_test = getenv("ZFS_IOC_TEST");
+ unsigned int ioc_num = 0, ioc_err = 0;
+
+ if (ioc_test != NULL &&
+ sscanf(ioc_test, "%i:%i", &ioc_num, &ioc_err) == 2 &&
+ ioc_num < ZFS_IOC_LAST) {
+ fail_ioc_cmd = ioc_num;
+ fail_ioc_err = ioc_err;
+ }
+ }
+}
+#endif
+
int
libzfs_core_init(void)
{
@@ -111,6 +150,10 @@
}
}
g_refcount++;
+
+#ifdef ZFS_DEBUG
+ libzfs_core_debug_ioc();
+#endif
(void) pthread_mutex_unlock(&g_lock);
return (0);
@@ -146,6 +189,11 @@
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);
+
+#ifdef ZFS_DEBUG
+ if (ioc == fail_ioc_cmd)
+ return (fail_ioc_err);
+#endif
if (name != NULL)
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
Index: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
===================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -27,7 +27,7 @@
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 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]
@@ -61,8 +61,9 @@
*
* zfs_ioc_t ioc
* The ioctl request number, which userland will pass to ioctl(2).
- * The ioctl numbers can change from release to release, because
- * the caller (libzfs) must be matched to the kernel.
+ * We want newer versions of libzfs and libzfs_core to run against
+ * existing zfs kernel modules (i.e. a deferred reboot after an update).
+ * Therefore the ioctl numbers cannot change from release to release.
*
* zfs_secpolicy_func_t *secpolicy
* This function will be called before the zfs_ioc_func_t, to
@@ -88,6 +89,10 @@
* Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED |
* POOL_CHECK_READONLY).
*
+ * zfs_ioc_key_t *nvl_keys
+ * The list of expected/allowable innvl input keys. This list is used
+ * to validate the nvlist input to the ioctl.
+ *
* boolean_t smush_outnvlist
* If smush_outnvlist is true, then the output is presumed to be a
* list of errors, and it will be "smushed" down to fit into the
@@ -136,7 +141,17 @@
* use the outnvl if they succeed, because the caller can not
* distinguish between the operation failing, and
* deserialization failing.
+ *
+ *
+ * IOCTL Interface Errors
+ *
+ * The following ioctl input errors can be returned:
+ * ZFS_ERR_IOC_CMD_UNAVAIL the ioctl number is not supported by kernel
+ * ZFS_ERR_IOC_ARG_UNAVAIL an input argument is not supported by kernel
+ * ZFS_ERR_IOC_ARG_REQUIRED a required input argument is missing
+ * ZFS_ERR_IOC_ARG_BADTYPE an input argument has an invalid type
*/
+
#ifdef __FreeBSD__
#include "opt_kstack_pages.h"
#endif
@@ -208,6 +223,10 @@
#include "lua.h"
#include "lauxlib.h"
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) nitems(x)
+#endif
+
static struct cdev *zfsdev;
extern void zfs_init(void);
@@ -222,7 +241,38 @@
typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
+/*
+ * IOC Keys are used to document and validate user->kernel interface inputs.
+ * See zfs_keys_recv_new for an example declaration. Any key name that is not
+ * listed will be rejected as input.
+ *
+ * The keyname 'optional' is always allowed, and must be an nvlist if present.
+ * Arguments which older kernels can safely ignore can be placed under the
+ * "optional" key.
+ *
+ * When adding new keys to an existing ioc for new functionality, consider:
+ * - adding an entry into zfs_sysfs.c zfs_features[] list
+ * - updating the libzfs_input_check.c test utility
+ *
+ * Note: in the ZK_WILDCARDLIST case, the name serves as documentation
+ * for the expected name (bookmark, snapshot, property, etc) but there
+ * is no validation in the preflight zfs_check_input_nvpairs() check.
+ */
typedef enum {
+ ZK_OPTIONAL = 1 << 0, /* pair is optional */
+ ZK_WILDCARDLIST = 1 << 1, /* one or more unspecified key names */
+} ioc_key_flag_t;
+
+/* DATA_TYPE_ANY is used when zkey_type can vary. */
+#define DATA_TYPE_ANY DATA_TYPE_UNKNOWN
+
+typedef struct zfs_ioc_key {
+ const char *zkey_name;
+ data_type_t zkey_type;
+ ioc_key_flag_t zkey_flags;
+} zfs_ioc_key_t;
+
+typedef enum {
NO_NAME,
POOL_NAME,
DATASET_NAME,
@@ -244,6 +294,8 @@
zfs_ioc_poolcheck_t zvec_pool_check;
boolean_t zvec_smush_outnvlist;
const char *zvec_name;
+ const zfs_ioc_key_t *zvec_nvl_keys;
+ size_t zvec_nvl_key_count;
} zfs_ioc_vec_t;
/* This array is indexed by zfs_userquota_prop_t */
@@ -865,8 +917,8 @@
nvpair_t *pair, *nextpair;
int error = 0;
- if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
- return (SET_ERROR(EINVAL));
+ snaps = fnvlist_lookup_nvlist(innvl, "snaps");
+
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nextpair) {
nextpair = nvlist_next_nvpair(snaps, pair);
@@ -1042,8 +1094,8 @@
int error;
nvpair_t *pair;
- if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
- return (SET_ERROR(EINVAL));
+ snaps = fnvlist_lookup_nvlist(innvl, "snaps");
+
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
char *name = nvpair_name(pair);
@@ -1063,7 +1115,7 @@
}
/*
- * Check for permission to create each snapshot in the nvlist.
+ * Check for permission to create each bookmark in the nvlist.
*/
/* ARGSUSED */
static int
@@ -1292,9 +1344,7 @@
nvlist_t *holds;
int error;
- error = nvlist_lookup_nvlist(innvl, "holds", &holds);
- if (error != 0)
- return (SET_ERROR(EINVAL));
+ holds = fnvlist_lookup_nvlist(innvl, "holds");
for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
pair = nvlist_next_nvpair(holds, pair)) {
@@ -1349,12 +1399,14 @@
return (0);
error = zfs_secpolicy_snapshot_perms(zc->zc_name, cr);
- if (error == 0)
- error = zfs_secpolicy_hold(zc, innvl, cr);
- if (error == 0)
- error = zfs_secpolicy_release(zc, innvl, cr);
- if (error == 0)
- error = zfs_secpolicy_destroy(zc, innvl, cr);
+ if (innvl != NULL) {
+ if (error == 0)
+ error = zfs_secpolicy_hold(zc, innvl, cr);
+ if (error == 0)
+ error = zfs_secpolicy_release(zc, innvl, cr);
+ if (error == 0)
+ error = zfs_secpolicy_destroy(zc, innvl, cr);
+ }
return (error);
}
@@ -3309,6 +3361,13 @@
*
* outnvl: propname -> error code (int32)
*/
+
+static const zfs_ioc_key_t zfs_keys_create[] = {
+ {"type", DATA_TYPE_INT32, 0},
+ {"props", DATA_TYPE_NVLIST, ZK_OPTIONAL},
+ {"hidden_args", DATA_TYPE_NVLIST, ZK_OPTIONAL},
+};
+
static int
zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3316,13 +3375,10 @@
zfs_creat_t zct = { 0 };
nvlist_t *nvprops = NULL;
void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
- int32_t type32;
dmu_objset_type_t type;
boolean_t is_insensitive = B_FALSE;
- if (nvlist_lookup_int32(innvl, "type", &type32) != 0)
- return (SET_ERROR(EINVAL));
- type = type32;
+ type = (dmu_objset_type_t)fnvlist_lookup_int32(innvl, "type");
(void) nvlist_lookup_nvlist(innvl, "props", &nvprops);
switch (type) {
@@ -3427,6 +3483,12 @@
*
* outnvl: propname -> error code (int32)
*/
+static const zfs_ioc_key_t zfs_keys_clone[] = {
+ {"origin", DATA_TYPE_STRING, 0},
+ {"props", DATA_TYPE_NVLIST, ZK_OPTIONAL},
+ {"hidden_args", DATA_TYPE_NVLIST, ZK_OPTIONAL},
+};
+
static int
zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3434,8 +3496,7 @@
nvlist_t *nvprops = NULL;
char *origin_name;
- if (nvlist_lookup_string(innvl, "origin", &origin_name) != 0)
- return (SET_ERROR(EINVAL));
+ origin_name = fnvlist_lookup_string(innvl, "origin");
(void) nvlist_lookup_nvlist(innvl, "props", &nvprops);
if (strchr(fsname, '@') ||
@@ -3460,6 +3521,10 @@
return (error);
}
+static const zfs_ioc_key_t zfs_keys_remap[] = {
+ /* no nvl keys */
+};
+
/* ARGSUSED */
static int
zfs_ioc_remap(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -3479,6 +3544,11 @@
*
* outnvl: snapshot -> error code (int32)
*/
+static const zfs_ioc_key_t zfs_keys_snapshot[] = {
+ {"snaps", DATA_TYPE_NVLIST, 0},
+ {"props", DATA_TYPE_NVLIST, ZK_OPTIONAL},
+};
+
static int
zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3494,8 +3564,7 @@
if ((error = zfs_check_userprops(props)) != 0)
return (error);
- if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
- return (SET_ERROR(EINVAL));
+ snaps = fnvlist_lookup_nvlist(innvl, "snaps");
poollen = strlen(poolname);
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) {
@@ -3546,6 +3615,10 @@
/*
* innvl: "message" -> string
*/
+static const zfs_ioc_key_t zfs_keys_log_history[] = {
+ {"message", DATA_TYPE_STRING, 0},
+};
+
/* ARGSUSED */
static int
zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
@@ -3569,10 +3642,7 @@
if (error != 0)
return (error);
- if (nvlist_lookup_string(innvl, "message", &message) != 0) {
- spa_close(spa, FTAG);
- return (SET_ERROR(EINVAL));
- }
+ message = fnvlist_lookup_string(innvl, "message");
if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
spa_close(spa, FTAG);
@@ -3585,6 +3655,10 @@
}
#ifdef __FreeBSD__
+static const zfs_ioc_key_t zfs_keys_nextboot[] = {
+ {"command", DATA_TYPE_STRING, 0},
+};
+
static int
zfs_ioc_nextboot(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3602,9 +3676,7 @@
if (nvlist_lookup_uint64(innvl,
ZPOOL_CONFIG_GUID, &vdev_guid) != 0)
return (EINVAL);
- if (nvlist_lookup_string(innvl,
- "command", &command) != 0)
- return (EINVAL);
+ command = fnvlist_lookup_string(innvl, "command");
mutex_enter(&spa_namespace_lock);
spa = spa_by_guid(pool_guid, vdev_guid);
@@ -3721,6 +3793,11 @@
* outnvl: snapshot -> error code (int32)
*
*/
+static const zfs_ioc_key_t zfs_keys_destroy_snaps[] = {
+ {"snaps", DATA_TYPE_NVLIST, 0},
+ {"defer", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+};
+
/* ARGSUSED */
static int
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -3730,8 +3807,7 @@
nvpair_t *pair;
boolean_t defer;
- if (nvlist_lookup_nvlist(innvl, "snaps", &snaps) != 0)
- return (SET_ERROR(EINVAL));
+ snaps = fnvlist_lookup_nvlist(innvl, "snaps");
defer = nvlist_exists(innvl, "defer");
poollen = strlen(poolname);
@@ -3764,6 +3840,10 @@
* outnvl: bookmark -> error code (int32)
*
*/
+static const zfs_ioc_key_t zfs_keys_bookmark[] = {
+ {"<bookmark>...", DATA_TYPE_STRING, ZK_WILDCARDLIST},
+};
+
/* ARGSUSED */
static int
zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -3801,6 +3881,10 @@
* }
*
*/
+static const zfs_ioc_key_t zfs_keys_get_bookmarks[] = {
+ {"<property>...", DATA_TYPE_BOOLEAN, ZK_WILDCARDLIST | ZK_OPTIONAL},
+};
+
static int
zfs_ioc_get_bookmarks(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -3815,6 +3899,10 @@
* outnvl: bookmark -> error code (int32)
*
*/
+static const zfs_ioc_key_t zfs_keys_destroy_bookmarks[] = {
+ {"<bookmark>...", DATA_TYPE_BOOLEAN, ZK_WILDCARDLIST},
+};
+
static int
zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl,
nvlist_t *outnvl)
@@ -3847,6 +3935,14 @@
return (error);
}
+static const zfs_ioc_key_t zfs_keys_channel_program[] = {
+ {"program", DATA_TYPE_STRING, 0},
+ {"arg", DATA_TYPE_ANY, 0},
+ {"sync", DATA_TYPE_BOOLEAN_VALUE, ZK_OPTIONAL},
+ {"instrlimit", DATA_TYPE_UINT64, ZK_OPTIONAL},
+ {"memlimit", DATA_TYPE_UINT64, ZK_OPTIONAL},
+};
+
static int
zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl,
nvlist_t *outnvl)
@@ -3856,9 +3952,7 @@
boolean_t sync_flag;
nvpair_t *nvarg = NULL;
- if (0 != nvlist_lookup_string(innvl, ZCP_ARG_PROGRAM, &program)) {
- return (EINVAL);
- }
+ program = fnvlist_lookup_string(innvl, ZCP_ARG_PROGRAM);
if (0 != nvlist_lookup_boolean_value(innvl, ZCP_ARG_SYNC, &sync_flag)) {
sync_flag = B_TRUE;
}
@@ -3868,9 +3962,7 @@
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);
- }
+ nvarg = fnvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST);
if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
return (EINVAL);
@@ -3885,6 +3977,10 @@
* innvl: unused
* outnvl: empty
*/
+static const zfs_ioc_key_t zfs_keys_pool_checkpoint[] = {
+ /* no nvl keys */
+};
+
/* ARGSUSED */
static int
zfs_ioc_pool_checkpoint(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -3896,6 +3992,10 @@
* innvl: unused
* outnvl: empty
*/
+static const zfs_ioc_key_t zfs_keys_pool_discard_checkpoint[] = {
+ /* no nvl keys */
+};
+
/* ARGSUSED */
static int
zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl,
@@ -3955,6 +4055,11 @@
* }
*
*/
+static const zfs_ioc_key_t zfs_keys_pool_initialize[] = {
+ {ZPOOL_INITIALIZE_COMMAND, DATA_TYPE_UINT64, 0},
+ {ZPOOL_INITIALIZE_VDEVS, DATA_TYPE_NVLIST, 0}
+};
+
static int
zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -4020,6 +4125,10 @@
* outnvl: "target" -> name of most recent snapshot
* }
*/
+static const zfs_ioc_key_t zfs_keys_rollback[] = {
+ {"target", DATA_TYPE_STRING, ZK_OPTIONAL},
+};
+
/* ARGSUSED */
static int
zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -5167,13 +5276,33 @@
return (error);
}
+/*
+ * Reopen all the vdevs associated with the pool.
+ *
+ * innvl: {
+ * "scrub_restart" -> when true and scrub is running, allow to restart
+ * scrub as the side effect of the reopen (boolean).
+ * }
+ *
+ * outnvl is unused
+ */
+static const zfs_ioc_key_t zfs_keys_pool_reopen[] = {
+ {"scrub_restart", DATA_TYPE_BOOLEAN_VALUE, ZK_OPTIONAL},
+};
+
static int
-zfs_ioc_pool_reopen(zfs_cmd_t *zc)
+zfs_ioc_pool_reopen(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
{
spa_t *spa;
int error;
+ boolean_t scrub_restart = B_TRUE;
- error = spa_open(zc->zc_name, &spa, FTAG);
+ if (innvl) {
+ scrub_restart = fnvlist_lookup_boolean_value(innvl,
+ "scrub_restart");
+ }
+
+ error = spa_open(pool, &spa, FTAG);
if (error != 0)
return (error);
@@ -5185,7 +5314,8 @@
* the scan as a side effect of the reopen. Otherwise, let
* vdev_open() decided if a resilver is required.
*/
- spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool);
+ spa->spa_scrub_reopen = (!scrub_restart &&
+ dsl_scan_resilvering(spa->spa_dsl_pool));
vdev_reopen(spa->spa_root_vdev);
spa->spa_scrub_reopen = B_FALSE;
@@ -5193,6 +5323,7 @@
spa_close(spa, FTAG);
return (0);
}
+
/*
* inputs:
* zc_name name of filesystem
@@ -5789,6 +5920,11 @@
* ...
* }
*/
+static const zfs_ioc_key_t zfs_keys_hold[] = {
+ {"holds", DATA_TYPE_NVLIST, 0},
+ {"cleanup_fd", DATA_TYPE_INT32, ZK_OPTIONAL},
+};
+
/* ARGSUSED */
static int
zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
@@ -5799,9 +5935,7 @@
int error;
minor_t minor = 0;
- error = nvlist_lookup_nvlist(args, "holds", &holds);
- if (error != 0)
- return (SET_ERROR(EINVAL));
+ holds = fnvlist_lookup_nvlist(args, "holds");
/* make sure the user didn't pass us any invalid (empty) tags */
for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
@@ -5836,11 +5970,14 @@
* ...
* }
*/
+static const zfs_ioc_key_t zfs_keys_get_holds[] = {
+ /* no nvl keys */
+};
+
/* ARGSUSED */
static int
zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
{
- ASSERT3P(args, ==, NULL);
return (dsl_dataset_get_holds(snapname, outnvl));
}
@@ -5855,6 +5992,10 @@
* ...
* }
*/
+static const zfs_ioc_key_t zfs_keys_release[] = {
+ {"<snapname>...", DATA_TYPE_NVLIST, ZK_WILDCARDLIST},
+};
+
/* ARGSUSED */
static int
zfs_ioc_release(const char *pool, nvlist_t *holds, nvlist_t *errlist)
@@ -5913,6 +6054,10 @@
* "uncompressed" -> uncompressed space in bytes
* }
*/
+static const zfs_ioc_key_t zfs_keys_space_snaps[] = {
+ {"firstsnap", DATA_TYPE_STRING, 0},
+};
+
static int
zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -5922,8 +6067,7 @@
char *firstsnap;
uint64_t used, comp, uncomp;
- if (nvlist_lookup_string(innvl, "firstsnap", &firstsnap) != 0)
- return (SET_ERROR(EINVAL));
+ firstsnap = fnvlist_lookup_string(innvl, "firstsnap");
error = dsl_pool_hold(lastsnap, FTAG, &dp);
if (error != 0)
@@ -5991,6 +6135,17 @@
*
* outnvl is unused
*/
+static const zfs_ioc_key_t zfs_keys_send_new[] = {
+ {"fd", DATA_TYPE_INT32, 0},
+ {"fromsnap", DATA_TYPE_STRING, ZK_OPTIONAL},
+ {"largeblockok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"embedok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"compressok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"rawok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"resume_object", DATA_TYPE_UINT64, ZK_OPTIONAL},
+ {"resume_offset", DATA_TYPE_UINT64, ZK_OPTIONAL},
+};
+
/* ARGSUSED */
static int
zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
@@ -6006,9 +6161,7 @@
uint64_t resumeobj = 0;
uint64_t resumeoff = 0;
- error = nvlist_lookup_int32(innvl, "fd", &fd);
- if (error != 0)
- return (SET_ERROR(EINVAL));
+ fd = fnvlist_lookup_int32(innvl, "fd");
(void) nvlist_lookup_string(innvl, "fromsnap", &fromname);
@@ -6065,6 +6218,15 @@
* "space" -> bytes of space (uint64)
* }
*/
+static const zfs_ioc_key_t zfs_keys_send_space[] = {
+ {"from", DATA_TYPE_STRING, ZK_OPTIONAL},
+ {"fromsnap", DATA_TYPE_STRING, ZK_OPTIONAL},
+ {"largeblockok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"embedok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"compressok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+ {"rawok", DATA_TYPE_BOOLEAN, ZK_OPTIONAL},
+};
+
static int
zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
{
@@ -6153,6 +6315,10 @@
*
* onvl is unused
*/
+static const zfs_ioc_key_t zfs_keys_pool_sync[] = {
+ {"force", DATA_TYPE_BOOLEAN_VALUE, 0},
+};
+
/* ARGSUSED */
static int
zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl)
@@ -6206,7 +6372,7 @@
zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist,
- boolean_t allow_log)
+ boolean_t allow_log, const zfs_ioc_key_t *nvl_keys, size_t num_keys)
{
zfs_ioc_vec_t *vec = &zfs_ioc_vec[ioc - ZFS_IOC_FIRST];
@@ -6225,6 +6391,8 @@
vec->zvec_pool_check = pool_check;
vec->zvec_smush_outnvlist = smush_outnvlist;
vec->zvec_allow_log = allow_log;
+ vec->zvec_nvl_keys = nvl_keys;
+ vec->zvec_nvl_key_count = num_keys;
}
static void
@@ -6287,89 +6455,115 @@
{
zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
zfs_ioc_snapshot, zfs_secpolicy_snapshot, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_snapshot, ARRAY_SIZE(zfs_keys_snapshot));
zfs_ioctl_register("log_history", ZFS_IOC_LOG_HISTORY,
zfs_ioc_log_history, zfs_secpolicy_log_history, NO_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE,
+ zfs_keys_log_history, ARRAY_SIZE(zfs_keys_log_history));
zfs_ioctl_register("space_snaps", ZFS_IOC_SPACE_SNAPS,
zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME,
- POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
+ zfs_keys_space_snaps, ARRAY_SIZE(zfs_keys_space_snaps));
zfs_ioctl_register("send", ZFS_IOC_SEND_NEW,
zfs_ioc_send_new, zfs_secpolicy_send_new, DATASET_NAME,
- POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
+ zfs_keys_send_new, ARRAY_SIZE(zfs_keys_send_new));
zfs_ioctl_register("send_space", ZFS_IOC_SEND_SPACE,
zfs_ioc_send_space, zfs_secpolicy_read, DATASET_NAME,
- POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
+ zfs_keys_send_space, ARRAY_SIZE(zfs_keys_send_space));
zfs_ioctl_register("create", ZFS_IOC_CREATE,
zfs_ioc_create, zfs_secpolicy_create_clone, DATASET_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_create, ARRAY_SIZE(zfs_keys_create));
zfs_ioctl_register("clone", ZFS_IOC_CLONE,
zfs_ioc_clone, zfs_secpolicy_create_clone, DATASET_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_clone, ARRAY_SIZE(zfs_keys_clone));
zfs_ioctl_register("remap", ZFS_IOC_REMAP,
zfs_ioc_remap, zfs_secpolicy_remap, DATASET_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE,
+ zfs_keys_remap, ARRAY_SIZE(zfs_keys_remap));
zfs_ioctl_register("destroy_snaps", ZFS_IOC_DESTROY_SNAPS,
zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_destroy_snaps, ARRAY_SIZE(zfs_keys_destroy_snaps));
zfs_ioctl_register("hold", ZFS_IOC_HOLD,
zfs_ioc_hold, zfs_secpolicy_hold, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_hold, ARRAY_SIZE(zfs_keys_hold));
zfs_ioctl_register("release", ZFS_IOC_RELEASE,
zfs_ioc_release, zfs_secpolicy_release, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_release, ARRAY_SIZE(zfs_keys_release));
zfs_ioctl_register("get_holds", ZFS_IOC_GET_HOLDS,
zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME,
- POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
+ zfs_keys_get_holds, ARRAY_SIZE(zfs_keys_get_holds));
zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK,
zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE,
+ zfs_keys_rollback, ARRAY_SIZE(zfs_keys_rollback));
zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK,
zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_bookmark, ARRAY_SIZE(zfs_keys_bookmark));
zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS,
zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME,
- POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
+ zfs_keys_get_bookmarks, ARRAY_SIZE(zfs_keys_get_bookmarks));
zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS,
zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks,
POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_destroy_bookmarks,
+ ARRAY_SIZE(zfs_keys_destroy_bookmarks));
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);
+ B_TRUE, zfs_keys_channel_program,
+ ARRAY_SIZE(zfs_keys_channel_program));
zfs_ioctl_register("zpool_checkpoint", ZFS_IOC_POOL_CHECKPOINT,
zfs_ioc_pool_checkpoint, zfs_secpolicy_config, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_pool_checkpoint, ARRAY_SIZE(zfs_keys_pool_checkpoint));
zfs_ioctl_register("zpool_discard_checkpoint",
ZFS_IOC_POOL_DISCARD_CHECKPOINT, zfs_ioc_pool_discard_checkpoint,
zfs_secpolicy_config, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_pool_discard_checkpoint,
+ ARRAY_SIZE(zfs_keys_pool_discard_checkpoint));
zfs_ioctl_register("initialize", ZFS_IOC_POOL_INITIALIZE,
zfs_ioc_pool_initialize, zfs_secpolicy_config, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE,
+ zfs_keys_pool_initialize, ARRAY_SIZE(zfs_keys_pool_initialize));
zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC,
zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME,
- POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE,
+ zfs_keys_pool_sync, ARRAY_SIZE(zfs_keys_pool_sync));
+ zfs_ioctl_register("reopen", ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen,
+ zfs_secpolicy_config, POOL_NAME, POOL_CHECK_SUSPENDED, B_TRUE,
+ B_TRUE, zfs_keys_pool_reopen, ARRAY_SIZE(zfs_keys_pool_reopen));
/* IOCTLS that use the legacy function signature */
@@ -6443,8 +6637,6 @@
zfs_ioctl_register_pool(ZFS_IOC_CLEAR, zfs_ioc_clear,
zfs_secpolicy_config, B_TRUE, POOL_CHECK_READONLY);
- zfs_ioctl_register_pool(ZFS_IOC_POOL_REOPEN, zfs_ioc_pool_reopen,
- zfs_secpolicy_config, B_TRUE, POOL_CHECK_SUSPENDED);
zfs_ioctl_register_dataset_read(ZFS_IOC_SPACE_WRITTEN,
zfs_ioc_space_written);
@@ -6517,10 +6709,85 @@
zfs_secpolicy_config, POOL_CHECK_NONE);
zfs_ioctl_register("fbsd_nextboot", ZFS_IOC_NEXTBOOT,
zfs_ioc_nextboot, zfs_secpolicy_config, NO_NAME,
- POOL_CHECK_NONE, B_FALSE, B_FALSE);
+ POOL_CHECK_NONE, B_FALSE, B_FALSE,
+ zfs_keys_nextboot, ARRAY_SIZE(zfs_keys_nextboot));
#endif
}
+/*
+ * Verify that for non-legacy ioctls the input nvlist
+ * pairs match against the expected input.
+ *
+ * Possible errors are:
+ * ZFS_ERR_IOC_ARG_UNAVAIL An unrecognized nvpair was encountered
+ * ZFS_ERR_IOC_ARG_REQUIRED A required nvpair is missing
+ * ZFS_ERR_IOC_ARG_BADTYPE Invalid type for nvpair
+ */
+static int
+zfs_check_input_nvpairs(nvlist_t *innvl, const zfs_ioc_vec_t *vec)
+{
+ const zfs_ioc_key_t *nvl_keys = vec->zvec_nvl_keys;
+ boolean_t required_keys_found = B_FALSE;
+
+ /*
+ * examine each input pair
+ */
+ for (nvpair_t *pair = nvlist_next_nvpair(innvl, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
+ char *name = nvpair_name(pair);
+ data_type_t type = nvpair_type(pair);
+ boolean_t identified = B_FALSE;
+
+ /*
+ * check pair against the documented names and type
+ */
+ for (int k = 0; k < vec->zvec_nvl_key_count; k++) {
+ /* if not a wild card name, check for an exact match */
+ if ((nvl_keys[k].zkey_flags & ZK_WILDCARDLIST) == 0 &&
+ strcmp(nvl_keys[k].zkey_name, name) != 0)
+ continue;
+
+ identified = B_TRUE;
+
+ if (nvl_keys[k].zkey_type != DATA_TYPE_ANY &&
+ nvl_keys[k].zkey_type != type) {
+ return (SET_ERROR(ZFS_ERR_IOC_ARG_BADTYPE));
+ }
+
+ if (nvl_keys[k].zkey_flags & ZK_OPTIONAL)
+ continue;
+
+ required_keys_found = B_TRUE;
+ break;
+ }
+
+ /* allow an 'optional' key, everything else is invalid */
+ if (!identified &&
+ (strcmp(name, "optional") != 0 ||
+ type != DATA_TYPE_NVLIST)) {
+ return (SET_ERROR(ZFS_ERR_IOC_ARG_UNAVAIL));
+ }
+ }
+
+ /* verify that all required keys were found */
+ for (int k = 0; k < vec->zvec_nvl_key_count; k++) {
+ if (nvl_keys[k].zkey_flags & ZK_OPTIONAL)
+ continue;
+
+ if (nvl_keys[k].zkey_flags & ZK_WILDCARDLIST) {
+ /* at least one non-optionial key is expected here */
+ if (!required_keys_found)
+ return (SET_ERROR(ZFS_ERR_IOC_ARG_REQUIRED));
+ continue;
+ }
+
+ if (!nvlist_exists(innvl, nvl_keys[k].zkey_name))
+ return (SET_ERROR(ZFS_ERR_IOC_ARG_REQUIRED));
+ }
+
+ return (0);
+}
+
int
pool_status_check(const char *name, zfs_ioc_namecheck_t type,
zfs_ioc_poolcheck_t check)
@@ -6727,7 +6994,7 @@
#endif
if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
- return (SET_ERROR(EINVAL));
+ return (SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
vec = &zfs_ioc_vec[vecnum];
zc = kmem_zalloc(sizeof(zfs_cmd_t), KM_SLEEP);
@@ -6873,6 +7140,20 @@
case NO_NAME:
break;
+ }
+
+ /*
+ * Ensure that all input pairs are valid before we pass them down
+ * to the lower layers.
+ *
+ * The vectored functions can use fnvlist_lookup_{type} for any
+ * required pairs since zfs_check_input_nvpairs() confirmed that
+ * they exist and are of the correct type.
+ */
+ if (error == 0 && vec->zvec_func != NULL) {
+ error = zfs_check_input_nvpairs(innvl, vec);
+ if (error != 0)
+ goto out;
}
if (error == 0)
Index: head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
===================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
+++ head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
@@ -963,9 +963,19 @@
/*
* /dev/zfs ioctl numbers.
+ *
+ * These numbers cannot change over time. New ioctl numbers must be appended.
*/
typedef enum zfs_ioc {
+ /*
+ * Core features - 81/128 numbers reserved.
+ */
+#ifdef __FreeBSD__
ZFS_IOC_FIRST = 0,
+#else
+ ZFS_IOC_FIRST = ('Z' << 8),
+#endif
+ ZFS_IOC = ZFS_IOC_FIRST,
ZFS_IOC_POOL_CREATE = ZFS_IOC_FIRST,
ZFS_IOC_POOL_DESTROY,
ZFS_IOC_POOL_IMPORT,
@@ -1057,6 +1067,8 @@
* The enum implicitly includes all the error codes from errno.h.
* New code should use and extend this enum for errors that are
* not described precisely by generic errno codes.
+ *
+ * These numbers should not change over time. New entries should be appended.
*/
typedef enum {
ZFS_ERR_CHECKPOINT_EXISTS = 1024,
@@ -1064,6 +1076,10 @@
ZFS_ERR_NO_CHECKPOINT,
ZFS_ERR_DEVRM_IN_PROGRESS,
ZFS_ERR_VDEV_TOO_BIG,
+ ZFS_ERR_IOC_CMD_UNAVAIL,
+ ZFS_ERR_IOC_ARG_UNAVAIL,
+ ZFS_ERR_IOC_ARG_REQUIRED,
+ ZFS_ERR_IOC_ARG_BADTYPE,
ZFS_ERR_WRONG_PARENT,
} zfs_errno_t;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 28, 5:31 PM (4 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32295268
Default Alt Text
D25393.id.diff (37 KB)
Attached To
Mode
D25393: Openzfs #7780: Add basic zfs ioc input nvpair validation
Attached
Detach File
Event Timeline
Log In to Comment