mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
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: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Don Brady <don.brady@delphix.com>
Closes #7780
This commit is contained in:
committed by
Brian Behlendorf
parent
e8bcb693d6
commit
b83a0e2dc1
@@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, Joyent, Inc. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
@@ -227,6 +227,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"));
|
||||
@@ -445,6 +448,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);
|
||||
@@ -556,6 +575,22 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
case ZFS_ERR_VDEV_TOO_BIG:
|
||||
zfs_verror(hdl, EZFS_VDEV_TOO_BIG, 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);
|
||||
|
||||
@@ -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) 2017 Datto Inc.
|
||||
* Copyright 2017 RackTop Systems.
|
||||
@@ -78,6 +78,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>
|
||||
@@ -91,6 +94,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)
|
||||
{
|
||||
@@ -103,6 +142,10 @@ libzfs_core_init(void)
|
||||
}
|
||||
}
|
||||
g_refcount++;
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
libzfs_core_debug_ioc();
|
||||
#endif
|
||||
(void) pthread_mutex_unlock(&g_lock);
|
||||
return (0);
|
||||
}
|
||||
@@ -135,6 +178,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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user