2011-02-27 19:41:40 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
/*
|
2013-03-01 09:42:58 +00:00
|
|
|
* Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
2011-04-08 11:08:26 +00:00
|
|
|
* Portions Copyright 2005, 2010, Oracle and/or its affiliates.
|
|
|
|
* All rights reserved.
|
2011-02-27 19:41:40 +00:00
|
|
|
* Use is subject to license terms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/cred.h>
|
|
|
|
#include <sys/dmu.h>
|
|
|
|
#include <sys/zio.h>
|
|
|
|
#include <sys/nvpair.h>
|
|
|
|
#include <sys/dsl_deleg.h>
|
|
|
|
#include <sys/zfs_ioctl.h>
|
|
|
|
#include "zfs_ioctl_compat.h"
|
|
|
|
|
2013-03-01 09:42:58 +00:00
|
|
|
static int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
|
|
|
|
SYSCTL_DECL(_vfs_zfs_version);
|
|
|
|
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
|
|
|
|
0, "ZFS_IOCTL_VERSION");
|
|
|
|
|
2011-02-27 19:41:40 +00:00
|
|
|
/*
|
2013-03-01 09:42:58 +00:00
|
|
|
* FreeBSD zfs_cmd compatibility with older binaries
|
2011-02-27 19:41:40 +00:00
|
|
|
* appropriately remap/extend the zfs_cmd_t structure
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
|
|
|
|
{
|
|
|
|
zfs_cmd_v15_t *zc_c;
|
2013-03-01 09:42:58 +00:00
|
|
|
zfs_cmd_v28_t *zc28_c;
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2013-03-01 09:42:58 +00:00
|
|
|
switch (cflag) {
|
|
|
|
case ZFS_CMD_COMPAT_V28:
|
|
|
|
zc28_c = (void *)addr;
|
|
|
|
|
|
|
|
/* zc */
|
|
|
|
strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
|
|
|
|
strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
|
|
|
|
strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
|
|
|
|
strlcpy(zc->zc_top_ds, zc28_c->zc_top_ds, MAXPATHLEN);
|
|
|
|
zc->zc_guid = zc28_c->zc_guid;
|
|
|
|
zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
|
|
|
|
zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
|
|
|
|
zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
|
|
|
|
zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
|
|
|
|
zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
|
|
|
|
zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
|
|
|
|
zc->zc_cookie = zc28_c->zc_cookie;
|
|
|
|
zc->zc_objset_type = zc28_c->zc_objset_type;
|
|
|
|
zc->zc_perm_action = zc28_c->zc_perm_action;
|
|
|
|
zc->zc_history = zc28_c->zc_history;
|
|
|
|
zc->zc_history_len = zc28_c->zc_history_len;
|
|
|
|
zc->zc_history_offset = zc28_c->zc_history_offset;
|
|
|
|
zc->zc_obj = zc28_c->zc_obj;
|
|
|
|
zc->zc_iflags = zc28_c->zc_iflags;
|
|
|
|
zc->zc_share = zc28_c->zc_share;
|
|
|
|
zc->zc_jailid = zc28_c->zc_jailid;
|
|
|
|
zc->zc_objset_stats = zc28_c->zc_objset_stats;
|
|
|
|
zc->zc_begin_record = zc28_c->zc_begin_record;
|
|
|
|
zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
|
|
|
|
zc->zc_temphold = zc28_c->zc_temphold;
|
|
|
|
zc->zc_action_handle = zc28_c->zc_action_handle;
|
|
|
|
zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
|
|
|
|
zc->zc_simple = zc28_c->zc_simple;
|
|
|
|
bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
|
|
|
|
zc->zc_sendobj = zc28_c->zc_sendobj;
|
|
|
|
zc->zc_fromobj = zc28_c->zc_fromobj;
|
|
|
|
zc->zc_createtxg = zc28_c->zc_createtxg;
|
|
|
|
zc->zc_stat = zc28_c->zc_stat;
|
|
|
|
|
|
|
|
/* zc->zc_inject_record */
|
|
|
|
zc->zc_inject_record.zi_objset =
|
|
|
|
zc28_c->zc_inject_record.zi_objset;
|
|
|
|
zc->zc_inject_record.zi_object =
|
|
|
|
zc28_c->zc_inject_record.zi_object;
|
|
|
|
zc->zc_inject_record.zi_start =
|
|
|
|
zc28_c->zc_inject_record.zi_start;
|
|
|
|
zc->zc_inject_record.zi_end =
|
|
|
|
zc28_c->zc_inject_record.zi_end;
|
|
|
|
zc->zc_inject_record.zi_guid =
|
|
|
|
zc28_c->zc_inject_record.zi_guid;
|
|
|
|
zc->zc_inject_record.zi_level =
|
|
|
|
zc28_c->zc_inject_record.zi_level;
|
|
|
|
zc->zc_inject_record.zi_error =
|
|
|
|
zc28_c->zc_inject_record.zi_error;
|
|
|
|
zc->zc_inject_record.zi_type =
|
|
|
|
zc28_c->zc_inject_record.zi_type;
|
|
|
|
zc->zc_inject_record.zi_freq =
|
|
|
|
zc28_c->zc_inject_record.zi_freq;
|
|
|
|
zc->zc_inject_record.zi_failfast =
|
|
|
|
zc28_c->zc_inject_record.zi_failfast;
|
|
|
|
strlcpy(zc->zc_inject_record.zi_func,
|
|
|
|
zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
|
|
|
|
zc->zc_inject_record.zi_iotype =
|
|
|
|
zc28_c->zc_inject_record.zi_iotype;
|
|
|
|
zc->zc_inject_record.zi_duration =
|
|
|
|
zc28_c->zc_inject_record.zi_duration;
|
|
|
|
zc->zc_inject_record.zi_timer =
|
|
|
|
zc28_c->zc_inject_record.zi_timer;
|
|
|
|
zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
|
|
|
|
zc->zc_inject_record.zi_pad = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZFS_CMD_COMPAT_V15:
|
2011-02-27 19:41:40 +00:00
|
|
|
zc_c = (void *)addr;
|
|
|
|
|
|
|
|
/* zc */
|
2013-03-01 09:42:58 +00:00
|
|
|
strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
|
|
|
|
strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
|
|
|
|
strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
|
2011-02-27 19:41:40 +00:00
|
|
|
zc->zc_guid = zc_c->zc_guid;
|
|
|
|
zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
|
|
|
|
zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
|
|
|
|
zc->zc_nvlist_src = zc_c->zc_nvlist_src;
|
|
|
|
zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
|
|
|
|
zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
|
|
|
|
zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
|
|
|
|
zc->zc_cookie = zc_c->zc_cookie;
|
|
|
|
zc->zc_objset_type = zc_c->zc_objset_type;
|
|
|
|
zc->zc_perm_action = zc_c->zc_perm_action;
|
|
|
|
zc->zc_history = zc_c->zc_history;
|
|
|
|
zc->zc_history_len = zc_c->zc_history_len;
|
|
|
|
zc->zc_history_offset = zc_c->zc_history_offset;
|
|
|
|
zc->zc_obj = zc_c->zc_obj;
|
|
|
|
zc->zc_share = zc_c->zc_share;
|
|
|
|
zc->zc_jailid = zc_c->zc_jailid;
|
|
|
|
zc->zc_objset_stats = zc_c->zc_objset_stats;
|
|
|
|
zc->zc_begin_record = zc_c->zc_begin_record;
|
|
|
|
|
|
|
|
/* zc->zc_inject_record */
|
|
|
|
zc->zc_inject_record.zi_objset =
|
|
|
|
zc_c->zc_inject_record.zi_objset;
|
|
|
|
zc->zc_inject_record.zi_object =
|
|
|
|
zc_c->zc_inject_record.zi_object;
|
|
|
|
zc->zc_inject_record.zi_start =
|
|
|
|
zc_c->zc_inject_record.zi_start;
|
|
|
|
zc->zc_inject_record.zi_end =
|
|
|
|
zc_c->zc_inject_record.zi_end;
|
|
|
|
zc->zc_inject_record.zi_guid =
|
|
|
|
zc_c->zc_inject_record.zi_guid;
|
|
|
|
zc->zc_inject_record.zi_level =
|
|
|
|
zc_c->zc_inject_record.zi_level;
|
|
|
|
zc->zc_inject_record.zi_error =
|
|
|
|
zc_c->zc_inject_record.zi_error;
|
|
|
|
zc->zc_inject_record.zi_type =
|
|
|
|
zc_c->zc_inject_record.zi_type;
|
|
|
|
zc->zc_inject_record.zi_freq =
|
|
|
|
zc_c->zc_inject_record.zi_freq;
|
|
|
|
zc->zc_inject_record.zi_failfast =
|
|
|
|
zc_c->zc_inject_record.zi_failfast;
|
2013-03-01 09:42:58 +00:00
|
|
|
break;
|
2011-02-27 19:41:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int cflag)
|
|
|
|
{
|
|
|
|
zfs_cmd_v15_t *zc_c;
|
2013-03-01 09:42:58 +00:00
|
|
|
zfs_cmd_v28_t *zc28_c;
|
2011-02-27 19:41:40 +00:00
|
|
|
|
|
|
|
switch (cflag) {
|
2013-03-01 09:42:58 +00:00
|
|
|
case ZFS_CMD_COMPAT_V28:
|
|
|
|
zc28_c = (void *)addr;
|
|
|
|
|
|
|
|
strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
|
|
|
|
strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
|
|
|
|
strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
|
|
|
|
strlcpy(zc28_c->zc_top_ds, zc->zc_top_ds, MAXPATHLEN);
|
|
|
|
zc28_c->zc_guid = zc->zc_guid;
|
|
|
|
zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
|
|
|
|
zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
|
|
|
|
zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
|
|
|
|
zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
|
|
|
|
zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
|
|
|
|
zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
|
|
|
|
zc28_c->zc_cookie = zc->zc_cookie;
|
|
|
|
zc28_c->zc_objset_type = zc->zc_objset_type;
|
|
|
|
zc28_c->zc_perm_action = zc->zc_perm_action;
|
|
|
|
zc28_c->zc_history = zc->zc_history;
|
|
|
|
zc28_c->zc_history_len = zc->zc_history_len;
|
|
|
|
zc28_c->zc_history_offset = zc->zc_history_offset;
|
|
|
|
zc28_c->zc_obj = zc->zc_obj;
|
|
|
|
zc28_c->zc_iflags = zc->zc_iflags;
|
|
|
|
zc28_c->zc_share = zc->zc_share;
|
|
|
|
zc28_c->zc_jailid = zc->zc_jailid;
|
|
|
|
zc28_c->zc_objset_stats = zc->zc_objset_stats;
|
|
|
|
zc28_c->zc_begin_record = zc->zc_begin_record;
|
|
|
|
zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
|
|
|
|
zc28_c->zc_temphold = zc->zc_temphold;
|
|
|
|
zc28_c->zc_action_handle = zc->zc_action_handle;
|
|
|
|
zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
|
|
|
|
zc28_c->zc_simple = zc->zc_simple;
|
|
|
|
bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad));
|
|
|
|
zc28_c->zc_sendobj = zc->zc_sendobj;
|
|
|
|
zc28_c->zc_fromobj = zc->zc_fromobj;
|
|
|
|
zc28_c->zc_createtxg = zc->zc_createtxg;
|
|
|
|
zc28_c->zc_stat = zc->zc_stat;
|
|
|
|
|
|
|
|
/* zc_inject_record */
|
|
|
|
zc28_c->zc_inject_record.zi_objset =
|
|
|
|
zc->zc_inject_record.zi_objset;
|
|
|
|
zc28_c->zc_inject_record.zi_object =
|
|
|
|
zc->zc_inject_record.zi_object;
|
|
|
|
zc28_c->zc_inject_record.zi_start =
|
|
|
|
zc->zc_inject_record.zi_start;
|
|
|
|
zc28_c->zc_inject_record.zi_end =
|
|
|
|
zc->zc_inject_record.zi_end;
|
|
|
|
zc28_c->zc_inject_record.zi_guid =
|
|
|
|
zc->zc_inject_record.zi_guid;
|
|
|
|
zc28_c->zc_inject_record.zi_level =
|
|
|
|
zc->zc_inject_record.zi_level;
|
|
|
|
zc28_c->zc_inject_record.zi_error =
|
|
|
|
zc->zc_inject_record.zi_error;
|
|
|
|
zc28_c->zc_inject_record.zi_type =
|
|
|
|
zc->zc_inject_record.zi_type;
|
|
|
|
zc28_c->zc_inject_record.zi_freq =
|
|
|
|
zc->zc_inject_record.zi_freq;
|
|
|
|
zc28_c->zc_inject_record.zi_failfast =
|
|
|
|
zc->zc_inject_record.zi_failfast;
|
|
|
|
strlcpy(zc28_c->zc_inject_record.zi_func,
|
|
|
|
zc->zc_inject_record.zi_func, MAXNAMELEN);
|
|
|
|
zc28_c->zc_inject_record.zi_iotype =
|
|
|
|
zc->zc_inject_record.zi_iotype;
|
|
|
|
zc28_c->zc_inject_record.zi_duration =
|
|
|
|
zc->zc_inject_record.zi_duration;
|
|
|
|
zc28_c->zc_inject_record.zi_timer =
|
|
|
|
zc->zc_inject_record.zi_timer;
|
|
|
|
break;
|
|
|
|
|
2011-02-27 19:41:40 +00:00
|
|
|
case ZFS_CMD_COMPAT_V15:
|
|
|
|
zc_c = (void *)addr;
|
|
|
|
|
|
|
|
/* zc */
|
2013-03-01 09:42:58 +00:00
|
|
|
strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
|
|
|
|
strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
|
|
|
|
strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
|
2011-02-27 19:41:40 +00:00
|
|
|
zc_c->zc_guid = zc->zc_guid;
|
|
|
|
zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
|
|
|
|
zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
|
|
|
|
zc_c->zc_nvlist_src = zc->zc_nvlist_src;
|
|
|
|
zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
|
|
|
|
zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
|
|
|
|
zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
|
|
|
|
zc_c->zc_cookie = zc->zc_cookie;
|
|
|
|
zc_c->zc_objset_type = zc->zc_objset_type;
|
|
|
|
zc_c->zc_perm_action = zc->zc_perm_action;
|
|
|
|
zc_c->zc_history = zc->zc_history;
|
|
|
|
zc_c->zc_history_len = zc->zc_history_len;
|
|
|
|
zc_c->zc_history_offset = zc->zc_history_offset;
|
|
|
|
zc_c->zc_obj = zc->zc_obj;
|
|
|
|
zc_c->zc_share = zc->zc_share;
|
|
|
|
zc_c->zc_jailid = zc->zc_jailid;
|
|
|
|
zc_c->zc_objset_stats = zc->zc_objset_stats;
|
|
|
|
zc_c->zc_begin_record = zc->zc_begin_record;
|
|
|
|
|
|
|
|
/* zc_inject_record */
|
|
|
|
zc_c->zc_inject_record.zi_objset =
|
|
|
|
zc->zc_inject_record.zi_objset;
|
|
|
|
zc_c->zc_inject_record.zi_object =
|
|
|
|
zc->zc_inject_record.zi_object;
|
|
|
|
zc_c->zc_inject_record.zi_start =
|
|
|
|
zc->zc_inject_record.zi_start;
|
|
|
|
zc_c->zc_inject_record.zi_end =
|
|
|
|
zc->zc_inject_record.zi_end;
|
|
|
|
zc_c->zc_inject_record.zi_guid =
|
|
|
|
zc->zc_inject_record.zi_guid;
|
|
|
|
zc_c->zc_inject_record.zi_level =
|
|
|
|
zc->zc_inject_record.zi_level;
|
|
|
|
zc_c->zc_inject_record.zi_error =
|
|
|
|
zc->zc_inject_record.zi_error;
|
|
|
|
zc_c->zc_inject_record.zi_type =
|
|
|
|
zc->zc_inject_record.zi_type;
|
|
|
|
zc_c->zc_inject_record.zi_freq =
|
|
|
|
zc->zc_inject_record.zi_freq;
|
|
|
|
zc_c->zc_inject_record.zi_failfast =
|
|
|
|
zc->zc_inject_record.zi_failfast;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-04-08 11:08:26 +00:00
|
|
|
zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
|
|
|
|
nvlist_t **nvp)
|
2011-02-27 19:41:40 +00:00
|
|
|
{
|
2011-04-08 11:08:26 +00:00
|
|
|
char *packed;
|
|
|
|
int error;
|
|
|
|
nvlist_t *list = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read in and unpack the user-supplied nvlist.
|
|
|
|
*/
|
|
|
|
if (size == 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
#ifdef _KERNEL
|
|
|
|
packed = kmem_alloc(size, KM_SLEEP);
|
|
|
|
if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
|
|
|
|
iflag)) != 0) {
|
|
|
|
kmem_free(packed, size);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
packed = (void *)(uintptr_t)nvl;
|
|
|
|
#endif
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
error = nvlist_unpack(packed, size, &list, 0);
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
#ifdef _KERNEL
|
|
|
|
kmem_free(packed, size);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
*nvp = list;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
|
|
|
|
{
|
|
|
|
char *packed = NULL;
|
|
|
|
int error = 0;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
|
|
|
|
|
|
|
|
#ifdef _KERNEL
|
|
|
|
packed = kmem_alloc(size, KM_SLEEP);
|
|
|
|
VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
|
|
|
|
KM_SLEEP) == 0);
|
|
|
|
|
|
|
|
if (ddi_copyout(packed,
|
|
|
|
(void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
|
|
|
|
error = EFAULT;
|
|
|
|
kmem_free(packed, size);
|
|
|
|
#else
|
|
|
|
packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
|
|
|
|
VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
|
|
|
|
0) == 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
zc->zc_nvlist_dst_size = size;
|
|
|
|
return (error);
|
2011-02-27 19:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
|
|
|
|
{
|
|
|
|
nvlist_t **child;
|
|
|
|
nvlist_t *nvroot = NULL;
|
|
|
|
vdev_stat_t *vs;
|
|
|
|
uint_t c, children, nelem;
|
|
|
|
|
|
|
|
if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
|
|
|
|
&child, &children) == 0) {
|
|
|
|
for (c = 0; c < children; c++) {
|
|
|
|
zfs_ioctl_compat_fix_stats_nvlist(child[c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
|
|
|
|
&nvroot) == 0)
|
|
|
|
zfs_ioctl_compat_fix_stats_nvlist(nvroot);
|
|
|
|
#ifdef _KERNEL
|
|
|
|
if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
|
|
|
|
#else
|
|
|
|
if ((nvlist_lookup_uint64_array(nvl, "stats",
|
|
|
|
#endif
|
|
|
|
|
|
|
|
(uint64_t **)&vs, &nelem) == 0)) {
|
|
|
|
nvlist_add_uint64_array(nvl,
|
|
|
|
#ifdef _KERNEL
|
|
|
|
"stats",
|
|
|
|
#else
|
|
|
|
ZPOOL_CONFIG_VDEV_STATS,
|
|
|
|
#endif
|
|
|
|
(uint64_t *)vs, nelem);
|
|
|
|
#ifdef _KERNEL
|
|
|
|
nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
|
|
|
|
#else
|
|
|
|
nvlist_remove(nvl, "stats",
|
|
|
|
#endif
|
|
|
|
DATA_TYPE_UINT64_ARRAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
static int
|
2013-03-01 09:42:58 +00:00
|
|
|
zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
|
2011-02-27 19:41:40 +00:00
|
|
|
{
|
|
|
|
nvlist_t *nv, *nvp = NULL;
|
|
|
|
nvpair_t *elem;
|
2011-04-08 11:08:26 +00:00
|
|
|
int error;
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
|
|
|
|
zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
|
|
|
|
return (error);
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2013-03-01 09:42:58 +00:00
|
|
|
if (nc == 5) { /* ZFS_IOC_POOL_STATS */
|
2011-02-27 19:41:40 +00:00
|
|
|
elem = NULL;
|
|
|
|
while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
|
|
|
|
if (nvpair_value_nvlist(elem, &nvp) == 0)
|
|
|
|
zfs_ioctl_compat_fix_stats_nvlist(nvp);
|
|
|
|
}
|
|
|
|
elem = NULL;
|
|
|
|
} else
|
|
|
|
zfs_ioctl_compat_fix_stats_nvlist(nv);
|
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
error = zfs_ioctl_compat_put_nvlist(zc, nv);
|
2011-02-27 19:41:40 +00:00
|
|
|
|
|
|
|
nvlist_free(nv);
|
2011-04-08 11:08:26 +00:00
|
|
|
|
|
|
|
return (error);
|
2011-02-27 19:41:40 +00:00
|
|
|
}
|
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
static int
|
2011-02-27 19:41:40 +00:00
|
|
|
zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
|
|
|
|
{
|
|
|
|
nvlist_t *nv, *nva = NULL;
|
2011-04-08 11:08:26 +00:00
|
|
|
int error;
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
|
|
|
|
zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
|
|
|
|
return (error);
|
2011-02-27 19:41:40 +00:00
|
|
|
|
|
|
|
#ifdef _KERNEL
|
|
|
|
if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
|
|
|
|
nvlist_add_nvlist(nv, "used", nva);
|
|
|
|
nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
|
|
|
|
nvlist_add_nvlist(nv, "available", nva);
|
|
|
|
nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
|
|
|
|
nvlist_add_nvlist(nv, "allocated", nva);
|
|
|
|
nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
|
|
|
|
nvlist_add_nvlist(nv, "free", nva);
|
|
|
|
nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-04-08 11:08:26 +00:00
|
|
|
error = zfs_ioctl_compat_put_nvlist(zc, nv);
|
2011-02-27 19:41:40 +00:00
|
|
|
|
|
|
|
nvlist_free(nv);
|
2011-04-08 11:08:26 +00:00
|
|
|
|
|
|
|
return (error);
|
2011-02-27 19:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _KERNEL
|
|
|
|
int
|
|
|
|
zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag)
|
|
|
|
{
|
|
|
|
int nc, ret;
|
|
|
|
void *zc_c;
|
|
|
|
unsigned long ncmd;
|
|
|
|
|
2013-03-01 09:42:58 +00:00
|
|
|
switch (cflag) {
|
|
|
|
case ZFS_CMD_COMPAT_NONE:
|
2011-02-27 19:41:40 +00:00
|
|
|
ret = ioctl(fd, cmd, zc);
|
|
|
|
return (ret);
|
2013-03-01 09:42:58 +00:00
|
|
|
case ZFS_CMD_COMPAT_V28:
|
|
|
|
zc_c = malloc(sizeof(zfs_cmd_v28_t));
|
2013-03-05 08:09:53 +00:00
|
|
|
ncmd = _IOWR('Z', ZFS_IOCREQ(cmd), struct zfs_cmd_v28);
|
2013-03-01 09:42:58 +00:00
|
|
|
break;
|
|
|
|
case ZFS_CMD_COMPAT_V15:
|
2013-03-05 08:09:53 +00:00
|
|
|
nc = zfs_ioctl_v28_to_v15[ZFS_IOCREQ(cmd)];
|
2011-02-27 19:41:40 +00:00
|
|
|
zc_c = malloc(sizeof(zfs_cmd_v15_t));
|
|
|
|
ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
|
2013-03-01 09:42:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-02-27 19:41:40 +00:00
|
|
|
return (EINVAL);
|
2013-03-01 09:42:58 +00:00
|
|
|
}
|
2011-02-27 19:41:40 +00:00
|
|
|
|
2013-03-05 08:09:53 +00:00
|
|
|
if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
|
2011-02-27 19:41:40 +00:00
|
|
|
return (ENOTSUP);
|
|
|
|
|
|
|
|
zfs_cmd_compat_put(zc, (caddr_t)zc_c, cflag);
|
|
|
|
ret = ioctl(fd, ncmd, zc_c);
|
|
|
|
if (cflag == ZFS_CMD_COMPAT_V15 &&
|
|
|
|
nc == 2 /* ZFS_IOC_POOL_IMPORT */)
|
|
|
|
ret = ioctl(fd, _IOWR('Z', 4 /* ZFS_IOC_POOL_CONFIGS */,
|
|
|
|
struct zfs_cmd_v15), zc_c);
|
|
|
|
zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
|
|
|
|
free(zc_c);
|
|
|
|
|
2013-03-01 09:42:58 +00:00
|
|
|
if (cflag == ZFS_CMD_COMPAT_V15) {
|
|
|
|
switch (nc) {
|
|
|
|
case 2: /* ZFS_IOC_POOL_IMPORT */
|
|
|
|
case 4: /* ZFS_IOC_POOL_CONFIGS */
|
|
|
|
case 5: /* ZFS_IOC_POOL_STATS */
|
|
|
|
case 6: /* ZFS_IOC_POOL_TRYIMPORT */
|
|
|
|
zfs_ioctl_compat_fix_stats(zc, nc);
|
|
|
|
break;
|
|
|
|
case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
|
|
|
|
zfs_ioctl_compat_pool_get_props(zc);
|
|
|
|
break;
|
|
|
|
}
|
2011-02-27 19:41:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
#else /* _KERNEL */
|
|
|
|
void
|
|
|
|
zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
|
|
|
|
{
|
|
|
|
if (cflag == ZFS_CMD_COMPAT_V15)
|
|
|
|
switch (*vec) {
|
|
|
|
|
|
|
|
case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
|
|
|
|
zc->zc_cookie = POOL_SCAN_SCRUB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
|
|
|
|
{
|
|
|
|
if (cflag == ZFS_CMD_COMPAT_V15) {
|
|
|
|
switch (vec) {
|
|
|
|
case 4: /* ZFS_IOC_POOL_CONFIGS */
|
|
|
|
case 5: /* ZFS_IOC_POOL_STATS */
|
|
|
|
case 6: /* ZFS_IOC_POOL_TRYIMPORT */
|
|
|
|
zfs_ioctl_compat_fix_stats(zc, vec);
|
|
|
|
break;
|
|
|
|
case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
|
|
|
|
zfs_ioctl_compat_pool_get_props(zc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* KERNEL */
|