From bb508e7732e285bcce70a43c900c58ee16e3c465 Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Fri, 1 Mar 2013 09:42:58 +0000 Subject: [PATCH] Fix the zfs_ioctl compat layer to support zfs_cmd size change introduced in r247265 (ZFS deadman thread). Both new utilities now support the old kernel and new kernel properly detects old utilities. For future backwards compatibility, the vfs.zfs.version.ioctl read-only sysctl has been introduced. With this sysctl zfs utilities will be able to detect the ioctl interface version of the currently loaded zfs module. As a side effect, the zfs utilities between r247265 and this revision don't support the old kernel module. If you are using HEAD newer or equal than r247265, install the new kernel module (or whole kernel) first. MFC after: 10 days --- .../lib/libzfs/common/libzfs_impl.h | 35 ++- .../opensolaris/common/zfs/zfs_ioctl_compat.c | 207 +++++++++++++++--- .../opensolaris/common/zfs/zfs_ioctl_compat.h | 74 ++++++- .../opensolaris/uts/common/fs/zfs/zfs_ioctl.c | 17 +- 4 files changed, 288 insertions(+), 45 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h index 1c46d32f4bab..be07187f9d5e 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h @@ -24,6 +24,7 @@ * Copyright (c) 2011 Pawel Jakub Dawidek . * All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2013 Martin Matuska . All rights reserved. */ #ifndef _LIBFS_IMPL_H @@ -216,6 +217,7 @@ extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t); #ifndef sun static int zfs_kernel_version = 0; +static int zfs_ioctl_version = 0; /* * This is FreeBSD version of ioctl, because Solaris' ioctl() updates @@ -225,19 +227,34 @@ static int zfs_kernel_version = 0; static __inline int zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc) { - size_t oldsize, zfs_kernel_version_size; + size_t oldsize, zfs_kernel_version_size, zfs_ioctl_version_size; int version, ret, cflag = ZFS_CMD_COMPAT_NONE; - zfs_kernel_version_size = sizeof(zfs_kernel_version); - if (zfs_kernel_version == 0) { - sysctlbyname("vfs.zfs.version.spa", &zfs_kernel_version, - &zfs_kernel_version_size, NULL, 0); + zfs_ioctl_version_size = sizeof(zfs_ioctl_version); + if (zfs_ioctl_version == 0) { + sysctlbyname("vfs.zfs.version.ioctl", &zfs_ioctl_version, + &zfs_ioctl_version_size, NULL, 0); } - if (zfs_kernel_version == SPA_VERSION_15 || - zfs_kernel_version == SPA_VERSION_14 || - zfs_kernel_version == SPA_VERSION_13) - cflag = ZFS_CMD_COMPAT_V15; + /* + * If vfs.zfs.version.ioctl is not defined, assume we have v28 + * compatible binaries and use vfs.zfs.version.spa to test for v15 + */ + if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) { + cflag = ZFS_CMD_COMPAT_V28; + zfs_kernel_version_size = sizeof(zfs_kernel_version); + + if (zfs_kernel_version == 0) { + sysctlbyname("vfs.zfs.version.spa", + &zfs_kernel_version, + &zfs_kernel_version_size, NULL, 0); + } + + if (zfs_kernel_version == SPA_VERSION_15 || + zfs_kernel_version == SPA_VERSION_14 || + zfs_kernel_version == SPA_VERSION_13) + cflag = ZFS_CMD_COMPAT_V15; + } oldsize = zc->zc_nvlist_dst_size; ret = zcmd_ioctl_compat(fd, cmd, zc, cflag); diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c index 0b43c7869e7b..4959335409b1 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Martin Matuska . All rights reserved. + * Copyright 2013 Martin Matuska . All rights reserved. * Portions Copyright 2005, 2010, Oracle and/or its affiliates. * All rights reserved. * Use is subject to license terms. @@ -35,22 +35,100 @@ #include #include "zfs_ioctl_compat.h" +static int zfs_version_ioctl = ZFS_IOCVER_CURRENT; +SYSCTL_DECL(_vfs_zfs_version); +SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl, + 0, "ZFS_IOCTL_VERSION"); + /* - * FreeBSD zfs_cmd compatibility with v15 and older binaries + * FreeBSD zfs_cmd compatibility with older binaries * appropriately remap/extend the zfs_cmd_t structure */ void zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) { zfs_cmd_v15_t *zc_c; + zfs_cmd_v28_t *zc28_c; - if (cflag == ZFS_CMD_COMPAT_V15) { + switch (cflag) { + case ZFS_CMD_COMPAT_V28: + zc28_c = (void *)addr; + + /* zc */ + strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN); + strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2); + strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN); + strlcpy(zc->zc_top_ds, zc28_c->zc_top_ds, MAXPATHLEN); + zc->zc_guid = zc28_c->zc_guid; + zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf; + zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size; + zc->zc_nvlist_src = zc28_c->zc_nvlist_src; + zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size; + zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst; + zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size; + zc->zc_cookie = zc28_c->zc_cookie; + zc->zc_objset_type = zc28_c->zc_objset_type; + zc->zc_perm_action = zc28_c->zc_perm_action; + zc->zc_history = zc28_c->zc_history; + zc->zc_history_len = zc28_c->zc_history_len; + zc->zc_history_offset = zc28_c->zc_history_offset; + zc->zc_obj = zc28_c->zc_obj; + zc->zc_iflags = zc28_c->zc_iflags; + zc->zc_share = zc28_c->zc_share; + zc->zc_jailid = zc28_c->zc_jailid; + zc->zc_objset_stats = zc28_c->zc_objset_stats; + zc->zc_begin_record = zc28_c->zc_begin_record; + zc->zc_defer_destroy = zc28_c->zc_defer_destroy; + zc->zc_temphold = zc28_c->zc_temphold; + zc->zc_action_handle = zc28_c->zc_action_handle; + zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd; + zc->zc_simple = zc28_c->zc_simple; + bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); + zc->zc_sendobj = zc28_c->zc_sendobj; + zc->zc_fromobj = zc28_c->zc_fromobj; + zc->zc_createtxg = zc28_c->zc_createtxg; + zc->zc_stat = zc28_c->zc_stat; + + /* zc->zc_inject_record */ + zc->zc_inject_record.zi_objset = + zc28_c->zc_inject_record.zi_objset; + zc->zc_inject_record.zi_object = + zc28_c->zc_inject_record.zi_object; + zc->zc_inject_record.zi_start = + zc28_c->zc_inject_record.zi_start; + zc->zc_inject_record.zi_end = + zc28_c->zc_inject_record.zi_end; + zc->zc_inject_record.zi_guid = + zc28_c->zc_inject_record.zi_guid; + zc->zc_inject_record.zi_level = + zc28_c->zc_inject_record.zi_level; + zc->zc_inject_record.zi_error = + zc28_c->zc_inject_record.zi_error; + zc->zc_inject_record.zi_type = + zc28_c->zc_inject_record.zi_type; + zc->zc_inject_record.zi_freq = + zc28_c->zc_inject_record.zi_freq; + zc->zc_inject_record.zi_failfast = + zc28_c->zc_inject_record.zi_failfast; + strlcpy(zc->zc_inject_record.zi_func, + zc28_c->zc_inject_record.zi_func, MAXNAMELEN); + zc->zc_inject_record.zi_iotype = + zc28_c->zc_inject_record.zi_iotype; + zc->zc_inject_record.zi_duration = + zc28_c->zc_inject_record.zi_duration; + zc->zc_inject_record.zi_timer = + zc28_c->zc_inject_record.zi_timer; + zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED; + zc->zc_inject_record.zi_pad = 0; + break; + + case ZFS_CMD_COMPAT_V15: zc_c = (void *)addr; /* zc */ - strlcpy(zc->zc_name,zc_c->zc_name,MAXPATHLEN); - strlcpy(zc->zc_value,zc_c->zc_value,MAXPATHLEN); - strlcpy(zc->zc_string,zc_c->zc_string,MAXPATHLEN); + strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN); + strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN); + strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN); zc->zc_guid = zc_c->zc_guid; zc->zc_nvlist_conf = zc_c->zc_nvlist_conf; zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size; @@ -91,6 +169,7 @@ zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) zc_c->zc_inject_record.zi_freq; zc->zc_inject_record.zi_failfast = zc_c->zc_inject_record.zi_failfast; + break; } } @@ -98,15 +177,84 @@ void zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int cflag) { zfs_cmd_v15_t *zc_c; + zfs_cmd_v28_t *zc28_c; switch (cflag) { + case ZFS_CMD_COMPAT_V28: + zc28_c = (void *)addr; + + strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN); + strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2); + strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN); + strlcpy(zc28_c->zc_top_ds, zc->zc_top_ds, MAXPATHLEN); + zc28_c->zc_guid = zc->zc_guid; + zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf; + zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; + zc28_c->zc_nvlist_src = zc->zc_nvlist_src; + zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; + zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst; + zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; + zc28_c->zc_cookie = zc->zc_cookie; + zc28_c->zc_objset_type = zc->zc_objset_type; + zc28_c->zc_perm_action = zc->zc_perm_action; + zc28_c->zc_history = zc->zc_history; + zc28_c->zc_history_len = zc->zc_history_len; + zc28_c->zc_history_offset = zc->zc_history_offset; + zc28_c->zc_obj = zc->zc_obj; + zc28_c->zc_iflags = zc->zc_iflags; + zc28_c->zc_share = zc->zc_share; + zc28_c->zc_jailid = zc->zc_jailid; + zc28_c->zc_objset_stats = zc->zc_objset_stats; + zc28_c->zc_begin_record = zc->zc_begin_record; + zc28_c->zc_defer_destroy = zc->zc_defer_destroy; + zc28_c->zc_temphold = zc->zc_temphold; + zc28_c->zc_action_handle = zc->zc_action_handle; + zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd; + zc28_c->zc_simple = zc->zc_simple; + bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad)); + zc28_c->zc_sendobj = zc->zc_sendobj; + zc28_c->zc_fromobj = zc->zc_fromobj; + zc28_c->zc_createtxg = zc->zc_createtxg; + zc28_c->zc_stat = zc->zc_stat; + + /* zc_inject_record */ + zc28_c->zc_inject_record.zi_objset = + zc->zc_inject_record.zi_objset; + zc28_c->zc_inject_record.zi_object = + zc->zc_inject_record.zi_object; + zc28_c->zc_inject_record.zi_start = + zc->zc_inject_record.zi_start; + zc28_c->zc_inject_record.zi_end = + zc->zc_inject_record.zi_end; + zc28_c->zc_inject_record.zi_guid = + zc->zc_inject_record.zi_guid; + zc28_c->zc_inject_record.zi_level = + zc->zc_inject_record.zi_level; + zc28_c->zc_inject_record.zi_error = + zc->zc_inject_record.zi_error; + zc28_c->zc_inject_record.zi_type = + zc->zc_inject_record.zi_type; + zc28_c->zc_inject_record.zi_freq = + zc->zc_inject_record.zi_freq; + zc28_c->zc_inject_record.zi_failfast = + zc->zc_inject_record.zi_failfast; + strlcpy(zc28_c->zc_inject_record.zi_func, + zc->zc_inject_record.zi_func, MAXNAMELEN); + zc28_c->zc_inject_record.zi_iotype = + zc->zc_inject_record.zi_iotype; + zc28_c->zc_inject_record.zi_duration = + zc->zc_inject_record.zi_duration; + zc28_c->zc_inject_record.zi_timer = + zc->zc_inject_record.zi_timer; + break; + case ZFS_CMD_COMPAT_V15: zc_c = (void *)addr; /* zc */ - strlcpy(zc_c->zc_name,zc->zc_name,MAXPATHLEN); - strlcpy(zc_c->zc_value,zc->zc_value,MAXPATHLEN); - strlcpy(zc_c->zc_string,zc->zc_string,MAXPATHLEN); + strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN); + strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN); + strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN); zc_c->zc_guid = zc->zc_guid; zc_c->zc_nvlist_conf = zc->zc_nvlist_conf; zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; @@ -260,7 +408,7 @@ zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl) } static int -zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int cflag) +zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc) { nvlist_t *nv, *nvp = NULL; nvpair_t *elem; @@ -270,7 +418,7 @@ zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int cflag) zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) return (error); - if (cflag == 5) { /* ZFS_IOC_POOL_STATS */ + if (nc == 5) { /* ZFS_IOC_POOL_STATS */ elem = NULL; while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) { if (nvpair_value_nvlist(elem, &nvp) == 0) @@ -334,17 +482,22 @@ zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag) void *zc_c; unsigned long ncmd; - if (cflag == ZFS_CMD_COMPAT_NONE) { + switch (cflag) { + case ZFS_CMD_COMPAT_NONE: ret = ioctl(fd, cmd, zc); return (ret); - } - - if (cflag == ZFS_CMD_COMPAT_V15) { + case ZFS_CMD_COMPAT_V28: + zc_c = malloc(sizeof(zfs_cmd_v28_t)); + ncmd = _IOWR('Z', ZFS_IOC(cmd), struct zfs_cmd_v28); + break; + case ZFS_CMD_COMPAT_V15: nc = zfs_ioctl_v28_to_v15[ZFS_IOC(cmd)]; zc_c = malloc(sizeof(zfs_cmd_v15_t)); ncmd = _IOWR('Z', nc, struct zfs_cmd_v15); - } else + break; + default: return (EINVAL); + } if (ZFS_IOC(ncmd) == ZFS_IOC_COMPAT_FAIL) return (ENOTSUP); @@ -358,16 +511,18 @@ zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag) zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag); free(zc_c); - switch (nc) { - case 2: /* ZFS_IOC_POOL_IMPORT */ - case 4: /* ZFS_IOC_POOL_CONFIGS */ - case 5: /* ZFS_IOC_POOL_STATS */ - case 6: /* ZFS_IOC_POOL_TRYIMPORT */ - zfs_ioctl_compat_fix_stats(zc, nc); - break; - case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ - zfs_ioctl_compat_pool_get_props(zc); - break; + if (cflag == ZFS_CMD_COMPAT_V15) { + switch (nc) { + case 2: /* ZFS_IOC_POOL_IMPORT */ + case 4: /* ZFS_IOC_POOL_CONFIGS */ + case 5: /* ZFS_IOC_POOL_STATS */ + case 6: /* ZFS_IOC_POOL_TRYIMPORT */ + zfs_ioctl_compat_fix_stats(zc, nc); + break; + case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ + zfs_ioctl_compat_pool_get_props(zc); + break; + } } return (ret); diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h index 03d648c9ea18..b20cecafc74b 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Martin Matuska . All rights reserved. + * Copyright 2013 Martin Matuska . All rights reserved. * Use is subject to license terms. */ @@ -40,11 +40,21 @@ extern "C" { #endif -#define ZFS_CMD_COMPAT_NONE 0 -#define ZFS_CMD_COMPAT_V15 1 +/* + * Backwards ioctl compatibility + */ -#define ZFS_IOC_COMPAT_PASS 254 -#define ZFS_IOC_COMPAT_FAIL 255 +/* ioctl versions for vfs.zfs.version.ioctl */ +#define ZFS_IOCVER_DEADMAN 1 +#define ZFS_IOCVER_CURRENT ZFS_IOCVER_DEADMAN + +/* compatibility conversion flag */ +#define ZFS_CMD_COMPAT_NONE 0 +#define ZFS_CMD_COMPAT_V15 1 +#define ZFS_CMD_COMPAT_V28 2 + +#define ZFS_IOC_COMPAT_PASS 254 +#define ZFS_IOC_COMPAT_FAIL 255 typedef struct zinject_record_v15 { uint64_t zi_objset; @@ -84,6 +94,60 @@ typedef struct zfs_cmd_v15 { zinject_record_v15_t zc_inject_record; } zfs_cmd_v15_t; +typedef struct zinject_record_v28 { + uint64_t zi_objset; + uint64_t zi_object; + uint64_t zi_start; + uint64_t zi_end; + uint64_t zi_guid; + uint32_t zi_level; + uint32_t zi_error; + uint64_t zi_type; + uint32_t zi_freq; + uint32_t zi_failfast; + char zi_func[MAXNAMELEN]; + uint32_t zi_iotype; + int32_t zi_duration; + uint64_t zi_timer; +} zinject_record_v28_t; + +typedef struct zfs_cmd_v28 { + char zc_name[MAXPATHLEN]; + char zc_value[MAXPATHLEN * 2]; + char zc_string[MAXNAMELEN]; + char zc_top_ds[MAXPATHLEN]; + uint64_t zc_guid; + uint64_t zc_nvlist_conf; /* really (char *) */ + uint64_t zc_nvlist_conf_size; + uint64_t zc_nvlist_src; /* really (char *) */ + uint64_t zc_nvlist_src_size; + uint64_t zc_nvlist_dst; /* really (char *) */ + uint64_t zc_nvlist_dst_size; + uint64_t zc_cookie; + uint64_t zc_objset_type; + uint64_t zc_perm_action; + uint64_t zc_history; /* really (char *) */ + uint64_t zc_history_len; + uint64_t zc_history_offset; + uint64_t zc_obj; + uint64_t zc_iflags; /* internal to zfs(7fs) */ + zfs_share_t zc_share; + uint64_t zc_jailid; + dmu_objset_stats_t zc_objset_stats; + struct drr_begin zc_begin_record; + zinject_record_v28_t zc_inject_record; + boolean_t zc_defer_destroy; + boolean_t zc_temphold; + uint64_t zc_action_handle; + int zc_cleanup_fd; + uint8_t zc_simple; + uint8_t zc_pad[3]; /* alignment */ + uint64_t zc_sendobj; + uint64_t zc_fromobj; + uint64_t zc_createtxg; + zfs_stat_t zc_stat; +} zfs_cmd_v28_t; + #ifdef _KERNEL unsigned static long zfs_ioctl_v15_to_v28[] = { 0, /* 0 ZFS_IOC_POOL_CREATE */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index 9925a3bb50c3..af0c9f75d337 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -23,7 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek . * All rights reserved. - * Portions Copyright 2011 Martin Matuska + * Copyright 2013 Martin Matuska . All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. @@ -5331,12 +5331,14 @@ zfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, len = IOCPARM_LEN(cmd); /* - * Check if we have sufficient kernel memory allocated - * for the zfs_cmd_t request. Bail out if not so we - * will not access undefined memory region. + * Check if we are talking to supported older binaries + * and translate zfs_cmd if necessary */ if (len < sizeof(zfs_cmd_t)) - if (len == sizeof(zfs_cmd_v15_t)) { + if (len == sizeof(zfs_cmd_v28_t)) { + cflag = ZFS_CMD_COMPAT_V28; + vec = ZFS_IOC(cmd); + } else if (len == sizeof(zfs_cmd_v15_t)) { cflag = ZFS_CMD_COMPAT_V15; vec = zfs_ioctl_v15_to_v28[ZFS_IOC(cmd)]; } else @@ -5351,6 +5353,11 @@ zfsdev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, return (ENOTSUP); } + /* + * Check if we have sufficient kernel memory allocated + * for the zfs_cmd_t request. Bail out if not so we + * will not access undefined memory region. + */ if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) return (EINVAL);