13227e6cfSchs /*
23227e6cfSchs * CDDL HEADER SART
33227e6cfSchs *
43227e6cfSchs * The contents of this file are subject to the terms of the
53227e6cfSchs * Common Development and Distribution License (the "License").
63227e6cfSchs * You may not use this file except in compliance with the License.
73227e6cfSchs *
83227e6cfSchs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93227e6cfSchs * or http://www.opensolaris.org/os/licensing.
103227e6cfSchs * See the License for the specific language governing permissions
113227e6cfSchs * and limitations under the License.
123227e6cfSchs *
133227e6cfSchs * When distributing Covered Code, include this CDDL HEADER in each
143227e6cfSchs * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153227e6cfSchs * If applicable, add the following below this CDDL HEADER, with the
163227e6cfSchs * fields enclosed by brackets "[]" replaced with your own identifying
173227e6cfSchs * information: Portions Copyright [yyyy] [name of copyright owner]
183227e6cfSchs *
193227e6cfSchs * CDDL HEADER END
203227e6cfSchs */
213227e6cfSchs
223227e6cfSchs /*
233227e6cfSchs * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
243227e6cfSchs */
253227e6cfSchs
26*ba2539a9Schs #include <err.h>
27*ba2539a9Schs
283227e6cfSchs #include "libzfs_compat.h"
293227e6cfSchs
303227e6cfSchs int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
313227e6cfSchs static int zfs_spa_version = -1;
323227e6cfSchs
333227e6cfSchs /*
343227e6cfSchs * Get zfs_ioctl_version
353227e6cfSchs */
363227e6cfSchs int
get_zfs_ioctl_version(void)373227e6cfSchs get_zfs_ioctl_version(void)
383227e6cfSchs {
393227e6cfSchs size_t ver_size;
403227e6cfSchs int ver = ZFS_IOCVER_NONE;
413227e6cfSchs
423227e6cfSchs ver_size = sizeof(ver);
43*ba2539a9Schs if (sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0) < 0)
44*ba2539a9Schs err(1, "sysctl vfs.zfs.version.ioctl failed");
453227e6cfSchs
463227e6cfSchs return (ver);
473227e6cfSchs }
483227e6cfSchs
493227e6cfSchs /*
503227e6cfSchs * Get the SPA version
513227e6cfSchs */
523227e6cfSchs static int
get_zfs_spa_version(void)533227e6cfSchs get_zfs_spa_version(void)
543227e6cfSchs {
553227e6cfSchs size_t ver_size;
563227e6cfSchs int ver = 0;
573227e6cfSchs
583227e6cfSchs ver_size = sizeof(ver);
59*ba2539a9Schs if (sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0) < 0)
60*ba2539a9Schs err(1, "sysctl vfs.zfs.version.spa failed");
613227e6cfSchs
623227e6cfSchs return (ver);
633227e6cfSchs }
643227e6cfSchs
653227e6cfSchs /*
663227e6cfSchs * This is FreeBSD version of ioctl, because Solaris' ioctl() updates
673227e6cfSchs * zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
683227e6cfSchs * error is returned zc_nvlist_dst_size won't be updated.
693227e6cfSchs */
703227e6cfSchs int
zcmd_ioctl(int fd,int request,zfs_cmd_t * zc)713227e6cfSchs zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
723227e6cfSchs {
733227e6cfSchs size_t oldsize;
743227e6cfSchs int ret, cflag = ZFS_CMD_COMPAT_NONE;
753227e6cfSchs
763227e6cfSchs if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
773227e6cfSchs zfs_ioctl_version = get_zfs_ioctl_version();
783227e6cfSchs
793227e6cfSchs if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
803227e6cfSchs switch (zfs_ioctl_version) {
813227e6cfSchs case ZFS_IOCVER_RESUME:
823227e6cfSchs cflag = ZFS_CMD_COMPAT_RESUME;
833227e6cfSchs break;
843227e6cfSchs case ZFS_IOCVER_EDBP:
853227e6cfSchs cflag = ZFS_CMD_COMPAT_EDBP;
863227e6cfSchs break;
873227e6cfSchs case ZFS_IOCVER_ZCMD:
883227e6cfSchs cflag = ZFS_CMD_COMPAT_ZCMD;
893227e6cfSchs break;
903227e6cfSchs case ZFS_IOCVER_LZC:
913227e6cfSchs cflag = ZFS_CMD_COMPAT_LZC;
923227e6cfSchs break;
933227e6cfSchs case ZFS_IOCVER_DEADMAN:
943227e6cfSchs cflag = ZFS_CMD_COMPAT_DEADMAN;
953227e6cfSchs break;
963227e6cfSchs }
973227e6cfSchs } else {
983227e6cfSchs /*
993227e6cfSchs * If vfs.zfs.version.ioctl is not defined, assume we have v28
1003227e6cfSchs * compatible binaries and use vfs.zfs.version.spa to test for v15
1013227e6cfSchs */
1023227e6cfSchs cflag = ZFS_CMD_COMPAT_V28;
1033227e6cfSchs
1043227e6cfSchs if (zfs_spa_version < 0)
1053227e6cfSchs zfs_spa_version = get_zfs_spa_version();
1063227e6cfSchs
1073227e6cfSchs if (zfs_spa_version == SPA_VERSION_15 ||
1083227e6cfSchs zfs_spa_version == SPA_VERSION_14 ||
1093227e6cfSchs zfs_spa_version == SPA_VERSION_13)
1103227e6cfSchs cflag = ZFS_CMD_COMPAT_V15;
1113227e6cfSchs }
1123227e6cfSchs
1133227e6cfSchs oldsize = zc->zc_nvlist_dst_size;
1143227e6cfSchs ret = zcmd_ioctl_compat(fd, request, zc, cflag);
1153227e6cfSchs
1163227e6cfSchs if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
1173227e6cfSchs ret = -1;
1183227e6cfSchs errno = ENOMEM;
1193227e6cfSchs }
1203227e6cfSchs
1213227e6cfSchs return (ret);
1223227e6cfSchs }
123