xref: /netbsd-src/external/cddl/osnet/dist/lib/libzfs/common/libzfs_compat.c (revision ba2539a9805a0544ff82c0003cc02fe1eee5603d)
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