1219089Spjd/*
2219089Spjd * CDDL HEADER START
3219089Spjd *
4219089Spjd * The contents of this file are subject to the terms of the
5219089Spjd * Common Development and Distribution License (the "License").
6219089Spjd * You may not use this file except in compliance with the License.
7219089Spjd *
8219089Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9219089Spjd * or http://www.opensolaris.org/os/licensing.
10219089Spjd * See the License for the specific language governing permissions
11219089Spjd * and limitations under the License.
12219089Spjd *
13219089Spjd * When distributing Covered Code, include this CDDL HEADER in each
14219089Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15219089Spjd * If applicable, add the following below this CDDL HEADER, with the
16219089Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17219089Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18219089Spjd *
19219089Spjd * CDDL HEADER END
20219089Spjd */
21219089Spjd/*
22248369Smm * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
23220447Smm * Portions Copyright 2005, 2010, Oracle and/or its affiliates.
24220447Smm * All rights reserved.
25219089Spjd * Use is subject to license terms.
26219089Spjd */
27219089Spjd
28219089Spjd#include <sys/types.h>
29219089Spjd#include <sys/param.h>
30219089Spjd#include <sys/cred.h>
31219089Spjd#include <sys/dmu.h>
32219089Spjd#include <sys/zio.h>
33219089Spjd#include <sys/nvpair.h>
34219089Spjd#include <sys/dsl_deleg.h>
35219089Spjd#include <sys/zfs_ioctl.h>
36249643Smm#include "zfs_namecheck.h"
37219089Spjd#include "zfs_ioctl_compat.h"
38219089Spjd
39248369Smmstatic int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
40248369SmmSYSCTL_DECL(_vfs_zfs_version);
41248369SmmSYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
42248369Smm    0, "ZFS_IOCTL_VERSION");
43248369Smm
44219089Spjd/*
45248369Smm * FreeBSD zfs_cmd compatibility with older binaries
46219089Spjd * appropriately remap/extend the zfs_cmd_t structure
47219089Spjd */
48219089Spjdvoid
49219089Spjdzfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
50219089Spjd{
51219089Spjd	zfs_cmd_v15_t *zc_c;
52248369Smm	zfs_cmd_v28_t *zc28_c;
53249643Smm	zfs_cmd_deadman_t *zcdm_c;
54219089Spjd
55248369Smm	switch (cflag) {
56249643Smm	case ZFS_CMD_COMPAT_DEADMAN:
57249643Smm		zcdm_c = (void *)addr;
58249643Smm		/* zc */
59249643Smm		strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN);
60249643Smm		strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2);
61249643Smm		strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN);
62249643Smm		zc->zc_guid = zcdm_c->zc_guid;
63249643Smm		zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf;
64249643Smm		zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size;
65249643Smm		zc->zc_nvlist_src = zcdm_c->zc_nvlist_src;
66249643Smm		zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size;
67249643Smm		zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst;
68249643Smm		zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size;
69249643Smm		zc->zc_cookie = zcdm_c->zc_cookie;
70249643Smm		zc->zc_objset_type = zcdm_c->zc_objset_type;
71249643Smm		zc->zc_perm_action = zcdm_c->zc_perm_action;
72249643Smm		zc->zc_history = zcdm_c->zc_history;
73249643Smm		zc->zc_history_len = zcdm_c->zc_history_len;
74249643Smm		zc->zc_history_offset = zcdm_c->zc_history_offset;
75249643Smm		zc->zc_obj = zcdm_c->zc_obj;
76249643Smm		zc->zc_iflags = zcdm_c->zc_iflags;
77249643Smm		zc->zc_share = zcdm_c->zc_share;
78249643Smm		zc->zc_jailid = zcdm_c->zc_jailid;
79249643Smm		zc->zc_objset_stats = zcdm_c->zc_objset_stats;
80249643Smm		zc->zc_begin_record = zcdm_c->zc_begin_record;
81249643Smm		zc->zc_defer_destroy = zcdm_c->zc_defer_destroy;
82249643Smm		zc->zc_temphold = zcdm_c->zc_temphold;
83249643Smm		zc->zc_action_handle = zcdm_c->zc_action_handle;
84249643Smm		zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd;
85249643Smm		zc->zc_simple = zcdm_c->zc_simple;
86249643Smm		bcopy(zcdm_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
87249643Smm		zc->zc_sendobj = zcdm_c->zc_sendobj;
88249643Smm		zc->zc_fromobj = zcdm_c->zc_fromobj;
89249643Smm		zc->zc_createtxg = zcdm_c->zc_createtxg;
90249643Smm		zc->zc_stat = zcdm_c->zc_stat;
91249643Smm
92249643Smm		/* zc_inject_record doesn't change in libzfs_core */
93249643Smm		zcdm_c->zc_inject_record = zc->zc_inject_record;
94249643Smm
95249643Smm		/* we always assume zc_nvlist_dst_filled is true */
96249643Smm		zc->zc_nvlist_dst_filled = B_TRUE;
97249643Smm	break;
98249643Smm
99248369Smm	case ZFS_CMD_COMPAT_V28:
100248369Smm		zc28_c = (void *)addr;
101248369Smm
102248369Smm		/* zc */
103248369Smm		strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
104248369Smm		strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
105248369Smm		strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
106248369Smm		zc->zc_guid = zc28_c->zc_guid;
107248369Smm		zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
108248369Smm		zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
109248369Smm		zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
110248369Smm		zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
111248369Smm		zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
112248369Smm		zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
113248369Smm		zc->zc_cookie = zc28_c->zc_cookie;
114248369Smm		zc->zc_objset_type = zc28_c->zc_objset_type;
115248369Smm		zc->zc_perm_action = zc28_c->zc_perm_action;
116248369Smm		zc->zc_history = zc28_c->zc_history;
117248369Smm		zc->zc_history_len = zc28_c->zc_history_len;
118248369Smm		zc->zc_history_offset = zc28_c->zc_history_offset;
119248369Smm		zc->zc_obj = zc28_c->zc_obj;
120248369Smm		zc->zc_iflags = zc28_c->zc_iflags;
121248369Smm		zc->zc_share = zc28_c->zc_share;
122248369Smm		zc->zc_jailid = zc28_c->zc_jailid;
123248369Smm		zc->zc_objset_stats = zc28_c->zc_objset_stats;
124248369Smm		zc->zc_begin_record = zc28_c->zc_begin_record;
125248369Smm		zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
126248369Smm		zc->zc_temphold = zc28_c->zc_temphold;
127248369Smm		zc->zc_action_handle = zc28_c->zc_action_handle;
128248369Smm		zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
129248369Smm		zc->zc_simple = zc28_c->zc_simple;
130248369Smm		bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
131248369Smm		zc->zc_sendobj = zc28_c->zc_sendobj;
132248369Smm		zc->zc_fromobj = zc28_c->zc_fromobj;
133248369Smm		zc->zc_createtxg = zc28_c->zc_createtxg;
134248369Smm		zc->zc_stat = zc28_c->zc_stat;
135248369Smm
136248369Smm		/* zc->zc_inject_record */
137248369Smm		zc->zc_inject_record.zi_objset =
138248369Smm		    zc28_c->zc_inject_record.zi_objset;
139248369Smm		zc->zc_inject_record.zi_object =
140248369Smm		    zc28_c->zc_inject_record.zi_object;
141248369Smm		zc->zc_inject_record.zi_start =
142248369Smm		    zc28_c->zc_inject_record.zi_start;
143248369Smm		zc->zc_inject_record.zi_end =
144248369Smm		    zc28_c->zc_inject_record.zi_end;
145248369Smm		zc->zc_inject_record.zi_guid =
146248369Smm		    zc28_c->zc_inject_record.zi_guid;
147248369Smm		zc->zc_inject_record.zi_level =
148248369Smm		    zc28_c->zc_inject_record.zi_level;
149248369Smm		zc->zc_inject_record.zi_error =
150248369Smm		    zc28_c->zc_inject_record.zi_error;
151248369Smm		zc->zc_inject_record.zi_type =
152248369Smm		    zc28_c->zc_inject_record.zi_type;
153248369Smm		zc->zc_inject_record.zi_freq =
154248369Smm		    zc28_c->zc_inject_record.zi_freq;
155248369Smm		zc->zc_inject_record.zi_failfast =
156248369Smm		    zc28_c->zc_inject_record.zi_failfast;
157248369Smm		strlcpy(zc->zc_inject_record.zi_func,
158248369Smm		    zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
159248369Smm		zc->zc_inject_record.zi_iotype =
160248369Smm		    zc28_c->zc_inject_record.zi_iotype;
161248369Smm		zc->zc_inject_record.zi_duration =
162248369Smm		    zc28_c->zc_inject_record.zi_duration;
163248369Smm		zc->zc_inject_record.zi_timer =
164248369Smm		    zc28_c->zc_inject_record.zi_timer;
165248369Smm		zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
166248369Smm		zc->zc_inject_record.zi_pad = 0;
167248369Smm		break;
168248369Smm
169248369Smm	case ZFS_CMD_COMPAT_V15:
170219089Spjd		zc_c = (void *)addr;
171219089Spjd
172219089Spjd		/* zc */
173248369Smm		strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
174248369Smm		strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
175248369Smm		strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
176219089Spjd		zc->zc_guid = zc_c->zc_guid;
177219089Spjd		zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
178219089Spjd		zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
179219089Spjd		zc->zc_nvlist_src = zc_c->zc_nvlist_src;
180219089Spjd		zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
181219089Spjd		zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
182219089Spjd		zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
183219089Spjd		zc->zc_cookie = zc_c->zc_cookie;
184219089Spjd		zc->zc_objset_type = zc_c->zc_objset_type;
185219089Spjd		zc->zc_perm_action = zc_c->zc_perm_action;
186219089Spjd		zc->zc_history = zc_c->zc_history;
187219089Spjd		zc->zc_history_len = zc_c->zc_history_len;
188219089Spjd		zc->zc_history_offset = zc_c->zc_history_offset;
189219089Spjd		zc->zc_obj = zc_c->zc_obj;
190219089Spjd		zc->zc_share = zc_c->zc_share;
191219089Spjd		zc->zc_jailid = zc_c->zc_jailid;
192219089Spjd		zc->zc_objset_stats = zc_c->zc_objset_stats;
193219089Spjd		zc->zc_begin_record = zc_c->zc_begin_record;
194219089Spjd
195219089Spjd		/* zc->zc_inject_record */
196219089Spjd		zc->zc_inject_record.zi_objset =
197219089Spjd		    zc_c->zc_inject_record.zi_objset;
198219089Spjd		zc->zc_inject_record.zi_object =
199219089Spjd		    zc_c->zc_inject_record.zi_object;
200219089Spjd		zc->zc_inject_record.zi_start =
201219089Spjd		    zc_c->zc_inject_record.zi_start;
202219089Spjd		zc->zc_inject_record.zi_end =
203219089Spjd		    zc_c->zc_inject_record.zi_end;
204219089Spjd		zc->zc_inject_record.zi_guid =
205219089Spjd		    zc_c->zc_inject_record.zi_guid;
206219089Spjd		zc->zc_inject_record.zi_level =
207219089Spjd		    zc_c->zc_inject_record.zi_level;
208219089Spjd		zc->zc_inject_record.zi_error =
209219089Spjd		    zc_c->zc_inject_record.zi_error;
210219089Spjd		zc->zc_inject_record.zi_type =
211219089Spjd		    zc_c->zc_inject_record.zi_type;
212219089Spjd		zc->zc_inject_record.zi_freq =
213219089Spjd		    zc_c->zc_inject_record.zi_freq;
214219089Spjd		zc->zc_inject_record.zi_failfast =
215219089Spjd		    zc_c->zc_inject_record.zi_failfast;
216248369Smm		break;
217219089Spjd	}
218219089Spjd}
219219089Spjd
220219089Spjdvoid
221249643Smmzfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request,
222249643Smm    const int cflag)
223219089Spjd{
224219089Spjd	zfs_cmd_v15_t *zc_c;
225248369Smm	zfs_cmd_v28_t *zc28_c;
226249643Smm	zfs_cmd_deadman_t *zcdm_c;
227219089Spjd
228219089Spjd	switch (cflag) {
229249643Smm	case ZFS_CMD_COMPAT_DEADMAN:
230249643Smm		zcdm_c = (void *)addr;
231249643Smm
232249643Smm		strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN);
233249643Smm		strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
234249643Smm		strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN);
235249643Smm		zcdm_c->zc_guid = zc->zc_guid;
236249643Smm		zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf;
237249643Smm		zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
238249643Smm		zcdm_c->zc_nvlist_src = zc->zc_nvlist_src;
239249643Smm		zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
240249643Smm		zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst;
241249643Smm		zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
242249643Smm		zcdm_c->zc_cookie = zc->zc_cookie;
243249643Smm		zcdm_c->zc_objset_type = zc->zc_objset_type;
244249643Smm		zcdm_c->zc_perm_action = zc->zc_perm_action;
245249643Smm		zcdm_c->zc_history = zc->zc_history;
246249643Smm		zcdm_c->zc_history_len = zc->zc_history_len;
247249643Smm		zcdm_c->zc_history_offset = zc->zc_history_offset;
248249643Smm		zcdm_c->zc_obj = zc->zc_obj;
249249643Smm		zcdm_c->zc_iflags = zc->zc_iflags;
250249643Smm		zcdm_c->zc_share = zc->zc_share;
251249643Smm		zcdm_c->zc_jailid = zc->zc_jailid;
252249643Smm		zcdm_c->zc_objset_stats = zc->zc_objset_stats;
253249643Smm		zcdm_c->zc_begin_record = zc->zc_begin_record;
254249643Smm		zcdm_c->zc_defer_destroy = zc->zc_defer_destroy;
255249643Smm		zcdm_c->zc_temphold = zc->zc_temphold;
256249643Smm		zcdm_c->zc_action_handle = zc->zc_action_handle;
257249643Smm		zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd;
258249643Smm		zcdm_c->zc_simple = zc->zc_simple;
259249643Smm		bcopy(zc->zc_pad, zcdm_c->zc_pad, sizeof(zcdm_c->zc_pad));
260249643Smm		zcdm_c->zc_sendobj = zc->zc_sendobj;
261249643Smm		zcdm_c->zc_fromobj = zc->zc_fromobj;
262249643Smm		zcdm_c->zc_createtxg = zc->zc_createtxg;
263249643Smm		zcdm_c->zc_stat = zc->zc_stat;
264249643Smm
265249643Smm		/* zc_inject_record doesn't change in libzfs_core */
266249643Smm		zc->zc_inject_record = zcdm_c->zc_inject_record;
267249643Smm#ifndef _KERNEL
268249643Smm		if (request == ZFS_IOC_RECV)
269249643Smm			strlcpy(zcdm_c->zc_top_ds,
270249643Smm			    zc->zc_value + strlen(zc->zc_value) + 1,
271249643Smm			    (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1);
272249643Smm#endif
273249643Smm	break;
274249643Smm
275248369Smm	case ZFS_CMD_COMPAT_V28:
276248369Smm		zc28_c = (void *)addr;
277248369Smm
278248369Smm		strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
279248369Smm		strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
280248369Smm		strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
281248369Smm		zc28_c->zc_guid = zc->zc_guid;
282248369Smm		zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
283248369Smm		zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
284248369Smm		zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
285248369Smm		zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
286248369Smm		zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
287248369Smm		zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
288248369Smm		zc28_c->zc_cookie = zc->zc_cookie;
289248369Smm		zc28_c->zc_objset_type = zc->zc_objset_type;
290248369Smm		zc28_c->zc_perm_action = zc->zc_perm_action;
291248369Smm		zc28_c->zc_history = zc->zc_history;
292248369Smm		zc28_c->zc_history_len = zc->zc_history_len;
293248369Smm		zc28_c->zc_history_offset = zc->zc_history_offset;
294248369Smm		zc28_c->zc_obj = zc->zc_obj;
295248369Smm		zc28_c->zc_iflags = zc->zc_iflags;
296248369Smm		zc28_c->zc_share = zc->zc_share;
297248369Smm		zc28_c->zc_jailid = zc->zc_jailid;
298248369Smm		zc28_c->zc_objset_stats = zc->zc_objset_stats;
299248369Smm		zc28_c->zc_begin_record = zc->zc_begin_record;
300248369Smm		zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
301248369Smm		zc28_c->zc_temphold = zc->zc_temphold;
302248369Smm		zc28_c->zc_action_handle = zc->zc_action_handle;
303248369Smm		zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
304248369Smm		zc28_c->zc_simple = zc->zc_simple;
305248369Smm		bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad));
306248369Smm		zc28_c->zc_sendobj = zc->zc_sendobj;
307248369Smm		zc28_c->zc_fromobj = zc->zc_fromobj;
308248369Smm		zc28_c->zc_createtxg = zc->zc_createtxg;
309248369Smm		zc28_c->zc_stat = zc->zc_stat;
310249643Smm#ifndef _KERNEL
311249643Smm		if (request == ZFS_IOC_RECV)
312249643Smm			strlcpy(zc28_c->zc_top_ds,
313249643Smm			    zc->zc_value + strlen(zc->zc_value) + 1,
314249643Smm			    MAXPATHLEN * 2 - strlen(zc->zc_value) - 1);
315249643Smm#endif
316248369Smm		/* zc_inject_record */
317248369Smm		zc28_c->zc_inject_record.zi_objset =
318248369Smm		    zc->zc_inject_record.zi_objset;
319248369Smm		zc28_c->zc_inject_record.zi_object =
320248369Smm		    zc->zc_inject_record.zi_object;
321248369Smm		zc28_c->zc_inject_record.zi_start =
322248369Smm		    zc->zc_inject_record.zi_start;
323248369Smm		zc28_c->zc_inject_record.zi_end =
324248369Smm		    zc->zc_inject_record.zi_end;
325248369Smm		zc28_c->zc_inject_record.zi_guid =
326248369Smm		    zc->zc_inject_record.zi_guid;
327248369Smm		zc28_c->zc_inject_record.zi_level =
328248369Smm		    zc->zc_inject_record.zi_level;
329248369Smm		zc28_c->zc_inject_record.zi_error =
330248369Smm		    zc->zc_inject_record.zi_error;
331248369Smm		zc28_c->zc_inject_record.zi_type =
332248369Smm		    zc->zc_inject_record.zi_type;
333248369Smm		zc28_c->zc_inject_record.zi_freq =
334248369Smm		    zc->zc_inject_record.zi_freq;
335248369Smm		zc28_c->zc_inject_record.zi_failfast =
336248369Smm		    zc->zc_inject_record.zi_failfast;
337248369Smm		strlcpy(zc28_c->zc_inject_record.zi_func,
338248369Smm		    zc->zc_inject_record.zi_func, MAXNAMELEN);
339248369Smm		zc28_c->zc_inject_record.zi_iotype =
340248369Smm		    zc->zc_inject_record.zi_iotype;
341248369Smm		zc28_c->zc_inject_record.zi_duration =
342248369Smm		    zc->zc_inject_record.zi_duration;
343248369Smm		zc28_c->zc_inject_record.zi_timer =
344248369Smm		    zc->zc_inject_record.zi_timer;
345248369Smm		break;
346248369Smm
347219089Spjd	case ZFS_CMD_COMPAT_V15:
348219089Spjd		zc_c = (void *)addr;
349219089Spjd
350219089Spjd		/* zc */
351248369Smm		strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
352248369Smm		strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
353248369Smm		strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
354219089Spjd		zc_c->zc_guid = zc->zc_guid;
355219089Spjd		zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
356219089Spjd		zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
357219089Spjd		zc_c->zc_nvlist_src = zc->zc_nvlist_src;
358219089Spjd		zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
359219089Spjd		zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
360219089Spjd		zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
361219089Spjd		zc_c->zc_cookie = zc->zc_cookie;
362219089Spjd		zc_c->zc_objset_type = zc->zc_objset_type;
363219089Spjd		zc_c->zc_perm_action = zc->zc_perm_action;
364219089Spjd		zc_c->zc_history = zc->zc_history;
365219089Spjd		zc_c->zc_history_len = zc->zc_history_len;
366219089Spjd		zc_c->zc_history_offset = zc->zc_history_offset;
367219089Spjd		zc_c->zc_obj = zc->zc_obj;
368219089Spjd		zc_c->zc_share = zc->zc_share;
369219089Spjd		zc_c->zc_jailid = zc->zc_jailid;
370219089Spjd		zc_c->zc_objset_stats = zc->zc_objset_stats;
371219089Spjd		zc_c->zc_begin_record = zc->zc_begin_record;
372219089Spjd
373219089Spjd		/* zc_inject_record */
374219089Spjd		zc_c->zc_inject_record.zi_objset =
375219089Spjd		    zc->zc_inject_record.zi_objset;
376219089Spjd		zc_c->zc_inject_record.zi_object =
377219089Spjd		    zc->zc_inject_record.zi_object;
378219089Spjd		zc_c->zc_inject_record.zi_start =
379219089Spjd		    zc->zc_inject_record.zi_start;
380219089Spjd		zc_c->zc_inject_record.zi_end =
381219089Spjd		    zc->zc_inject_record.zi_end;
382219089Spjd		zc_c->zc_inject_record.zi_guid =
383219089Spjd		    zc->zc_inject_record.zi_guid;
384219089Spjd		zc_c->zc_inject_record.zi_level =
385219089Spjd		    zc->zc_inject_record.zi_level;
386219089Spjd		zc_c->zc_inject_record.zi_error =
387219089Spjd		    zc->zc_inject_record.zi_error;
388219089Spjd		zc_c->zc_inject_record.zi_type =
389219089Spjd		    zc->zc_inject_record.zi_type;
390219089Spjd		zc_c->zc_inject_record.zi_freq =
391219089Spjd		    zc->zc_inject_record.zi_freq;
392219089Spjd		zc_c->zc_inject_record.zi_failfast =
393219089Spjd		    zc->zc_inject_record.zi_failfast;
394219089Spjd
395219089Spjd		break;
396219089Spjd	}
397219089Spjd}
398219089Spjd
399219089Spjdstatic int
400220447Smmzfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
401220447Smm    nvlist_t **nvp)
402219089Spjd{
403220447Smm	char *packed;
404220447Smm	int error;
405220447Smm	nvlist_t *list = NULL;
406219089Spjd
407220447Smm	/*
408220447Smm	 * Read in and unpack the user-supplied nvlist.
409220447Smm	 */
410220447Smm	if (size == 0)
411220447Smm		return (EINVAL);
412219089Spjd
413220447Smm#ifdef _KERNEL
414220447Smm	packed = kmem_alloc(size, KM_SLEEP);
415220447Smm	if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
416220447Smm	    iflag)) != 0) {
417220447Smm		kmem_free(packed, size);
418220447Smm		return (error);
419220447Smm	}
420220447Smm#else
421220447Smm	packed = (void *)(uintptr_t)nvl;
422220447Smm#endif
423220447Smm
424220447Smm	error = nvlist_unpack(packed, size, &list, 0);
425220447Smm
426220447Smm#ifdef _KERNEL
427220447Smm	kmem_free(packed, size);
428220447Smm#endif
429220447Smm
430220447Smm	if (error != 0)
431220447Smm		return (error);
432220447Smm
433220447Smm	*nvp = list;
434220447Smm	return (0);
435219089Spjd}
436219089Spjd
437220447Smmstatic int
438220447Smmzfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
439220447Smm{
440220447Smm	char *packed = NULL;
441220447Smm	int error = 0;
442220447Smm	size_t size;
443220447Smm
444220447Smm	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
445220447Smm
446220447Smm#ifdef _KERNEL
447220447Smm	packed = kmem_alloc(size, KM_SLEEP);
448220447Smm	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
449220447Smm	    KM_SLEEP) == 0);
450220447Smm
451220447Smm	if (ddi_copyout(packed,
452220447Smm	    (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
453220447Smm		error = EFAULT;
454220447Smm	kmem_free(packed, size);
455220447Smm#else
456220447Smm	packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
457220447Smm	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
458220447Smm	    0) == 0);
459220447Smm#endif
460220447Smm
461220447Smm	zc->zc_nvlist_dst_size = size;
462220447Smm	return (error);
463220447Smm}
464220447Smm
465219089Spjdstatic void
466219089Spjdzfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
467219089Spjd{
468219089Spjd	nvlist_t **child;
469219089Spjd	nvlist_t *nvroot = NULL;
470219089Spjd	vdev_stat_t *vs;
471219089Spjd	uint_t c, children, nelem;
472219089Spjd
473219089Spjd	if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
474219089Spjd	    &child, &children) == 0) {
475219089Spjd		for (c = 0; c < children; c++) {
476219089Spjd			zfs_ioctl_compat_fix_stats_nvlist(child[c]);
477219089Spjd		}
478219089Spjd	}
479219089Spjd
480219089Spjd	if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
481219089Spjd	    &nvroot) == 0)
482219089Spjd		zfs_ioctl_compat_fix_stats_nvlist(nvroot);
483219089Spjd#ifdef _KERNEL
484219089Spjd	if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
485219089Spjd#else
486219089Spjd	if ((nvlist_lookup_uint64_array(nvl, "stats",
487219089Spjd#endif
488219089Spjd
489219089Spjd	    (uint64_t **)&vs, &nelem) == 0)) {
490219089Spjd		nvlist_add_uint64_array(nvl,
491219089Spjd#ifdef _KERNEL
492219089Spjd		    "stats",
493219089Spjd#else
494219089Spjd		    ZPOOL_CONFIG_VDEV_STATS,
495219089Spjd#endif
496219089Spjd		    (uint64_t *)vs, nelem);
497219089Spjd#ifdef _KERNEL
498219089Spjd		nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
499219089Spjd#else
500219089Spjd		nvlist_remove(nvl, "stats",
501219089Spjd#endif
502219089Spjd		    DATA_TYPE_UINT64_ARRAY);
503219089Spjd	}
504219089Spjd}
505219089Spjd
506220447Smmstatic int
507248369Smmzfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
508219089Spjd{
509219089Spjd	nvlist_t *nv, *nvp = NULL;
510219089Spjd	nvpair_t *elem;
511220447Smm	int error;
512219089Spjd
513220447Smm	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
514220447Smm	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
515220447Smm		return (error);
516219089Spjd
517248369Smm	if (nc == 5) { /* ZFS_IOC_POOL_STATS */
518219089Spjd		elem = NULL;
519219089Spjd		while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
520219089Spjd			if (nvpair_value_nvlist(elem, &nvp) == 0)
521219089Spjd				zfs_ioctl_compat_fix_stats_nvlist(nvp);
522219089Spjd		}
523219089Spjd		elem = NULL;
524219089Spjd	} else
525219089Spjd		zfs_ioctl_compat_fix_stats_nvlist(nv);
526219089Spjd
527220447Smm	error = zfs_ioctl_compat_put_nvlist(zc, nv);
528219089Spjd
529219089Spjd	nvlist_free(nv);
530220447Smm
531220447Smm	return (error);
532219089Spjd}
533219089Spjd
534220447Smmstatic int
535219089Spjdzfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
536219089Spjd{
537219089Spjd	nvlist_t *nv, *nva = NULL;
538220447Smm	int error;
539219089Spjd
540220447Smm	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
541220447Smm	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
542220447Smm		return (error);
543219089Spjd
544219089Spjd#ifdef _KERNEL
545219089Spjd	if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
546219089Spjd		nvlist_add_nvlist(nv, "used", nva);
547219089Spjd		nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
548219089Spjd	}
549219089Spjd
550219089Spjd	if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
551219089Spjd		nvlist_add_nvlist(nv, "available", nva);
552219089Spjd		nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
553219089Spjd	}
554219089Spjd#else
555219089Spjd	if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
556219089Spjd		nvlist_add_nvlist(nv, "allocated", nva);
557219089Spjd		nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
558219089Spjd	}
559219089Spjd
560219089Spjd	if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
561219089Spjd		nvlist_add_nvlist(nv, "free", nva);
562219089Spjd		nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
563219089Spjd	}
564219089Spjd#endif
565219089Spjd
566220447Smm	error = zfs_ioctl_compat_put_nvlist(zc, nv);
567219089Spjd
568219089Spjd	nvlist_free(nv);
569220447Smm
570220447Smm	return (error);
571219089Spjd}
572219089Spjd
573219089Spjd#ifndef _KERNEL
574219089Spjdint
575249643Smmzcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
576219089Spjd{
577219089Spjd	int nc, ret;
578219089Spjd	void *zc_c;
579219089Spjd	unsigned long ncmd;
580249643Smm	zfs_iocparm_t zp;
581219089Spjd
582248369Smm	switch (cflag) {
583248369Smm	case ZFS_CMD_COMPAT_NONE:
584249643Smm		ncmd = _IOWR('Z', request, struct zfs_iocparm);
585249643Smm		zp.zfs_cmd = (uint64_t)zc;
586249643Smm		zp.zfs_cmd_size = sizeof(zfs_cmd_t);
587249643Smm		zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT;
588249643Smm		return (ioctl(fd, ncmd, &zp));
589249643Smm	case ZFS_CMD_COMPAT_LZC:
590249643Smm		ncmd = _IOWR('Z', request, struct zfs_cmd);
591249643Smm		return (ioctl(fd, ncmd, zc));
592249643Smm	case ZFS_CMD_COMPAT_DEADMAN:
593249643Smm		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
594249643Smm		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
595249643Smm		break;
596248369Smm	case ZFS_CMD_COMPAT_V28:
597248369Smm		zc_c = malloc(sizeof(zfs_cmd_v28_t));
598249643Smm		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
599248369Smm		break;
600248369Smm	case ZFS_CMD_COMPAT_V15:
601249643Smm		nc = zfs_ioctl_v28_to_v15[request];
602219089Spjd		zc_c = malloc(sizeof(zfs_cmd_v15_t));
603219089Spjd		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
604248369Smm		break;
605248369Smm	default:
606219089Spjd		return (EINVAL);
607248369Smm	}
608219089Spjd
609249643Smm	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
610219089Spjd		return (ENOTSUP);
611219089Spjd
612249643Smm	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
613249643Smm
614219089Spjd	ret = ioctl(fd, ncmd, zc_c);
615219089Spjd	if (cflag == ZFS_CMD_COMPAT_V15 &&
616249643Smm	    nc == ZFS_IOC_POOL_IMPORT)
617249643Smm		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
618219089Spjd		    struct zfs_cmd_v15), zc_c);
619219089Spjd	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
620219089Spjd	free(zc_c);
621219089Spjd
622248369Smm	if (cflag == ZFS_CMD_COMPAT_V15) {
623248369Smm		switch (nc) {
624249643Smm		case ZFS_IOC_POOL_IMPORT:
625249643Smm		case ZFS_IOC_POOL_CONFIGS:
626249643Smm		case ZFS_IOC_POOL_STATS:
627249643Smm		case ZFS_IOC_POOL_TRYIMPORT:
628248369Smm			zfs_ioctl_compat_fix_stats(zc, nc);
629248369Smm			break;
630248369Smm		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
631248369Smm			zfs_ioctl_compat_pool_get_props(zc);
632248369Smm			break;
633248369Smm		}
634219089Spjd	}
635219089Spjd
636219089Spjd	return (ret);
637219089Spjd}
638219089Spjd#else /* _KERNEL */
639249643Smmint
640219089Spjdzfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
641219089Spjd{
642249643Smm	int error = 0;
643249643Smm
644249643Smm	/* are we creating a clone? */
645249643Smm	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
646249643Smm		*vec = ZFS_IOC_CLONE;
647249643Smm
648249643Smm	if (cflag == ZFS_CMD_COMPAT_V15) {
649219089Spjd		switch (*vec) {
650219089Spjd
651219089Spjd		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
652219089Spjd			zc->zc_cookie = POOL_SCAN_SCRUB;
653219089Spjd			break;
654219089Spjd		}
655249643Smm	}
656249643Smm
657249643Smm	return (error);
658219089Spjd}
659219089Spjd
660219089Spjdvoid
661219089Spjdzfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
662219089Spjd{
663219089Spjd	if (cflag == ZFS_CMD_COMPAT_V15) {
664219089Spjd		switch (vec) {
665249643Smm		case ZFS_IOC_POOL_CONFIGS:
666249643Smm		case ZFS_IOC_POOL_STATS:
667249643Smm		case ZFS_IOC_POOL_TRYIMPORT:
668219089Spjd			zfs_ioctl_compat_fix_stats(zc, vec);
669219089Spjd			break;
670219089Spjd		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
671219089Spjd			zfs_ioctl_compat_pool_get_props(zc);
672219089Spjd			break;
673219089Spjd		}
674219089Spjd	}
675219089Spjd}
676249643Smm
677249643Smmnvlist_t *
678249643Smmzfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
679249643Smm    const int cflag)
680249643Smm{
681249643Smm	nvlist_t *nvl, *tmpnvl, *hnvl;
682249643Smm	nvpair_t *elem;
683249643Smm	char *poolname, *snapname;
684249643Smm	int err;
685249643Smm
686249643Smm	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC)
687249643Smm		goto out;
688249643Smm
689249643Smm	switch (vec) {
690249643Smm	case ZFS_IOC_CREATE:
691249643Smm		nvl = fnvlist_alloc();
692249643Smm		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
693249643Smm		if (innvl != NULL) {
694249643Smm			fnvlist_add_nvlist(nvl, "props", innvl);
695249643Smm			nvlist_free(innvl);
696249643Smm		}
697249643Smm		return (nvl);
698249643Smm	break;
699249643Smm	case ZFS_IOC_CLONE:
700249643Smm		nvl = fnvlist_alloc();
701249643Smm		fnvlist_add_string(nvl, "origin", zc->zc_value);
702249643Smm		if (innvl != NULL) {
703249643Smm			fnvlist_add_nvlist(nvl, "props", innvl);
704249643Smm			nvlist_free(innvl);
705249643Smm		}
706249643Smm		return (nvl);
707249643Smm	break;
708249643Smm	case ZFS_IOC_SNAPSHOT:
709249643Smm		if (innvl == NULL)
710249643Smm			goto out;
711249643Smm		nvl = fnvlist_alloc();
712249643Smm		fnvlist_add_nvlist(nvl, "props", innvl);
713249643Smm		tmpnvl = fnvlist_alloc();
714249643Smm		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
715249643Smm		fnvlist_add_boolean(tmpnvl, snapname);
716249643Smm		kmem_free(snapname, strlen(snapname + 1));
717249643Smm		/* check if we are doing a recursive snapshot */
718249643Smm		if (zc->zc_cookie)
719249643Smm			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
720249643Smm			    tmpnvl);
721249643Smm		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
722249643Smm		fnvlist_free(tmpnvl);
723249643Smm		nvlist_free(innvl);
724249643Smm		/* strip dataset part from zc->zc_name */
725249643Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
726249643Smm		return (nvl);
727249643Smm	break;
728249643Smm	case ZFS_IOC_SPACE_SNAPS:
729249643Smm		nvl = fnvlist_alloc();
730249643Smm		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
731249643Smm		if (innvl != NULL)
732249643Smm			nvlist_free(innvl);
733249643Smm		return (nvl);
734249643Smm	break;
735249643Smm	case ZFS_IOC_DESTROY_SNAPS:
736249643Smm		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
737249643Smm			goto out;
738249643Smm		nvl = fnvlist_alloc();
739249643Smm		if (innvl != NULL) {
740249643Smm			fnvlist_add_nvlist(nvl, "snaps", innvl);
741249643Smm		} else {
742249643Smm			/*
743249643Smm			 * We are probably called by even older binaries,
744249643Smm			 * allocate and populate nvlist with recursive
745249643Smm			 * snapshots
746249643Smm			 */
747263410Sdelphij			if (zfs_component_namecheck(zc->zc_value, NULL,
748249643Smm			    NULL) == 0) {
749249643Smm				tmpnvl = fnvlist_alloc();
750249643Smm				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
751249643Smm				    zc->zc_value, tmpnvl) == 0)
752249643Smm					fnvlist_add_nvlist(nvl, "snaps",
753249643Smm					    tmpnvl);
754249643Smm				nvlist_free(tmpnvl);
755249643Smm			}
756249643Smm		}
757249643Smm		if (innvl != NULL)
758249643Smm			nvlist_free(innvl);
759249643Smm		/* strip dataset part from zc->zc_name */
760249643Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
761249643Smm		return (nvl);
762249643Smm	break;
763249643Smm	case ZFS_IOC_HOLD:
764249643Smm		nvl = fnvlist_alloc();
765249643Smm		tmpnvl = fnvlist_alloc();
766249643Smm		if (zc->zc_cleanup_fd != -1)
767249643Smm			fnvlist_add_int32(nvl, "cleanup_fd",
768249643Smm			    (int32_t)zc->zc_cleanup_fd);
769249643Smm		if (zc->zc_cookie) {
770249643Smm			hnvl = fnvlist_alloc();
771249643Smm			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
772249643Smm			    zc->zc_value, hnvl) == 0) {
773249643Smm				elem = NULL;
774249643Smm				while ((elem = nvlist_next_nvpair(hnvl,
775249643Smm				    elem)) != NULL) {
776249643Smm					nvlist_add_string(tmpnvl,
777249643Smm					    nvpair_name(elem), zc->zc_string);
778249643Smm				}
779249643Smm			}
780249643Smm			nvlist_free(hnvl);
781249643Smm		} else {
782249643Smm			snapname = kmem_asprintf("%s@%s", zc->zc_name,
783249643Smm			    zc->zc_value);
784249643Smm			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
785249643Smm			kmem_free(snapname, strlen(snapname + 1));
786249643Smm		}
787249643Smm		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
788249643Smm		nvlist_free(tmpnvl);
789249643Smm		if (innvl != NULL)
790249643Smm			nvlist_free(innvl);
791249643Smm		/* strip dataset part from zc->zc_name */
792249643Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
793249643Smm		return (nvl);
794249643Smm	break;
795249643Smm	case ZFS_IOC_RELEASE:
796249643Smm		nvl = fnvlist_alloc();
797249643Smm		tmpnvl = fnvlist_alloc();
798249643Smm		if (zc->zc_cookie) {
799249643Smm			hnvl = fnvlist_alloc();
800249643Smm			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
801249643Smm			    zc->zc_value, hnvl) == 0) {
802249643Smm				elem = NULL;
803249643Smm				while ((elem = nvlist_next_nvpair(hnvl,
804249643Smm				    elem)) != NULL) {
805249643Smm					fnvlist_add_boolean(tmpnvl,
806249643Smm					    zc->zc_string);
807249643Smm					fnvlist_add_nvlist(nvl,
808249643Smm					    nvpair_name(elem), tmpnvl);
809249643Smm				}
810249643Smm			}
811249643Smm			nvlist_free(hnvl);
812249643Smm		} else {
813249643Smm			snapname = kmem_asprintf("%s@%s", zc->zc_name,
814249643Smm			    zc->zc_value);
815249643Smm			fnvlist_add_boolean(tmpnvl, zc->zc_string);
816249643Smm			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
817249643Smm			kmem_free(snapname, strlen(snapname + 1));
818249643Smm		}
819249643Smm		nvlist_free(tmpnvl);
820249643Smm		if (innvl != NULL)
821249643Smm			nvlist_free(innvl);
822249643Smm		/* strip dataset part from zc->zc_name */
823249643Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
824249643Smm		return (nvl);
825249643Smm	break;
826249643Smm	}
827249643Smmout:
828249643Smm	return (innvl);
829249643Smm}
830249643Smm
831249643Smmnvlist_t *
832249643Smmzfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
833249643Smm    const int cflag)
834249643Smm{
835249643Smm	nvlist_t *tmpnvl;
836249643Smm
837249643Smm	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC)
838249643Smm		return (outnvl);
839249643Smm
840249643Smm	switch (vec) {
841249643Smm	case ZFS_IOC_SPACE_SNAPS:
842249643Smm		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
843249643Smm		(void) nvlist_lookup_uint64(outnvl, "compressed",
844249643Smm		    &zc->zc_objset_type);
845249643Smm		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
846249643Smm		    &zc->zc_perm_action);
847249643Smm		nvlist_free(outnvl);
848249643Smm		/* return empty outnvl */
849249643Smm		tmpnvl = fnvlist_alloc();
850249643Smm		return (tmpnvl);
851249643Smm	break;
852249643Smm	case ZFS_IOC_CREATE:
853249643Smm	case ZFS_IOC_CLONE:
854249643Smm	case ZFS_IOC_HOLD:
855249643Smm	case ZFS_IOC_RELEASE:
856249643Smm		nvlist_free(outnvl);
857249643Smm		/* return empty outnvl */
858249643Smm		tmpnvl = fnvlist_alloc();
859249643Smm		return (tmpnvl);
860249643Smm	break;
861249643Smm	}
862249643Smm
863249643Smm	return (outnvl);
864249643Smm}
865219089Spjd#endif /* KERNEL */
866