Move common zfs ioctl compatibility functions (userland) into libzfs_compat.c

Introduce additional constants for zfs ioctl versions
This commit is contained in:
Martin Matuska 2013-03-18 09:32:29 +00:00
parent d97b41582d
commit 6f4accc2de
7 changed files with 125 additions and 77 deletions

View File

@ -0,0 +1,103 @@
/*
* CDDL HEADER SART
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#include "libzfs_compat.h"
int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
static int zfs_spa_version = -1;
/*
* Get zfs_ioctl_version
*/
int
get_zfs_ioctl_version(void)
{
size_t ver_size;
int ver = ZFS_IOCVER_NONE;
ver_size = sizeof(ver);
sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
return (ver);
}
/*
* Get the SPA version
*/
static int
get_zfs_spa_version(void)
{
size_t ver_size;
int ver = 0;
ver_size = sizeof(ver);
sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0);
return (ver);
}
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
* error is returned zc_nvlist_dst_size won't be updated.
*/
int
zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
{
size_t oldsize;
int ret, cflag = ZFS_CMD_COMPAT_NONE;
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN)
cflag = ZFS_CMD_COMPAT_DEADMAN;
/*
* 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;
if (zfs_spa_version < 0)
zfs_spa_version = get_zfs_spa_version();
if (zfs_spa_version == SPA_VERSION_15 ||
zfs_spa_version == SPA_VERSION_14 ||
zfs_spa_version == SPA_VERSION_13)
cflag = ZFS_CMD_COMPAT_V15;
}
oldsize = zc->zc_nvlist_dst_size;
ret = zcmd_ioctl_compat(fd, request, zc, cflag);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
errno = ENOMEM;
}
return (ret);
}

View File

@ -32,71 +32,9 @@
extern "C" {
#endif
static int zfs_ioctl_version = -1;
static int zfs_kernel_version = 0;
int get_zfs_ioctl_version(void);
int zcmd_ioctl(int fd, int request, zfs_cmd_t *zc);
/*
* Get zfs_ioctl_version
*/
static __inline int
get_zfs_ioctl_version(void)
{
size_t ver_size;
int ver = 0;
ver_size = sizeof(ver);
sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
return (ver);
}
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
* error is returned zc_nvlist_dst_size won't be updated.
*/
static __inline int
zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
{
size_t oldsize, zfs_kernel_version_size;
int version, ret, cflag = ZFS_CMD_COMPAT_NONE;
if (zfs_ioctl_version == -1)
zfs_ioctl_version = get_zfs_ioctl_version();
if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN)
cflag = ZFS_CMD_COMPAT_DEADMAN;
/*
* 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, request, zc, cflag);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
errno = ENOMEM;
}
return (ret);
}
#define ioctl(fd, ioc, zc) zcmd_ioctl((fd), (ioc), (zc))
#ifdef __cplusplus

View File

@ -88,7 +88,7 @@
#include "libzfs_compat.h"
#ifdef __FreeBSD__
int lzc_ioctl_version = -1;
extern int zfs_ioctl_version;
#endif
static int g_fd;
@ -140,10 +140,10 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
#ifdef __FreeBSD__
if (lzc_ioctl_version == -1)
lzc_ioctl_version = get_zfs_ioctl_version();
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
if (lzc_ioctl_version < ZFS_IOCVER_LZC) {
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
oldsource = source;
error = lzc_compat_pre(&zc, &ioc, &source);
if (error)
@ -190,7 +190,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
}
#ifdef __FreeBSD__
if (lzc_ioctl_version < ZFS_IOCVER_LZC)
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_post(&zc, ioc);
#endif
if (zc.zc_nvlist_dst_filled) {
@ -200,12 +200,12 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
*resultp = NULL;
}
#ifdef __FreeBSD__
if (lzc_ioctl_version < ZFS_IOCVER_LZC)
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_outnvl(&zc, ioc, resultp);
#endif
out:
#ifdef __FreeBSD__
if (lzc_ioctl_version < ZFS_IOCVER_LZC) {
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
if (source != oldsource)
nvlist_free(source);
source = oldsource;

View File

@ -27,7 +27,7 @@
#include <zfs_ioctl_compat.h>
#include "libzfs_core_compat.h"
extern int lzc_ioctl_version;
extern int zfs_ioctl_version;
int
lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
@ -40,7 +40,7 @@ lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
int error = 0;
int pos;
if (lzc_ioctl_version >= ZFS_IOCVER_LZC)
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
vecnum = *ioc;
@ -99,7 +99,7 @@ lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
void
lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
{
if (lzc_ioctl_version >= ZFS_IOCVER_LZC)
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return;
switch (ioc) {
@ -118,7 +118,7 @@ lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
{
nvlist_t *nvl;
if (lzc_ioctl_version >= ZFS_IOCVER_LZC)
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
switch (ioc) {

View File

@ -18,6 +18,7 @@ SRCS= deviceid.c \
zone.c
SRCS+= libzfs_changelist.c \
libzfs_compat.c \
libzfs_config.c \
libzfs_dataset.c \
libzfs_diff.c \

View File

@ -4,12 +4,16 @@
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
LIB= zfs_core
DPADD= ${LIBNVPAIR}
LDADD= -lnvpair
SRCS= libzfs_core.c libzfs_core_compat.c
SRCS= libzfs_core.c \
libzfs_core_compat.c
SRCS+= libzfs_compat.c
WARNS?= 0
CSTD= c99

View File

@ -45,8 +45,10 @@ extern "C" {
*/
/* ioctl versions for vfs.zfs.version.ioctl */
#define ZFS_IOCVER_LZC 2
#define ZFS_IOCVER_UNDEF -1
#define ZFS_IOCVER_NONE 0
#define ZFS_IOCVER_DEADMAN 1
#define ZFS_IOCVER_LZC 2
#define ZFS_IOCVER_CURRENT ZFS_IOCVER_LZC
/* compatibility conversion flag */