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/*
22268649Sdelphij * Copyright 2013 Xin Li <delphij@FreeBSD.org>. All rights reserved.
23247540Smm * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
24220447Smm * Portions Copyright 2005, 2010, Oracle and/or its affiliates.
25220447Smm * All rights reserved.
26219089Spjd * Use is subject to license terms.
27219089Spjd */
28219089Spjd
29219089Spjd#include <sys/types.h>
30219089Spjd#include <sys/param.h>
31219089Spjd#include <sys/cred.h>
32219089Spjd#include <sys/dmu.h>
33219089Spjd#include <sys/zio.h>
34219089Spjd#include <sys/nvpair.h>
35219089Spjd#include <sys/dsl_deleg.h>
36219089Spjd#include <sys/zfs_ioctl.h>
37248571Smm#include "zfs_namecheck.h"
38219089Spjd#include "zfs_ioctl_compat.h"
39219089Spjd
40247540Smmstatic int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
41247540SmmSYSCTL_DECL(_vfs_zfs_version);
42247540SmmSYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
43247540Smm    0, "ZFS_IOCTL_VERSION");
44247540Smm
45219089Spjd/*
46247540Smm * FreeBSD zfs_cmd compatibility with older binaries
47219089Spjd * appropriately remap/extend the zfs_cmd_t structure
48219089Spjd */
49219089Spjdvoid
50219089Spjdzfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
51219089Spjd{
52219089Spjd	zfs_cmd_v15_t *zc_c;
53247540Smm	zfs_cmd_v28_t *zc28_c;
54248571Smm	zfs_cmd_deadman_t *zcdm_c;
55268649Sdelphij	zfs_cmd_zcmd_t *zcmd_c;
56219089Spjd
57247540Smm	switch (cflag) {
58268649Sdelphij	case ZFS_CMD_COMPAT_ZCMD:
59268649Sdelphij		zcmd_c = (void *)addr;
60268649Sdelphij		/* zc */
61268649Sdelphij		strlcpy(zc->zc_name, zcmd_c->zc_name, MAXPATHLEN);
62268649Sdelphij		strlcpy(zc->zc_value, zcmd_c->zc_value, MAXPATHLEN * 2);
63268649Sdelphij		strlcpy(zc->zc_string, zcmd_c->zc_string, MAXPATHLEN);
64268649Sdelphij
65268649Sdelphij#define ZCMD_COPY(field) zc->field = zcmd_c->field
66268649Sdelphij		ZCMD_COPY(zc_nvlist_src);
67268649Sdelphij		ZCMD_COPY(zc_nvlist_src_size);
68268649Sdelphij		ZCMD_COPY(zc_nvlist_dst);
69268649Sdelphij		ZCMD_COPY(zc_nvlist_dst_size);
70268649Sdelphij		ZCMD_COPY(zc_nvlist_dst_filled);
71268649Sdelphij		ZCMD_COPY(zc_pad2);
72268649Sdelphij		ZCMD_COPY(zc_history);
73268649Sdelphij		ZCMD_COPY(zc_guid);
74268649Sdelphij		ZCMD_COPY(zc_nvlist_conf);
75268649Sdelphij		ZCMD_COPY(zc_nvlist_conf_size);
76268649Sdelphij		ZCMD_COPY(zc_cookie);
77268649Sdelphij		ZCMD_COPY(zc_objset_type);
78268649Sdelphij		ZCMD_COPY(zc_perm_action);
79268649Sdelphij		ZCMD_COPY(zc_history_len);
80268649Sdelphij		ZCMD_COPY(zc_history_offset);
81268649Sdelphij		ZCMD_COPY(zc_obj);
82268649Sdelphij		ZCMD_COPY(zc_iflags);
83268649Sdelphij		ZCMD_COPY(zc_share);
84268649Sdelphij		ZCMD_COPY(zc_jailid);
85268649Sdelphij		ZCMD_COPY(zc_objset_stats);
86268649Sdelphij
87268649Sdelphij		/*
88268649Sdelphij		 * zc_begin_record, zc_inject_record didn't change in embedeed-data
89268649Sdelphij		 * block pointers
90268649Sdelphij		 *
91268649Sdelphij		 * TODO: CTASSERT?
92268649Sdelphij		 */
93268649Sdelphij		ZCMD_COPY(zc_begin_record);
94268649Sdelphij		ZCMD_COPY(zc_inject_record);
95268649Sdelphij
96268649Sdelphij		/* boolean_t -> uint32_t */
97268649Sdelphij		zc->zc_defer_destroy = (uint32_t)(zcmd_c->zc_defer_destroy);
98268649Sdelphij		zc->zc_flags = 0;
99268649Sdelphij
100268649Sdelphij		ZCMD_COPY(zc_action_handle);
101268649Sdelphij		ZCMD_COPY(zc_cleanup_fd);
102268649Sdelphij		ZCMD_COPY(zc_simple);
103268649Sdelphij		bcopy(zcmd_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
104268649Sdelphij		ZCMD_COPY(zc_sendobj);
105268649Sdelphij		ZCMD_COPY(zc_fromobj);
106268649Sdelphij		ZCMD_COPY(zc_createtxg);
107268649Sdelphij		ZCMD_COPY(zc_stat);
108268649Sdelphij#undef ZCMD_COPY
109268649Sdelphij
110268649Sdelphij		break;
111268649Sdelphij
112248571Smm	case ZFS_CMD_COMPAT_DEADMAN:
113248571Smm		zcdm_c = (void *)addr;
114248571Smm		/* zc */
115248571Smm		strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN);
116248571Smm		strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2);
117248571Smm		strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN);
118248571Smm		zc->zc_guid = zcdm_c->zc_guid;
119248571Smm		zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf;
120248571Smm		zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size;
121248571Smm		zc->zc_nvlist_src = zcdm_c->zc_nvlist_src;
122248571Smm		zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size;
123248571Smm		zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst;
124248571Smm		zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size;
125248571Smm		zc->zc_cookie = zcdm_c->zc_cookie;
126248571Smm		zc->zc_objset_type = zcdm_c->zc_objset_type;
127248571Smm		zc->zc_perm_action = zcdm_c->zc_perm_action;
128248571Smm		zc->zc_history = zcdm_c->zc_history;
129248571Smm		zc->zc_history_len = zcdm_c->zc_history_len;
130248571Smm		zc->zc_history_offset = zcdm_c->zc_history_offset;
131248571Smm		zc->zc_obj = zcdm_c->zc_obj;
132248571Smm		zc->zc_iflags = zcdm_c->zc_iflags;
133248571Smm		zc->zc_share = zcdm_c->zc_share;
134248571Smm		zc->zc_jailid = zcdm_c->zc_jailid;
135248571Smm		zc->zc_objset_stats = zcdm_c->zc_objset_stats;
136248571Smm		zc->zc_begin_record = zcdm_c->zc_begin_record;
137248571Smm		zc->zc_defer_destroy = zcdm_c->zc_defer_destroy;
138268649Sdelphij		(void)zcdm_c->zc_temphold;
139248571Smm		zc->zc_action_handle = zcdm_c->zc_action_handle;
140248571Smm		zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd;
141248571Smm		zc->zc_simple = zcdm_c->zc_simple;
142248571Smm		bcopy(zcdm_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
143248571Smm		zc->zc_sendobj = zcdm_c->zc_sendobj;
144248571Smm		zc->zc_fromobj = zcdm_c->zc_fromobj;
145248571Smm		zc->zc_createtxg = zcdm_c->zc_createtxg;
146248571Smm		zc->zc_stat = zcdm_c->zc_stat;
147248571Smm
148248571Smm		/* zc_inject_record doesn't change in libzfs_core */
149248571Smm		zcdm_c->zc_inject_record = zc->zc_inject_record;
150248571Smm
151248571Smm		/* we always assume zc_nvlist_dst_filled is true */
152248571Smm		zc->zc_nvlist_dst_filled = B_TRUE;
153268649Sdelphij		break;
154248571Smm
155247540Smm	case ZFS_CMD_COMPAT_V28:
156247540Smm		zc28_c = (void *)addr;
157247540Smm
158247540Smm		/* zc */
159247540Smm		strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
160247540Smm		strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
161247540Smm		strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
162247540Smm		zc->zc_guid = zc28_c->zc_guid;
163247540Smm		zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
164247540Smm		zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
165247540Smm		zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
166247540Smm		zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
167247540Smm		zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
168247540Smm		zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
169247540Smm		zc->zc_cookie = zc28_c->zc_cookie;
170247540Smm		zc->zc_objset_type = zc28_c->zc_objset_type;
171247540Smm		zc->zc_perm_action = zc28_c->zc_perm_action;
172247540Smm		zc->zc_history = zc28_c->zc_history;
173247540Smm		zc->zc_history_len = zc28_c->zc_history_len;
174247540Smm		zc->zc_history_offset = zc28_c->zc_history_offset;
175247540Smm		zc->zc_obj = zc28_c->zc_obj;
176247540Smm		zc->zc_iflags = zc28_c->zc_iflags;
177247540Smm		zc->zc_share = zc28_c->zc_share;
178247540Smm		zc->zc_jailid = zc28_c->zc_jailid;
179247540Smm		zc->zc_objset_stats = zc28_c->zc_objset_stats;
180247540Smm		zc->zc_begin_record = zc28_c->zc_begin_record;
181247540Smm		zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
182268649Sdelphij		(void)zc28_c->zc_temphold;
183247540Smm		zc->zc_action_handle = zc28_c->zc_action_handle;
184247540Smm		zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
185247540Smm		zc->zc_simple = zc28_c->zc_simple;
186247540Smm		bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad));
187247540Smm		zc->zc_sendobj = zc28_c->zc_sendobj;
188247540Smm		zc->zc_fromobj = zc28_c->zc_fromobj;
189247540Smm		zc->zc_createtxg = zc28_c->zc_createtxg;
190247540Smm		zc->zc_stat = zc28_c->zc_stat;
191247540Smm
192247540Smm		/* zc->zc_inject_record */
193247540Smm		zc->zc_inject_record.zi_objset =
194247540Smm		    zc28_c->zc_inject_record.zi_objset;
195247540Smm		zc->zc_inject_record.zi_object =
196247540Smm		    zc28_c->zc_inject_record.zi_object;
197247540Smm		zc->zc_inject_record.zi_start =
198247540Smm		    zc28_c->zc_inject_record.zi_start;
199247540Smm		zc->zc_inject_record.zi_end =
200247540Smm		    zc28_c->zc_inject_record.zi_end;
201247540Smm		zc->zc_inject_record.zi_guid =
202247540Smm		    zc28_c->zc_inject_record.zi_guid;
203247540Smm		zc->zc_inject_record.zi_level =
204247540Smm		    zc28_c->zc_inject_record.zi_level;
205247540Smm		zc->zc_inject_record.zi_error =
206247540Smm		    zc28_c->zc_inject_record.zi_error;
207247540Smm		zc->zc_inject_record.zi_type =
208247540Smm		    zc28_c->zc_inject_record.zi_type;
209247540Smm		zc->zc_inject_record.zi_freq =
210247540Smm		    zc28_c->zc_inject_record.zi_freq;
211247540Smm		zc->zc_inject_record.zi_failfast =
212247540Smm		    zc28_c->zc_inject_record.zi_failfast;
213247540Smm		strlcpy(zc->zc_inject_record.zi_func,
214247540Smm		    zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
215247540Smm		zc->zc_inject_record.zi_iotype =
216247540Smm		    zc28_c->zc_inject_record.zi_iotype;
217247540Smm		zc->zc_inject_record.zi_duration =
218247540Smm		    zc28_c->zc_inject_record.zi_duration;
219247540Smm		zc->zc_inject_record.zi_timer =
220247540Smm		    zc28_c->zc_inject_record.zi_timer;
221247540Smm		zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
222247540Smm		zc->zc_inject_record.zi_pad = 0;
223247540Smm		break;
224247540Smm
225247540Smm	case ZFS_CMD_COMPAT_V15:
226219089Spjd		zc_c = (void *)addr;
227219089Spjd
228219089Spjd		/* zc */
229247540Smm		strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
230247540Smm		strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
231247540Smm		strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
232219089Spjd		zc->zc_guid = zc_c->zc_guid;
233219089Spjd		zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
234219089Spjd		zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
235219089Spjd		zc->zc_nvlist_src = zc_c->zc_nvlist_src;
236219089Spjd		zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
237219089Spjd		zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
238219089Spjd		zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
239219089Spjd		zc->zc_cookie = zc_c->zc_cookie;
240219089Spjd		zc->zc_objset_type = zc_c->zc_objset_type;
241219089Spjd		zc->zc_perm_action = zc_c->zc_perm_action;
242219089Spjd		zc->zc_history = zc_c->zc_history;
243219089Spjd		zc->zc_history_len = zc_c->zc_history_len;
244219089Spjd		zc->zc_history_offset = zc_c->zc_history_offset;
245219089Spjd		zc->zc_obj = zc_c->zc_obj;
246219089Spjd		zc->zc_share = zc_c->zc_share;
247219089Spjd		zc->zc_jailid = zc_c->zc_jailid;
248219089Spjd		zc->zc_objset_stats = zc_c->zc_objset_stats;
249219089Spjd		zc->zc_begin_record = zc_c->zc_begin_record;
250219089Spjd
251219089Spjd		/* zc->zc_inject_record */
252219089Spjd		zc->zc_inject_record.zi_objset =
253219089Spjd		    zc_c->zc_inject_record.zi_objset;
254219089Spjd		zc->zc_inject_record.zi_object =
255219089Spjd		    zc_c->zc_inject_record.zi_object;
256219089Spjd		zc->zc_inject_record.zi_start =
257219089Spjd		    zc_c->zc_inject_record.zi_start;
258219089Spjd		zc->zc_inject_record.zi_end =
259219089Spjd		    zc_c->zc_inject_record.zi_end;
260219089Spjd		zc->zc_inject_record.zi_guid =
261219089Spjd		    zc_c->zc_inject_record.zi_guid;
262219089Spjd		zc->zc_inject_record.zi_level =
263219089Spjd		    zc_c->zc_inject_record.zi_level;
264219089Spjd		zc->zc_inject_record.zi_error =
265219089Spjd		    zc_c->zc_inject_record.zi_error;
266219089Spjd		zc->zc_inject_record.zi_type =
267219089Spjd		    zc_c->zc_inject_record.zi_type;
268219089Spjd		zc->zc_inject_record.zi_freq =
269219089Spjd		    zc_c->zc_inject_record.zi_freq;
270219089Spjd		zc->zc_inject_record.zi_failfast =
271219089Spjd		    zc_c->zc_inject_record.zi_failfast;
272247540Smm		break;
273219089Spjd	}
274219089Spjd}
275219089Spjd
276219089Spjdvoid
277248571Smmzfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request,
278248571Smm    const int cflag)
279219089Spjd{
280219089Spjd	zfs_cmd_v15_t *zc_c;
281247540Smm	zfs_cmd_v28_t *zc28_c;
282248571Smm	zfs_cmd_deadman_t *zcdm_c;
283268649Sdelphij	zfs_cmd_zcmd_t *zcmd_c;
284219089Spjd
285219089Spjd	switch (cflag) {
286268649Sdelphij	case ZFS_CMD_COMPAT_ZCMD:
287268649Sdelphij		zcmd_c = (void *)addr;
288268649Sdelphij		/* zc */
289268649Sdelphij		strlcpy(zcmd_c->zc_name, zc->zc_name, MAXPATHLEN);
290268649Sdelphij		strlcpy(zcmd_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
291268649Sdelphij		strlcpy(zcmd_c->zc_string, zc->zc_string, MAXPATHLEN);
292268649Sdelphij
293268649Sdelphij#define ZCMD_COPY(field) zcmd_c->field = zc->field
294268649Sdelphij		ZCMD_COPY(zc_nvlist_src);
295268649Sdelphij		ZCMD_COPY(zc_nvlist_src_size);
296268649Sdelphij		ZCMD_COPY(zc_nvlist_dst);
297268649Sdelphij		ZCMD_COPY(zc_nvlist_dst_size);
298268649Sdelphij		ZCMD_COPY(zc_nvlist_dst_filled);
299268649Sdelphij		ZCMD_COPY(zc_pad2);
300268649Sdelphij		ZCMD_COPY(zc_history);
301268649Sdelphij		ZCMD_COPY(zc_guid);
302268649Sdelphij		ZCMD_COPY(zc_nvlist_conf);
303268649Sdelphij		ZCMD_COPY(zc_nvlist_conf_size);
304268649Sdelphij		ZCMD_COPY(zc_cookie);
305268649Sdelphij		ZCMD_COPY(zc_objset_type);
306268649Sdelphij		ZCMD_COPY(zc_perm_action);
307268649Sdelphij		ZCMD_COPY(zc_history_len);
308268649Sdelphij		ZCMD_COPY(zc_history_offset);
309268649Sdelphij		ZCMD_COPY(zc_obj);
310268649Sdelphij		ZCMD_COPY(zc_iflags);
311268649Sdelphij		ZCMD_COPY(zc_share);
312268649Sdelphij		ZCMD_COPY(zc_jailid);
313268649Sdelphij		ZCMD_COPY(zc_objset_stats);
314268649Sdelphij
315268649Sdelphij		/*
316268649Sdelphij		 * zc_begin_record, zc_inject_record didn't change in embedeed-data
317268649Sdelphij		 * block pointers
318268649Sdelphij		 *
319268649Sdelphij		 * TODO: CTASSERT?
320268649Sdelphij		 */
321268649Sdelphij		ZCMD_COPY(zc_begin_record);
322268649Sdelphij		ZCMD_COPY(zc_inject_record);
323268649Sdelphij
324268649Sdelphij		/* boolean_t -> uint32_t */
325268649Sdelphij		zcmd_c->zc_defer_destroy = (uint32_t)(zc->zc_defer_destroy);
326268649Sdelphij		zcmd_c->zc_temphold = 0;
327268649Sdelphij
328268649Sdelphij		ZCMD_COPY(zc_action_handle);
329268649Sdelphij		ZCMD_COPY(zc_cleanup_fd);
330268649Sdelphij		ZCMD_COPY(zc_simple);
331268649Sdelphij		bcopy(zc->zc_pad, zcmd_c->zc_pad, sizeof(zcmd_c->zc_pad));
332268649Sdelphij		ZCMD_COPY(zc_sendobj);
333268649Sdelphij		ZCMD_COPY(zc_fromobj);
334268649Sdelphij		ZCMD_COPY(zc_createtxg);
335268649Sdelphij		ZCMD_COPY(zc_stat);
336268649Sdelphij#undef ZCMD_COPY
337268649Sdelphij
338268649Sdelphij		break;
339268649Sdelphij
340248571Smm	case ZFS_CMD_COMPAT_DEADMAN:
341248571Smm		zcdm_c = (void *)addr;
342248571Smm
343248571Smm		strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN);
344248571Smm		strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
345248571Smm		strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN);
346248571Smm		zcdm_c->zc_guid = zc->zc_guid;
347248571Smm		zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf;
348248571Smm		zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
349248571Smm		zcdm_c->zc_nvlist_src = zc->zc_nvlist_src;
350248571Smm		zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
351248571Smm		zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst;
352248571Smm		zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
353248571Smm		zcdm_c->zc_cookie = zc->zc_cookie;
354248571Smm		zcdm_c->zc_objset_type = zc->zc_objset_type;
355248571Smm		zcdm_c->zc_perm_action = zc->zc_perm_action;
356248571Smm		zcdm_c->zc_history = zc->zc_history;
357248571Smm		zcdm_c->zc_history_len = zc->zc_history_len;
358248571Smm		zcdm_c->zc_history_offset = zc->zc_history_offset;
359248571Smm		zcdm_c->zc_obj = zc->zc_obj;
360248571Smm		zcdm_c->zc_iflags = zc->zc_iflags;
361248571Smm		zcdm_c->zc_share = zc->zc_share;
362248571Smm		zcdm_c->zc_jailid = zc->zc_jailid;
363248571Smm		zcdm_c->zc_objset_stats = zc->zc_objset_stats;
364248571Smm		zcdm_c->zc_begin_record = zc->zc_begin_record;
365248571Smm		zcdm_c->zc_defer_destroy = zc->zc_defer_destroy;
366268649Sdelphij		zcdm_c->zc_temphold = 0;
367248571Smm		zcdm_c->zc_action_handle = zc->zc_action_handle;
368248571Smm		zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd;
369248571Smm		zcdm_c->zc_simple = zc->zc_simple;
370248571Smm		bcopy(zc->zc_pad, zcdm_c->zc_pad, sizeof(zcdm_c->zc_pad));
371248571Smm		zcdm_c->zc_sendobj = zc->zc_sendobj;
372248571Smm		zcdm_c->zc_fromobj = zc->zc_fromobj;
373248571Smm		zcdm_c->zc_createtxg = zc->zc_createtxg;
374248571Smm		zcdm_c->zc_stat = zc->zc_stat;
375248571Smm
376248571Smm		/* zc_inject_record doesn't change in libzfs_core */
377248571Smm		zc->zc_inject_record = zcdm_c->zc_inject_record;
378248571Smm#ifndef _KERNEL
379248571Smm		if (request == ZFS_IOC_RECV)
380248571Smm			strlcpy(zcdm_c->zc_top_ds,
381248571Smm			    zc->zc_value + strlen(zc->zc_value) + 1,
382248571Smm			    (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1);
383248571Smm#endif
384268649Sdelphij		break;
385248571Smm
386247540Smm	case ZFS_CMD_COMPAT_V28:
387247540Smm		zc28_c = (void *)addr;
388247540Smm
389247540Smm		strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
390247540Smm		strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
391247540Smm		strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
392247540Smm		zc28_c->zc_guid = zc->zc_guid;
393247540Smm		zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
394247540Smm		zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
395247540Smm		zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
396247540Smm		zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
397247540Smm		zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
398247540Smm		zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
399247540Smm		zc28_c->zc_cookie = zc->zc_cookie;
400247540Smm		zc28_c->zc_objset_type = zc->zc_objset_type;
401247540Smm		zc28_c->zc_perm_action = zc->zc_perm_action;
402247540Smm		zc28_c->zc_history = zc->zc_history;
403247540Smm		zc28_c->zc_history_len = zc->zc_history_len;
404247540Smm		zc28_c->zc_history_offset = zc->zc_history_offset;
405247540Smm		zc28_c->zc_obj = zc->zc_obj;
406247540Smm		zc28_c->zc_iflags = zc->zc_iflags;
407247540Smm		zc28_c->zc_share = zc->zc_share;
408247540Smm		zc28_c->zc_jailid = zc->zc_jailid;
409247540Smm		zc28_c->zc_objset_stats = zc->zc_objset_stats;
410247540Smm		zc28_c->zc_begin_record = zc->zc_begin_record;
411247540Smm		zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
412268649Sdelphij		zc28_c->zc_temphold = 0;
413247540Smm		zc28_c->zc_action_handle = zc->zc_action_handle;
414247540Smm		zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
415247540Smm		zc28_c->zc_simple = zc->zc_simple;
416247540Smm		bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad));
417247540Smm		zc28_c->zc_sendobj = zc->zc_sendobj;
418247540Smm		zc28_c->zc_fromobj = zc->zc_fromobj;
419247540Smm		zc28_c->zc_createtxg = zc->zc_createtxg;
420247540Smm		zc28_c->zc_stat = zc->zc_stat;
421248571Smm#ifndef _KERNEL
422248571Smm		if (request == ZFS_IOC_RECV)
423248571Smm			strlcpy(zc28_c->zc_top_ds,
424248571Smm			    zc->zc_value + strlen(zc->zc_value) + 1,
425248571Smm			    MAXPATHLEN * 2 - strlen(zc->zc_value) - 1);
426248571Smm#endif
427247540Smm		/* zc_inject_record */
428247540Smm		zc28_c->zc_inject_record.zi_objset =
429247540Smm		    zc->zc_inject_record.zi_objset;
430247540Smm		zc28_c->zc_inject_record.zi_object =
431247540Smm		    zc->zc_inject_record.zi_object;
432247540Smm		zc28_c->zc_inject_record.zi_start =
433247540Smm		    zc->zc_inject_record.zi_start;
434247540Smm		zc28_c->zc_inject_record.zi_end =
435247540Smm		    zc->zc_inject_record.zi_end;
436247540Smm		zc28_c->zc_inject_record.zi_guid =
437247540Smm		    zc->zc_inject_record.zi_guid;
438247540Smm		zc28_c->zc_inject_record.zi_level =
439247540Smm		    zc->zc_inject_record.zi_level;
440247540Smm		zc28_c->zc_inject_record.zi_error =
441247540Smm		    zc->zc_inject_record.zi_error;
442247540Smm		zc28_c->zc_inject_record.zi_type =
443247540Smm		    zc->zc_inject_record.zi_type;
444247540Smm		zc28_c->zc_inject_record.zi_freq =
445247540Smm		    zc->zc_inject_record.zi_freq;
446247540Smm		zc28_c->zc_inject_record.zi_failfast =
447247540Smm		    zc->zc_inject_record.zi_failfast;
448247540Smm		strlcpy(zc28_c->zc_inject_record.zi_func,
449247540Smm		    zc->zc_inject_record.zi_func, MAXNAMELEN);
450247540Smm		zc28_c->zc_inject_record.zi_iotype =
451247540Smm		    zc->zc_inject_record.zi_iotype;
452247540Smm		zc28_c->zc_inject_record.zi_duration =
453247540Smm		    zc->zc_inject_record.zi_duration;
454247540Smm		zc28_c->zc_inject_record.zi_timer =
455247540Smm		    zc->zc_inject_record.zi_timer;
456247540Smm		break;
457247540Smm
458219089Spjd	case ZFS_CMD_COMPAT_V15:
459219089Spjd		zc_c = (void *)addr;
460219089Spjd
461219089Spjd		/* zc */
462247540Smm		strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
463247540Smm		strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
464247540Smm		strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
465219089Spjd		zc_c->zc_guid = zc->zc_guid;
466219089Spjd		zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
467219089Spjd		zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
468219089Spjd		zc_c->zc_nvlist_src = zc->zc_nvlist_src;
469219089Spjd		zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
470219089Spjd		zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
471219089Spjd		zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
472219089Spjd		zc_c->zc_cookie = zc->zc_cookie;
473219089Spjd		zc_c->zc_objset_type = zc->zc_objset_type;
474219089Spjd		zc_c->zc_perm_action = zc->zc_perm_action;
475219089Spjd		zc_c->zc_history = zc->zc_history;
476219089Spjd		zc_c->zc_history_len = zc->zc_history_len;
477219089Spjd		zc_c->zc_history_offset = zc->zc_history_offset;
478219089Spjd		zc_c->zc_obj = zc->zc_obj;
479219089Spjd		zc_c->zc_share = zc->zc_share;
480219089Spjd		zc_c->zc_jailid = zc->zc_jailid;
481219089Spjd		zc_c->zc_objset_stats = zc->zc_objset_stats;
482219089Spjd		zc_c->zc_begin_record = zc->zc_begin_record;
483219089Spjd
484219089Spjd		/* zc_inject_record */
485219089Spjd		zc_c->zc_inject_record.zi_objset =
486219089Spjd		    zc->zc_inject_record.zi_objset;
487219089Spjd		zc_c->zc_inject_record.zi_object =
488219089Spjd		    zc->zc_inject_record.zi_object;
489219089Spjd		zc_c->zc_inject_record.zi_start =
490219089Spjd		    zc->zc_inject_record.zi_start;
491219089Spjd		zc_c->zc_inject_record.zi_end =
492219089Spjd		    zc->zc_inject_record.zi_end;
493219089Spjd		zc_c->zc_inject_record.zi_guid =
494219089Spjd		    zc->zc_inject_record.zi_guid;
495219089Spjd		zc_c->zc_inject_record.zi_level =
496219089Spjd		    zc->zc_inject_record.zi_level;
497219089Spjd		zc_c->zc_inject_record.zi_error =
498219089Spjd		    zc->zc_inject_record.zi_error;
499219089Spjd		zc_c->zc_inject_record.zi_type =
500219089Spjd		    zc->zc_inject_record.zi_type;
501219089Spjd		zc_c->zc_inject_record.zi_freq =
502219089Spjd		    zc->zc_inject_record.zi_freq;
503219089Spjd		zc_c->zc_inject_record.zi_failfast =
504219089Spjd		    zc->zc_inject_record.zi_failfast;
505219089Spjd
506219089Spjd		break;
507219089Spjd	}
508219089Spjd}
509219089Spjd
510219089Spjdstatic int
511220447Smmzfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
512220447Smm    nvlist_t **nvp)
513219089Spjd{
514220447Smm	char *packed;
515220447Smm	int error;
516220447Smm	nvlist_t *list = NULL;
517219089Spjd
518220447Smm	/*
519220447Smm	 * Read in and unpack the user-supplied nvlist.
520220447Smm	 */
521220447Smm	if (size == 0)
522220447Smm		return (EINVAL);
523219089Spjd
524220447Smm#ifdef _KERNEL
525220447Smm	packed = kmem_alloc(size, KM_SLEEP);
526220447Smm	if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
527220447Smm	    iflag)) != 0) {
528220447Smm		kmem_free(packed, size);
529220447Smm		return (error);
530220447Smm	}
531220447Smm#else
532220447Smm	packed = (void *)(uintptr_t)nvl;
533220447Smm#endif
534220447Smm
535220447Smm	error = nvlist_unpack(packed, size, &list, 0);
536220447Smm
537220447Smm#ifdef _KERNEL
538220447Smm	kmem_free(packed, size);
539220447Smm#endif
540220447Smm
541220447Smm	if (error != 0)
542220447Smm		return (error);
543220447Smm
544220447Smm	*nvp = list;
545220447Smm	return (0);
546219089Spjd}
547219089Spjd
548220447Smmstatic int
549220447Smmzfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
550220447Smm{
551220447Smm	char *packed = NULL;
552220447Smm	int error = 0;
553220447Smm	size_t size;
554220447Smm
555220447Smm	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
556220447Smm
557220447Smm#ifdef _KERNEL
558220447Smm	packed = kmem_alloc(size, KM_SLEEP);
559220447Smm	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
560220447Smm	    KM_SLEEP) == 0);
561220447Smm
562220447Smm	if (ddi_copyout(packed,
563220447Smm	    (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
564220447Smm		error = EFAULT;
565220447Smm	kmem_free(packed, size);
566220447Smm#else
567220447Smm	packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
568220447Smm	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
569220447Smm	    0) == 0);
570220447Smm#endif
571220447Smm
572220447Smm	zc->zc_nvlist_dst_size = size;
573220447Smm	return (error);
574220447Smm}
575220447Smm
576219089Spjdstatic void
577219089Spjdzfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
578219089Spjd{
579219089Spjd	nvlist_t **child;
580219089Spjd	nvlist_t *nvroot = NULL;
581219089Spjd	vdev_stat_t *vs;
582219089Spjd	uint_t c, children, nelem;
583219089Spjd
584219089Spjd	if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
585219089Spjd	    &child, &children) == 0) {
586219089Spjd		for (c = 0; c < children; c++) {
587219089Spjd			zfs_ioctl_compat_fix_stats_nvlist(child[c]);
588219089Spjd		}
589219089Spjd	}
590219089Spjd
591219089Spjd	if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
592219089Spjd	    &nvroot) == 0)
593219089Spjd		zfs_ioctl_compat_fix_stats_nvlist(nvroot);
594219089Spjd#ifdef _KERNEL
595219089Spjd	if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
596219089Spjd#else
597219089Spjd	if ((nvlist_lookup_uint64_array(nvl, "stats",
598219089Spjd#endif
599219089Spjd
600219089Spjd	    (uint64_t **)&vs, &nelem) == 0)) {
601219089Spjd		nvlist_add_uint64_array(nvl,
602219089Spjd#ifdef _KERNEL
603219089Spjd		    "stats",
604219089Spjd#else
605219089Spjd		    ZPOOL_CONFIG_VDEV_STATS,
606219089Spjd#endif
607219089Spjd		    (uint64_t *)vs, nelem);
608219089Spjd#ifdef _KERNEL
609219089Spjd		nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
610219089Spjd#else
611219089Spjd		nvlist_remove(nvl, "stats",
612219089Spjd#endif
613219089Spjd		    DATA_TYPE_UINT64_ARRAY);
614219089Spjd	}
615219089Spjd}
616219089Spjd
617220447Smmstatic int
618247540Smmzfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
619219089Spjd{
620219089Spjd	nvlist_t *nv, *nvp = NULL;
621219089Spjd	nvpair_t *elem;
622220447Smm	int error;
623219089Spjd
624220447Smm	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
625220447Smm	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
626220447Smm		return (error);
627219089Spjd
628247540Smm	if (nc == 5) { /* ZFS_IOC_POOL_STATS */
629219089Spjd		elem = NULL;
630219089Spjd		while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
631219089Spjd			if (nvpair_value_nvlist(elem, &nvp) == 0)
632219089Spjd				zfs_ioctl_compat_fix_stats_nvlist(nvp);
633219089Spjd		}
634219089Spjd		elem = NULL;
635219089Spjd	} else
636219089Spjd		zfs_ioctl_compat_fix_stats_nvlist(nv);
637219089Spjd
638220447Smm	error = zfs_ioctl_compat_put_nvlist(zc, nv);
639219089Spjd
640219089Spjd	nvlist_free(nv);
641220447Smm
642220447Smm	return (error);
643219089Spjd}
644219089Spjd
645220447Smmstatic int
646219089Spjdzfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
647219089Spjd{
648219089Spjd	nvlist_t *nv, *nva = NULL;
649220447Smm	int error;
650219089Spjd
651220447Smm	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
652220447Smm	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
653220447Smm		return (error);
654219089Spjd
655219089Spjd#ifdef _KERNEL
656219089Spjd	if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
657219089Spjd		nvlist_add_nvlist(nv, "used", nva);
658219089Spjd		nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
659219089Spjd	}
660219089Spjd
661219089Spjd	if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
662219089Spjd		nvlist_add_nvlist(nv, "available", nva);
663219089Spjd		nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
664219089Spjd	}
665219089Spjd#else
666219089Spjd	if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
667219089Spjd		nvlist_add_nvlist(nv, "allocated", nva);
668219089Spjd		nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
669219089Spjd	}
670219089Spjd
671219089Spjd	if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
672219089Spjd		nvlist_add_nvlist(nv, "free", nva);
673219089Spjd		nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
674219089Spjd	}
675219089Spjd#endif
676219089Spjd
677220447Smm	error = zfs_ioctl_compat_put_nvlist(zc, nv);
678219089Spjd
679219089Spjd	nvlist_free(nv);
680220447Smm
681220447Smm	return (error);
682219089Spjd}
683219089Spjd
684219089Spjd#ifndef _KERNEL
685219089Spjdint
686248571Smmzcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
687219089Spjd{
688219089Spjd	int nc, ret;
689219089Spjd	void *zc_c;
690219089Spjd	unsigned long ncmd;
691249319Smm	zfs_iocparm_t zp;
692219089Spjd
693247540Smm	switch (cflag) {
694247540Smm	case ZFS_CMD_COMPAT_NONE:
695249319Smm		ncmd = _IOWR('Z', request, struct zfs_iocparm);
696249319Smm		zp.zfs_cmd = (uint64_t)zc;
697249319Smm		zp.zfs_cmd_size = sizeof(zfs_cmd_t);
698249319Smm		zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT;
699249319Smm		return (ioctl(fd, ncmd, &zp));
700268786Sdelphij	case ZFS_CMD_COMPAT_ZCMD:
701268786Sdelphij		ncmd = _IOWR('Z', request, struct zfs_iocparm);
702268786Sdelphij		zp.zfs_cmd = (uint64_t)zc;
703268786Sdelphij		zp.zfs_cmd_size = sizeof(zfs_cmd_zcmd_t);
704268786Sdelphij		zp.zfs_ioctl_version = ZFS_IOCVER_ZCMD;
705268786Sdelphij		return (ioctl(fd, ncmd, &zp));
706249319Smm	case ZFS_CMD_COMPAT_LZC:
707248571Smm		ncmd = _IOWR('Z', request, struct zfs_cmd);
708249319Smm		return (ioctl(fd, ncmd, zc));
709248571Smm	case ZFS_CMD_COMPAT_DEADMAN:
710248571Smm		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
711248571Smm		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
712248571Smm		break;
713247540Smm	case ZFS_CMD_COMPAT_V28:
714247540Smm		zc_c = malloc(sizeof(zfs_cmd_v28_t));
715248571Smm		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
716247540Smm		break;
717247540Smm	case ZFS_CMD_COMPAT_V15:
718248571Smm		nc = zfs_ioctl_v28_to_v15[request];
719219089Spjd		zc_c = malloc(sizeof(zfs_cmd_v15_t));
720219089Spjd		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
721247540Smm		break;
722247540Smm	default:
723219089Spjd		return (EINVAL);
724247540Smm	}
725219089Spjd
726248571Smm	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
727219089Spjd		return (ENOTSUP);
728219089Spjd
729248571Smm	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
730248571Smm
731219089Spjd	ret = ioctl(fd, ncmd, zc_c);
732219089Spjd	if (cflag == ZFS_CMD_COMPAT_V15 &&
733248571Smm	    nc == ZFS_IOC_POOL_IMPORT)
734248571Smm		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
735219089Spjd		    struct zfs_cmd_v15), zc_c);
736219089Spjd	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
737219089Spjd	free(zc_c);
738219089Spjd
739247540Smm	if (cflag == ZFS_CMD_COMPAT_V15) {
740247540Smm		switch (nc) {
741248571Smm		case ZFS_IOC_POOL_IMPORT:
742248571Smm		case ZFS_IOC_POOL_CONFIGS:
743248571Smm		case ZFS_IOC_POOL_STATS:
744248571Smm		case ZFS_IOC_POOL_TRYIMPORT:
745247540Smm			zfs_ioctl_compat_fix_stats(zc, nc);
746247540Smm			break;
747247540Smm		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
748247540Smm			zfs_ioctl_compat_pool_get_props(zc);
749247540Smm			break;
750247540Smm		}
751219089Spjd	}
752219089Spjd
753219089Spjd	return (ret);
754219089Spjd}
755219089Spjd#else /* _KERNEL */
756248571Smmint
757219089Spjdzfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
758219089Spjd{
759248571Smm	int error = 0;
760248571Smm
761248571Smm	/* are we creating a clone? */
762248571Smm	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
763248571Smm		*vec = ZFS_IOC_CLONE;
764248571Smm
765248571Smm	if (cflag == ZFS_CMD_COMPAT_V15) {
766219089Spjd		switch (*vec) {
767219089Spjd
768219089Spjd		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
769219089Spjd			zc->zc_cookie = POOL_SCAN_SCRUB;
770219089Spjd			break;
771219089Spjd		}
772248571Smm	}
773248571Smm
774248571Smm	return (error);
775219089Spjd}
776219089Spjd
777219089Spjdvoid
778219089Spjdzfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
779219089Spjd{
780219089Spjd	if (cflag == ZFS_CMD_COMPAT_V15) {
781219089Spjd		switch (vec) {
782248571Smm		case ZFS_IOC_POOL_CONFIGS:
783248571Smm		case ZFS_IOC_POOL_STATS:
784248571Smm		case ZFS_IOC_POOL_TRYIMPORT:
785219089Spjd			zfs_ioctl_compat_fix_stats(zc, vec);
786219089Spjd			break;
787219089Spjd		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
788219089Spjd			zfs_ioctl_compat_pool_get_props(zc);
789219089Spjd			break;
790219089Spjd		}
791219089Spjd	}
792219089Spjd}
793248571Smm
794248571Smmnvlist_t *
795248571Smmzfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
796248571Smm    const int cflag)
797248571Smm{
798248571Smm	nvlist_t *nvl, *tmpnvl, *hnvl;
799248571Smm	nvpair_t *elem;
800248571Smm	char *poolname, *snapname;
801248571Smm	int err;
802248571Smm
803268786Sdelphij	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
804268786Sdelphij	    cflag == ZFS_CMD_COMPAT_ZCMD)
805248571Smm		goto out;
806248571Smm
807248571Smm	switch (vec) {
808248571Smm	case ZFS_IOC_CREATE:
809248571Smm		nvl = fnvlist_alloc();
810248571Smm		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
811248571Smm		if (innvl != NULL) {
812248571Smm			fnvlist_add_nvlist(nvl, "props", innvl);
813248571Smm			nvlist_free(innvl);
814248571Smm		}
815248571Smm		return (nvl);
816248571Smm	break;
817248571Smm	case ZFS_IOC_CLONE:
818248571Smm		nvl = fnvlist_alloc();
819248571Smm		fnvlist_add_string(nvl, "origin", zc->zc_value);
820248571Smm		if (innvl != NULL) {
821248571Smm			fnvlist_add_nvlist(nvl, "props", innvl);
822248571Smm			nvlist_free(innvl);
823248571Smm		}
824248571Smm		return (nvl);
825248571Smm	break;
826248571Smm	case ZFS_IOC_SNAPSHOT:
827248571Smm		if (innvl == NULL)
828248571Smm			goto out;
829248571Smm		nvl = fnvlist_alloc();
830248571Smm		fnvlist_add_nvlist(nvl, "props", innvl);
831248571Smm		tmpnvl = fnvlist_alloc();
832248571Smm		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
833248571Smm		fnvlist_add_boolean(tmpnvl, snapname);
834248571Smm		kmem_free(snapname, strlen(snapname + 1));
835248571Smm		/* check if we are doing a recursive snapshot */
836248571Smm		if (zc->zc_cookie)
837248571Smm			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
838248571Smm			    tmpnvl);
839248571Smm		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
840248571Smm		fnvlist_free(tmpnvl);
841248571Smm		nvlist_free(innvl);
842248571Smm		/* strip dataset part from zc->zc_name */
843248571Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
844248571Smm		return (nvl);
845248571Smm	break;
846248571Smm	case ZFS_IOC_SPACE_SNAPS:
847248571Smm		nvl = fnvlist_alloc();
848248571Smm		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
849248571Smm		if (innvl != NULL)
850248571Smm			nvlist_free(innvl);
851248571Smm		return (nvl);
852248571Smm	break;
853248571Smm	case ZFS_IOC_DESTROY_SNAPS:
854248571Smm		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
855248571Smm			goto out;
856248571Smm		nvl = fnvlist_alloc();
857248571Smm		if (innvl != NULL) {
858248571Smm			fnvlist_add_nvlist(nvl, "snaps", innvl);
859248571Smm		} else {
860248571Smm			/*
861248571Smm			 * We are probably called by even older binaries,
862248571Smm			 * allocate and populate nvlist with recursive
863248571Smm			 * snapshots
864248571Smm			 */
865263407Sdelphij			if (zfs_component_namecheck(zc->zc_value, NULL,
866248571Smm			    NULL) == 0) {
867248571Smm				tmpnvl = fnvlist_alloc();
868248571Smm				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
869248571Smm				    zc->zc_value, tmpnvl) == 0)
870248571Smm					fnvlist_add_nvlist(nvl, "snaps",
871248571Smm					    tmpnvl);
872248571Smm				nvlist_free(tmpnvl);
873248571Smm			}
874248571Smm		}
875248571Smm		if (innvl != NULL)
876248571Smm			nvlist_free(innvl);
877248571Smm		/* strip dataset part from zc->zc_name */
878248571Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
879248571Smm		return (nvl);
880248571Smm	break;
881248571Smm	case ZFS_IOC_HOLD:
882248571Smm		nvl = fnvlist_alloc();
883248571Smm		tmpnvl = fnvlist_alloc();
884248571Smm		if (zc->zc_cleanup_fd != -1)
885248571Smm			fnvlist_add_int32(nvl, "cleanup_fd",
886248571Smm			    (int32_t)zc->zc_cleanup_fd);
887248571Smm		if (zc->zc_cookie) {
888248571Smm			hnvl = fnvlist_alloc();
889248571Smm			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
890248571Smm			    zc->zc_value, hnvl) == 0) {
891248571Smm				elem = NULL;
892248571Smm				while ((elem = nvlist_next_nvpair(hnvl,
893248571Smm				    elem)) != NULL) {
894248571Smm					nvlist_add_string(tmpnvl,
895248571Smm					    nvpair_name(elem), zc->zc_string);
896248571Smm				}
897248571Smm			}
898248571Smm			nvlist_free(hnvl);
899248571Smm		} else {
900248571Smm			snapname = kmem_asprintf("%s@%s", zc->zc_name,
901248571Smm			    zc->zc_value);
902248571Smm			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
903248571Smm			kmem_free(snapname, strlen(snapname + 1));
904248571Smm		}
905248571Smm		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
906248571Smm		nvlist_free(tmpnvl);
907248571Smm		if (innvl != NULL)
908248571Smm			nvlist_free(innvl);
909248571Smm		/* strip dataset part from zc->zc_name */
910248571Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
911248571Smm		return (nvl);
912248571Smm	break;
913248571Smm	case ZFS_IOC_RELEASE:
914248571Smm		nvl = fnvlist_alloc();
915248571Smm		tmpnvl = fnvlist_alloc();
916248571Smm		if (zc->zc_cookie) {
917248571Smm			hnvl = fnvlist_alloc();
918248571Smm			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
919248571Smm			    zc->zc_value, hnvl) == 0) {
920248571Smm				elem = NULL;
921248571Smm				while ((elem = nvlist_next_nvpair(hnvl,
922248571Smm				    elem)) != NULL) {
923248571Smm					fnvlist_add_boolean(tmpnvl,
924248571Smm					    zc->zc_string);
925248571Smm					fnvlist_add_nvlist(nvl,
926248571Smm					    nvpair_name(elem), tmpnvl);
927248571Smm				}
928248571Smm			}
929248571Smm			nvlist_free(hnvl);
930248571Smm		} else {
931248571Smm			snapname = kmem_asprintf("%s@%s", zc->zc_name,
932248571Smm			    zc->zc_value);
933248571Smm			fnvlist_add_boolean(tmpnvl, zc->zc_string);
934248571Smm			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
935248571Smm			kmem_free(snapname, strlen(snapname + 1));
936248571Smm		}
937248571Smm		nvlist_free(tmpnvl);
938248571Smm		if (innvl != NULL)
939248571Smm			nvlist_free(innvl);
940248571Smm		/* strip dataset part from zc->zc_name */
941248571Smm		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
942248571Smm		return (nvl);
943248571Smm	break;
944248571Smm	}
945248571Smmout:
946248571Smm	return (innvl);
947248571Smm}
948248571Smm
949248571Smmnvlist_t *
950248571Smmzfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
951248571Smm    const int cflag)
952248571Smm{
953248571Smm	nvlist_t *tmpnvl;
954248571Smm
955268786Sdelphij	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
956268786Sdelphij	    cflag == ZFS_CMD_COMPAT_ZCMD)
957248571Smm		return (outnvl);
958248571Smm
959248571Smm	switch (vec) {
960248571Smm	case ZFS_IOC_SPACE_SNAPS:
961248571Smm		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
962248571Smm		(void) nvlist_lookup_uint64(outnvl, "compressed",
963248571Smm		    &zc->zc_objset_type);
964248571Smm		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
965248571Smm		    &zc->zc_perm_action);
966248571Smm		nvlist_free(outnvl);
967248571Smm		/* return empty outnvl */
968248571Smm		tmpnvl = fnvlist_alloc();
969248571Smm		return (tmpnvl);
970248571Smm	break;
971248571Smm	case ZFS_IOC_CREATE:
972248571Smm	case ZFS_IOC_CLONE:
973248571Smm	case ZFS_IOC_HOLD:
974248571Smm	case ZFS_IOC_RELEASE:
975248571Smm		nvlist_free(outnvl);
976248571Smm		/* return empty outnvl */
977248571Smm		tmpnvl = fnvlist_alloc();
978248571Smm		return (tmpnvl);
979248571Smm	break;
980248571Smm	}
981248571Smm
982248571Smm	return (outnvl);
983248571Smm}
984219089Spjd#endif /* KERNEL */
985