Add forwards compatibility for libzfs_core

Unsupported: creation of multiple snapshots including "zfs snapshot -r"
This commit is contained in:
Martin Matuska 2013-03-17 18:33:06 +00:00
parent 70b0720877
commit 67ebc12d49
5 changed files with 217 additions and 2 deletions

View File

@ -86,6 +86,10 @@
#include <sys/zfs_ioctl.h>
#include <libzfs_compat.h>
#ifdef __FreeBSD__
extern int zfs_ioctl_version;
#endif
static int g_fd;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_refcount;
@ -124,12 +128,24 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
zfs_cmd_t zc = { 0 };
int error = 0;
char *packed;
#ifdef __FreeBSD__
nvlist_t *oldsource;
#endif
size_t size;
ASSERT3S(g_refcount, >, 0);
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
oldsource = source;
error = lzc_compat_pre(&zc, &ioc, &source);
if (error)
return (error);
}
#endif
packed = fnvlist_pack(source, &size);
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
zc.zc_nvlist_src_size = size;
@ -167,14 +183,29 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
break;
}
}
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_post(&zc, ioc);
#endif
if (zc.zc_nvlist_dst_filled) {
*resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
zc.zc_nvlist_dst_size);
} else if (resultp != NULL) {
*resultp = NULL;
}
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_outnvl(&zc, ioc, resultp);
#endif
out:
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
if (source != oldsource)
nvlist_free(source);
source = oldsource;
}
#endif
fnvlist_pack_free(packed, size);
free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (error);

View File

@ -31,6 +31,9 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/fs/zfs.h>
#ifdef __FreeBSD__
#include "libzfs_core_compat.h"
#endif
#ifdef __cplusplus
extern "C" {

View File

@ -0,0 +1,134 @@
/*
* CDDL HEADER START
*
* 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 <sys/zfs_ioctl.h>
#include <libzfs_compat.h>
extern int zfs_ioctl_version;
int
lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
{
nvlist_t *nvl = NULL;
nvpair_t *pair;
char *buf;
zfs_ioc_t vecnum;
uint32_t type32;
int error = 0;
int pos;
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
vecnum = *ioc;
switch (vecnum) {
case ZFS_IOC_CREATE:
type32 = fnvlist_lookup_int32(*source, "type");
zc->zc_objset_type = (uint64_t)type32;
nvlist_lookup_nvlist(*source, "props", &nvl);
*source = nvl;
break;
case ZFS_IOC_CLONE:
buf = fnvlist_lookup_string(*source, "origin");
strlcpy(zc->zc_value, buf, MAXPATHLEN);
nvlist_lookup_nvlist(*source, "props", &nvl);
*ioc = ZFS_IOC_CREATE;
*source = nvl;
break;
case ZFS_IOC_SNAPSHOT:
nvl = fnvlist_lookup_nvlist(*source, "snaps");
pair = nvlist_next_nvpair(nvl, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
} else
error = EOPNOTSUPP;
/* old kernel cannot create multiple snapshots */
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
error = EOPNOTSUPP;
nvlist_free(nvl);
nvl = NULL;
nvlist_lookup_nvlist(*source, "props", &nvl);
*source = nvl;
break;
case ZFS_IOC_SPACE_SNAPS:
buf = fnvlist_lookup_string(*source, "firstsnap");
strlcpy(zc->zc_value, buf, MAXPATHLEN);
break;
case ZFS_IOC_DESTROY_SNAPS:
nvl = fnvlist_lookup_nvlist(*source, "snaps");
pair = nvlist_next_nvpair(nvl, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
}
*source = nvl;
break;
}
return (error);
}
void
lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
{
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return;
switch (ioc) {
case ZFS_IOC_CREATE:
case ZFS_IOC_CLONE:
case ZFS_IOC_SNAPSHOT:
case ZFS_IOC_SPACE_SNAPS:
case ZFS_IOC_DESTROY_SNAPS:
zc->zc_nvlist_dst_filled = B_FALSE;
break;
}
}
int
lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
{
nvlist_t *nvl;
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
switch (ioc) {
case ZFS_IOC_SPACE_SNAPS:
nvl = fnvlist_alloc();
fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
*outnvl = nvl;
break;
}
return (0);
}

View File

@ -0,0 +1,47 @@
/*
* CDDL HEADER START
*
* 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 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#ifndef _LIBZFS_CORE_COMPAT_H
#define _LIBZFS_CORE_COMPAT_H
#include <libnvpair.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
int lzc_compat_pre(zfs_cmd_t *, zfs_ioc_t *, nvlist_t **);
void lzc_compat_post(zfs_cmd_t *, const zfs_ioc_t);
int lzc_compat_outnvl(zfs_cmd_t *, const zfs_ioc_t, nvlist_t **);
#ifdef __cplusplus
}
#endif
#endif /* _LIBZFS_CORE_COMPAT_H */

View File

@ -9,7 +9,7 @@ LIB= zfs_core
DPADD= ${LIBNVPAIR}
LDADD= -lnvpair
SRCS= libzfs_core.c
SRCS= libzfs_core.c libzfs_core_compat.c
WARNS?= 0
CSTD= c99