diff options
author | Toomas Soome <tsoome@FreeBSD.org> | 2020-06-23 06:42:39 +0000 |
---|---|---|
committer | Toomas Soome <tsoome@FreeBSD.org> | 2020-06-23 06:42:39 +0000 |
commit | a14844e0d67a69239e522de342c6690428edccd0 (patch) | |
tree | 6597aa42b3e2b571f966faa50d16d1c39e35c7c7 /cddl/contrib/opensolaris/lib | |
parent | b40dd828bdc96959cf5fa90d02fc00d96c54fbe4 (diff) | |
download | src-a14844e0d67a69239e522de342c6690428edccd0.tar.gz src-a14844e0d67a69239e522de342c6690428edccd0.zip |
MFOpenZFS: Add basic zfs ioc input nvpair validation
We want newer versions of libzfs_core to run against an existing
zfs kernel module (i.e. a deferred reboot or module reload after
an update).
Programmatically document, via a zfs_ioc_key_t, the valid arguments
for the ioc commands that rely on nvpair input arguments (i.e. non
legacy commands from libzfs_core). Automatically verify the expected
pairs before dispatching a command.
This initial phase focuses on the non-legacy ioctls. A follow-on
change can address the legacy ioctl input from the zfs_cmd_t.
The zfs_ioc_key_t for zfs_keys_channel_program looks like:
static const zfs_ioc_key_t zfs_keys_channel_program[] = {
{"program", DATA_TYPE_STRING, 0},
{"arg", DATA_TYPE_UNKNOWN, 0},
{"sync", DATA_TYPE_BOOLEAN_VALUE, ZK_OPTIONAL},
{"instrlimit", DATA_TYPE_UINT64, ZK_OPTIONAL},
{"memlimit", DATA_TYPE_UINT64, ZK_OPTIONAL},
};
Introduce four input errors to identify specific input failures
(in addition to generic argument value errors like EINVAL, ERANGE,
EBADF, and E2BIG).
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
Reviewed by: allanjude
Obtained from: OpenZFS
Sponsored by: Netflix, Klara Inc.
Differential Revision: https://reviews.freebsd.org/D25393
Notes
Notes:
svn path=/head/; revision=362531
Diffstat (limited to 'cddl/contrib/opensolaris/lib')
3 files changed, 87 insertions, 3 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 7d67f9463a1f..7be49cb7e4e0 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/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 @@ typedef enum zfs_error { 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; diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c index e69467397fc8..4439bcbbee57 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c +++ b/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 @@ libzfs_error_description(libzfs_handle_t *hdl) 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 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) 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); @@ -542,6 +561,22 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) 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)); zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap); diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c index cd5767e69b9b..f4ed52a29232 100644 --- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c +++ b/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 int g_fd = -1; 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 @@ libzfs_core_init(void) } } g_refcount++; + +#ifdef ZFS_DEBUG + libzfs_core_debug_ioc(); +#endif (void) pthread_mutex_unlock(&g_lock); return (0); @@ -147,6 +190,11 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name, 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)); |