1248461Smm/* 2248461Smm * CDDL HEADER SART 3248461Smm * 4248461Smm * The contents of this file are subject to the terms of the 5248461Smm * Common Development and Distribution License (the "License"). 6248461Smm * You may not use this file except in compliance with the License. 7248461Smm * 8248461Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9248461Smm * or http://www.opensolaris.org/os/licensing. 10248461Smm * See the License for the specific language governing permissions 11248461Smm * and limitations under the License. 12248461Smm * 13248461Smm * When distributing Covered Code, include this CDDL HEADER in each 14248461Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15248461Smm * If applicable, add the following below this CDDL HEADER, with the 16248461Smm * fields enclosed by brackets "[]" replaced with your own identifying 17248461Smm * information: Portions Copyright [yyyy] [name of copyright owner] 18248461Smm * 19248461Smm * CDDL HEADER END 20248461Smm */ 21248461Smm 22248461Smm/* 23248461Smm * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 24248461Smm */ 25248461Smm 26248461Smm#include "libzfs_compat.h" 27248461Smm 28248461Smmint zfs_ioctl_version = ZFS_IOCVER_UNDEF; 29248461Smmstatic int zfs_spa_version = -1; 30248461Smm 31248461Smm/* 32248461Smm * Get zfs_ioctl_version 33248461Smm */ 34248461Smmint 35248461Smmget_zfs_ioctl_version(void) 36248461Smm{ 37248461Smm size_t ver_size; 38248461Smm int ver = ZFS_IOCVER_NONE; 39248461Smm 40248461Smm ver_size = sizeof(ver); 41248461Smm sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0); 42248461Smm 43248461Smm return (ver); 44248461Smm} 45248461Smm 46248461Smm/* 47248461Smm * Get the SPA version 48248461Smm */ 49248461Smmstatic int 50248461Smmget_zfs_spa_version(void) 51248461Smm{ 52248461Smm size_t ver_size; 53248461Smm int ver = 0; 54248461Smm 55248461Smm ver_size = sizeof(ver); 56248461Smm sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0); 57248461Smm 58248461Smm return (ver); 59248461Smm} 60248461Smm 61248461Smm/* 62248461Smm * This is FreeBSD version of ioctl, because Solaris' ioctl() updates 63248461Smm * zc_nvlist_dst_size even if an error is returned, on FreeBSD if an 64248461Smm * error is returned zc_nvlist_dst_size won't be updated. 65248461Smm */ 66248461Smmint 67248461Smmzcmd_ioctl(int fd, int request, zfs_cmd_t *zc) 68248461Smm{ 69248461Smm size_t oldsize; 70248461Smm int ret, cflag = ZFS_CMD_COMPAT_NONE; 71248461Smm 72248461Smm if (zfs_ioctl_version == ZFS_IOCVER_UNDEF) 73248461Smm zfs_ioctl_version = get_zfs_ioctl_version(); 74248461Smm 75268786Sdelphij if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) { 76268786Sdelphij switch (zfs_ioctl_version) { 77322079Smav case ZFS_IOCVER_INLANES: 78322079Smav cflag = ZFS_CMD_COMPAT_INLANES; 79322079Smav break; 80297108Smav case ZFS_IOCVER_RESUME: 81297108Smav cflag = ZFS_CMD_COMPAT_RESUME; 82297108Smav break; 83290756Smav case ZFS_IOCVER_EDBP: 84290756Smav cflag = ZFS_CMD_COMPAT_EDBP; 85290756Smav break; 86268786Sdelphij case ZFS_IOCVER_ZCMD: 87268786Sdelphij cflag = ZFS_CMD_COMPAT_ZCMD; 88268786Sdelphij break; 89268786Sdelphij case ZFS_IOCVER_LZC: 90268786Sdelphij cflag = ZFS_CMD_COMPAT_LZC; 91268786Sdelphij break; 92268786Sdelphij case ZFS_IOCVER_DEADMAN: 93268786Sdelphij cflag = ZFS_CMD_COMPAT_DEADMAN; 94268786Sdelphij break; 95268786Sdelphij } 96268786Sdelphij } else { 97268786Sdelphij /* 98268786Sdelphij * If vfs.zfs.version.ioctl is not defined, assume we have v28 99268786Sdelphij * compatible binaries and use vfs.zfs.version.spa to test for v15 100268786Sdelphij */ 101248461Smm cflag = ZFS_CMD_COMPAT_V28; 102248461Smm 103248461Smm if (zfs_spa_version < 0) 104248461Smm zfs_spa_version = get_zfs_spa_version(); 105248461Smm 106248461Smm if (zfs_spa_version == SPA_VERSION_15 || 107248461Smm zfs_spa_version == SPA_VERSION_14 || 108248461Smm zfs_spa_version == SPA_VERSION_13) 109248461Smm cflag = ZFS_CMD_COMPAT_V15; 110248461Smm } 111248461Smm 112248461Smm oldsize = zc->zc_nvlist_dst_size; 113248461Smm ret = zcmd_ioctl_compat(fd, request, zc, cflag); 114248461Smm 115248461Smm if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) { 116248461Smm ret = -1; 117248461Smm errno = ENOMEM; 118248461Smm } 119248461Smm 120248461Smm return (ret); 121248461Smm} 122