zfs_ioctl_compat.c revision 290756
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2013 Xin Li <delphij@FreeBSD.org>. All rights reserved.
23 * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
24 * Portions Copyright 2005, 2010, Oracle and/or its affiliates.
25 * All rights reserved.
26 * Use is subject to license terms.
27 */
28
29#include <sys/types.h>
30#include <sys/param.h>
31#include <sys/cred.h>
32#include <sys/dmu.h>
33#include <sys/zio.h>
34#include <sys/nvpair.h>
35#include <sys/dsl_deleg.h>
36#include <sys/zfs_ioctl.h>
37#include "zfs_namecheck.h"
38#include "zfs_ioctl_compat.h"
39
40static int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
41SYSCTL_DECL(_vfs_zfs_version);
42SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
43    0, "ZFS_IOCTL_VERSION");
44
45/*
46 * FreeBSD zfs_cmd compatibility with older binaries
47 * appropriately remap/extend the zfs_cmd_t structure
48 */
49void
50zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
51{
52	zfs_cmd_v15_t *zc_c;
53	zfs_cmd_v28_t *zc28_c;
54	zfs_cmd_deadman_t *zcdm_c;
55	zfs_cmd_zcmd_t *zcmd_c;
56	zfs_cmd_edbp_t *edbp_c;
57
58	switch (cflag) {
59	case ZFS_CMD_COMPAT_EDBP:
60		edbp_c = (void *)addr;
61		/* zc */
62		strlcpy(zc->zc_name, edbp_c->zc_name, MAXPATHLEN);
63		strlcpy(zc->zc_value, edbp_c->zc_value, MAXPATHLEN * 2);
64		strlcpy(zc->zc_string, edbp_c->zc_string, MAXPATHLEN);
65
66#define ZCMD_COPY(field) zc->field = edbp_c->field
67		ZCMD_COPY(zc_nvlist_src);
68		ZCMD_COPY(zc_nvlist_src_size);
69		ZCMD_COPY(zc_nvlist_dst);
70		ZCMD_COPY(zc_nvlist_dst_size);
71		ZCMD_COPY(zc_nvlist_dst_filled);
72		ZCMD_COPY(zc_pad2);
73		ZCMD_COPY(zc_history);
74		ZCMD_COPY(zc_guid);
75		ZCMD_COPY(zc_nvlist_conf);
76		ZCMD_COPY(zc_nvlist_conf_size);
77		ZCMD_COPY(zc_cookie);
78		ZCMD_COPY(zc_objset_type);
79		ZCMD_COPY(zc_perm_action);
80		ZCMD_COPY(zc_history_len);
81		ZCMD_COPY(zc_history_offset);
82		ZCMD_COPY(zc_obj);
83		ZCMD_COPY(zc_iflags);
84		ZCMD_COPY(zc_share);
85		ZCMD_COPY(zc_jailid);
86		ZCMD_COPY(zc_objset_stats);
87		zc->zc_begin_record.drr_u.drr_begin = edbp_c->zc_begin_record;
88		ZCMD_COPY(zc_inject_record);
89		ZCMD_COPY(zc_defer_destroy);
90		ZCMD_COPY(zc_flags);
91		ZCMD_COPY(zc_action_handle);
92		ZCMD_COPY(zc_cleanup_fd);
93		ZCMD_COPY(zc_simple);
94		zc->zc_resumable = B_FALSE;
95		ZCMD_COPY(zc_sendobj);
96		ZCMD_COPY(zc_fromobj);
97		ZCMD_COPY(zc_createtxg);
98		ZCMD_COPY(zc_stat);
99#undef ZCMD_COPY
100		break;
101
102	case ZFS_CMD_COMPAT_ZCMD:
103		zcmd_c = (void *)addr;
104		/* zc */
105		strlcpy(zc->zc_name, zcmd_c->zc_name, MAXPATHLEN);
106		strlcpy(zc->zc_value, zcmd_c->zc_value, MAXPATHLEN * 2);
107		strlcpy(zc->zc_string, zcmd_c->zc_string, MAXPATHLEN);
108
109#define ZCMD_COPY(field) zc->field = zcmd_c->field
110		ZCMD_COPY(zc_nvlist_src);
111		ZCMD_COPY(zc_nvlist_src_size);
112		ZCMD_COPY(zc_nvlist_dst);
113		ZCMD_COPY(zc_nvlist_dst_size);
114		ZCMD_COPY(zc_nvlist_dst_filled);
115		ZCMD_COPY(zc_pad2);
116		ZCMD_COPY(zc_history);
117		ZCMD_COPY(zc_guid);
118		ZCMD_COPY(zc_nvlist_conf);
119		ZCMD_COPY(zc_nvlist_conf_size);
120		ZCMD_COPY(zc_cookie);
121		ZCMD_COPY(zc_objset_type);
122		ZCMD_COPY(zc_perm_action);
123		ZCMD_COPY(zc_history_len);
124		ZCMD_COPY(zc_history_offset);
125		ZCMD_COPY(zc_obj);
126		ZCMD_COPY(zc_iflags);
127		ZCMD_COPY(zc_share);
128		ZCMD_COPY(zc_jailid);
129		ZCMD_COPY(zc_objset_stats);
130		zc->zc_begin_record.drr_u.drr_begin = zcmd_c->zc_begin_record;
131		ZCMD_COPY(zc_inject_record);
132
133		/* boolean_t -> uint32_t */
134		zc->zc_defer_destroy = (uint32_t)(zcmd_c->zc_defer_destroy);
135		zc->zc_flags = 0;
136
137		ZCMD_COPY(zc_action_handle);
138		ZCMD_COPY(zc_cleanup_fd);
139		ZCMD_COPY(zc_simple);
140		zc->zc_resumable = B_FALSE;
141		ZCMD_COPY(zc_sendobj);
142		ZCMD_COPY(zc_fromobj);
143		ZCMD_COPY(zc_createtxg);
144		ZCMD_COPY(zc_stat);
145#undef ZCMD_COPY
146
147		break;
148
149	case ZFS_CMD_COMPAT_DEADMAN:
150		zcdm_c = (void *)addr;
151		/* zc */
152		strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN);
153		strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2);
154		strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN);
155		zc->zc_guid = zcdm_c->zc_guid;
156		zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf;
157		zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size;
158		zc->zc_nvlist_src = zcdm_c->zc_nvlist_src;
159		zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size;
160		zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst;
161		zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size;
162		zc->zc_cookie = zcdm_c->zc_cookie;
163		zc->zc_objset_type = zcdm_c->zc_objset_type;
164		zc->zc_perm_action = zcdm_c->zc_perm_action;
165		zc->zc_history = zcdm_c->zc_history;
166		zc->zc_history_len = zcdm_c->zc_history_len;
167		zc->zc_history_offset = zcdm_c->zc_history_offset;
168		zc->zc_obj = zcdm_c->zc_obj;
169		zc->zc_iflags = zcdm_c->zc_iflags;
170		zc->zc_share = zcdm_c->zc_share;
171		zc->zc_jailid = zcdm_c->zc_jailid;
172		zc->zc_objset_stats = zcdm_c->zc_objset_stats;
173		zc->zc_begin_record.drr_u.drr_begin = zcdm_c->zc_begin_record;
174		zc->zc_defer_destroy = zcdm_c->zc_defer_destroy;
175		(void)zcdm_c->zc_temphold;
176		zc->zc_action_handle = zcdm_c->zc_action_handle;
177		zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd;
178		zc->zc_simple = zcdm_c->zc_simple;
179		zc->zc_resumable = B_FALSE;
180		zc->zc_sendobj = zcdm_c->zc_sendobj;
181		zc->zc_fromobj = zcdm_c->zc_fromobj;
182		zc->zc_createtxg = zcdm_c->zc_createtxg;
183		zc->zc_stat = zcdm_c->zc_stat;
184
185		/* zc_inject_record doesn't change in libzfs_core */
186		zcdm_c->zc_inject_record = zc->zc_inject_record;
187
188		/* we always assume zc_nvlist_dst_filled is true */
189		zc->zc_nvlist_dst_filled = B_TRUE;
190		break;
191
192	case ZFS_CMD_COMPAT_V28:
193		zc28_c = (void *)addr;
194
195		/* zc */
196		strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
197		strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
198		strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
199		zc->zc_guid = zc28_c->zc_guid;
200		zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
201		zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
202		zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
203		zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
204		zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
205		zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
206		zc->zc_cookie = zc28_c->zc_cookie;
207		zc->zc_objset_type = zc28_c->zc_objset_type;
208		zc->zc_perm_action = zc28_c->zc_perm_action;
209		zc->zc_history = zc28_c->zc_history;
210		zc->zc_history_len = zc28_c->zc_history_len;
211		zc->zc_history_offset = zc28_c->zc_history_offset;
212		zc->zc_obj = zc28_c->zc_obj;
213		zc->zc_iflags = zc28_c->zc_iflags;
214		zc->zc_share = zc28_c->zc_share;
215		zc->zc_jailid = zc28_c->zc_jailid;
216		zc->zc_objset_stats = zc28_c->zc_objset_stats;
217		zc->zc_begin_record.drr_u.drr_begin = zc28_c->zc_begin_record;
218		zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
219		(void)zc28_c->zc_temphold;
220		zc->zc_action_handle = zc28_c->zc_action_handle;
221		zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
222		zc->zc_simple = zc28_c->zc_simple;
223		zc->zc_resumable = B_FALSE;
224		zc->zc_sendobj = zc28_c->zc_sendobj;
225		zc->zc_fromobj = zc28_c->zc_fromobj;
226		zc->zc_createtxg = zc28_c->zc_createtxg;
227		zc->zc_stat = zc28_c->zc_stat;
228
229		/* zc->zc_inject_record */
230		zc->zc_inject_record.zi_objset =
231		    zc28_c->zc_inject_record.zi_objset;
232		zc->zc_inject_record.zi_object =
233		    zc28_c->zc_inject_record.zi_object;
234		zc->zc_inject_record.zi_start =
235		    zc28_c->zc_inject_record.zi_start;
236		zc->zc_inject_record.zi_end =
237		    zc28_c->zc_inject_record.zi_end;
238		zc->zc_inject_record.zi_guid =
239		    zc28_c->zc_inject_record.zi_guid;
240		zc->zc_inject_record.zi_level =
241		    zc28_c->zc_inject_record.zi_level;
242		zc->zc_inject_record.zi_error =
243		    zc28_c->zc_inject_record.zi_error;
244		zc->zc_inject_record.zi_type =
245		    zc28_c->zc_inject_record.zi_type;
246		zc->zc_inject_record.zi_freq =
247		    zc28_c->zc_inject_record.zi_freq;
248		zc->zc_inject_record.zi_failfast =
249		    zc28_c->zc_inject_record.zi_failfast;
250		strlcpy(zc->zc_inject_record.zi_func,
251		    zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
252		zc->zc_inject_record.zi_iotype =
253		    zc28_c->zc_inject_record.zi_iotype;
254		zc->zc_inject_record.zi_duration =
255		    zc28_c->zc_inject_record.zi_duration;
256		zc->zc_inject_record.zi_timer =
257		    zc28_c->zc_inject_record.zi_timer;
258		zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
259		zc->zc_inject_record.zi_pad = 0;
260		break;
261
262	case ZFS_CMD_COMPAT_V15:
263		zc_c = (void *)addr;
264
265		/* zc */
266		strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
267		strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
268		strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
269		zc->zc_guid = zc_c->zc_guid;
270		zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
271		zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
272		zc->zc_nvlist_src = zc_c->zc_nvlist_src;
273		zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
274		zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
275		zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
276		zc->zc_cookie = zc_c->zc_cookie;
277		zc->zc_objset_type = zc_c->zc_objset_type;
278		zc->zc_perm_action = zc_c->zc_perm_action;
279		zc->zc_history = zc_c->zc_history;
280		zc->zc_history_len = zc_c->zc_history_len;
281		zc->zc_history_offset = zc_c->zc_history_offset;
282		zc->zc_obj = zc_c->zc_obj;
283		zc->zc_share = zc_c->zc_share;
284		zc->zc_jailid = zc_c->zc_jailid;
285		zc->zc_objset_stats = zc_c->zc_objset_stats;
286		zc->zc_begin_record.drr_u.drr_begin = zc_c->zc_begin_record;
287
288		/* zc->zc_inject_record */
289		zc->zc_inject_record.zi_objset =
290		    zc_c->zc_inject_record.zi_objset;
291		zc->zc_inject_record.zi_object =
292		    zc_c->zc_inject_record.zi_object;
293		zc->zc_inject_record.zi_start =
294		    zc_c->zc_inject_record.zi_start;
295		zc->zc_inject_record.zi_end =
296		    zc_c->zc_inject_record.zi_end;
297		zc->zc_inject_record.zi_guid =
298		    zc_c->zc_inject_record.zi_guid;
299		zc->zc_inject_record.zi_level =
300		    zc_c->zc_inject_record.zi_level;
301		zc->zc_inject_record.zi_error =
302		    zc_c->zc_inject_record.zi_error;
303		zc->zc_inject_record.zi_type =
304		    zc_c->zc_inject_record.zi_type;
305		zc->zc_inject_record.zi_freq =
306		    zc_c->zc_inject_record.zi_freq;
307		zc->zc_inject_record.zi_failfast =
308		    zc_c->zc_inject_record.zi_failfast;
309		break;
310	}
311}
312
313void
314zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request,
315    const int cflag)
316{
317	zfs_cmd_v15_t *zc_c;
318	zfs_cmd_v28_t *zc28_c;
319	zfs_cmd_deadman_t *zcdm_c;
320	zfs_cmd_zcmd_t *zcmd_c;
321	zfs_cmd_edbp_t *edbp_c;
322
323	switch (cflag) {
324	case ZFS_CMD_COMPAT_EDBP:
325		edbp_c = (void *)addr;
326		strlcpy(edbp_c->zc_name, zc->zc_name, MAXPATHLEN);
327		strlcpy(edbp_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
328		strlcpy(edbp_c->zc_string, zc->zc_string, MAXPATHLEN);
329
330#define ZCMD_COPY(field) edbp_c->field = zc->field
331		ZCMD_COPY(zc_nvlist_src);
332		ZCMD_COPY(zc_nvlist_src_size);
333		ZCMD_COPY(zc_nvlist_dst);
334		ZCMD_COPY(zc_nvlist_dst_size);
335		ZCMD_COPY(zc_nvlist_dst_filled);
336		ZCMD_COPY(zc_pad2);
337		ZCMD_COPY(zc_history);
338		ZCMD_COPY(zc_guid);
339		ZCMD_COPY(zc_nvlist_conf);
340		ZCMD_COPY(zc_nvlist_conf_size);
341		ZCMD_COPY(zc_cookie);
342		ZCMD_COPY(zc_objset_type);
343		ZCMD_COPY(zc_perm_action);
344		ZCMD_COPY(zc_history_len);
345		ZCMD_COPY(zc_history_offset);
346		ZCMD_COPY(zc_obj);
347		ZCMD_COPY(zc_iflags);
348		ZCMD_COPY(zc_share);
349		ZCMD_COPY(zc_jailid);
350		ZCMD_COPY(zc_objset_stats);
351		edbp_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
352		ZCMD_COPY(zc_inject_record);
353		ZCMD_COPY(zc_defer_destroy);
354		ZCMD_COPY(zc_flags);
355		ZCMD_COPY(zc_action_handle);
356		ZCMD_COPY(zc_cleanup_fd);
357		ZCMD_COPY(zc_simple);
358		ZCMD_COPY(zc_sendobj);
359		ZCMD_COPY(zc_fromobj);
360		ZCMD_COPY(zc_createtxg);
361		ZCMD_COPY(zc_stat);
362#undef ZCMD_COPY
363		break;
364
365	case ZFS_CMD_COMPAT_ZCMD:
366		zcmd_c = (void *)addr;
367		/* zc */
368		strlcpy(zcmd_c->zc_name, zc->zc_name, MAXPATHLEN);
369		strlcpy(zcmd_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
370		strlcpy(zcmd_c->zc_string, zc->zc_string, MAXPATHLEN);
371
372#define ZCMD_COPY(field) zcmd_c->field = zc->field
373		ZCMD_COPY(zc_nvlist_src);
374		ZCMD_COPY(zc_nvlist_src_size);
375		ZCMD_COPY(zc_nvlist_dst);
376		ZCMD_COPY(zc_nvlist_dst_size);
377		ZCMD_COPY(zc_nvlist_dst_filled);
378		ZCMD_COPY(zc_pad2);
379		ZCMD_COPY(zc_history);
380		ZCMD_COPY(zc_guid);
381		ZCMD_COPY(zc_nvlist_conf);
382		ZCMD_COPY(zc_nvlist_conf_size);
383		ZCMD_COPY(zc_cookie);
384		ZCMD_COPY(zc_objset_type);
385		ZCMD_COPY(zc_perm_action);
386		ZCMD_COPY(zc_history_len);
387		ZCMD_COPY(zc_history_offset);
388		ZCMD_COPY(zc_obj);
389		ZCMD_COPY(zc_iflags);
390		ZCMD_COPY(zc_share);
391		ZCMD_COPY(zc_jailid);
392		ZCMD_COPY(zc_objset_stats);
393		zcmd_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
394		ZCMD_COPY(zc_inject_record);
395
396		/* boolean_t -> uint32_t */
397		zcmd_c->zc_defer_destroy = (uint32_t)(zc->zc_defer_destroy);
398		zcmd_c->zc_temphold = 0;
399
400		ZCMD_COPY(zc_action_handle);
401		ZCMD_COPY(zc_cleanup_fd);
402		ZCMD_COPY(zc_simple);
403		ZCMD_COPY(zc_sendobj);
404		ZCMD_COPY(zc_fromobj);
405		ZCMD_COPY(zc_createtxg);
406		ZCMD_COPY(zc_stat);
407#undef ZCMD_COPY
408
409		break;
410
411	case ZFS_CMD_COMPAT_DEADMAN:
412		zcdm_c = (void *)addr;
413
414		strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN);
415		strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
416		strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN);
417		zcdm_c->zc_guid = zc->zc_guid;
418		zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf;
419		zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
420		zcdm_c->zc_nvlist_src = zc->zc_nvlist_src;
421		zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
422		zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst;
423		zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
424		zcdm_c->zc_cookie = zc->zc_cookie;
425		zcdm_c->zc_objset_type = zc->zc_objset_type;
426		zcdm_c->zc_perm_action = zc->zc_perm_action;
427		zcdm_c->zc_history = zc->zc_history;
428		zcdm_c->zc_history_len = zc->zc_history_len;
429		zcdm_c->zc_history_offset = zc->zc_history_offset;
430		zcdm_c->zc_obj = zc->zc_obj;
431		zcdm_c->zc_iflags = zc->zc_iflags;
432		zcdm_c->zc_share = zc->zc_share;
433		zcdm_c->zc_jailid = zc->zc_jailid;
434		zcdm_c->zc_objset_stats = zc->zc_objset_stats;
435		zcdm_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
436		zcdm_c->zc_defer_destroy = zc->zc_defer_destroy;
437		zcdm_c->zc_temphold = 0;
438		zcdm_c->zc_action_handle = zc->zc_action_handle;
439		zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd;
440		zcdm_c->zc_simple = zc->zc_simple;
441		zcdm_c->zc_sendobj = zc->zc_sendobj;
442		zcdm_c->zc_fromobj = zc->zc_fromobj;
443		zcdm_c->zc_createtxg = zc->zc_createtxg;
444		zcdm_c->zc_stat = zc->zc_stat;
445
446		/* zc_inject_record doesn't change in libzfs_core */
447		zc->zc_inject_record = zcdm_c->zc_inject_record;
448#ifndef _KERNEL
449		if (request == ZFS_IOC_RECV)
450			strlcpy(zcdm_c->zc_top_ds,
451			    zc->zc_value + strlen(zc->zc_value) + 1,
452			    (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1);
453#endif
454		break;
455
456	case ZFS_CMD_COMPAT_V28:
457		zc28_c = (void *)addr;
458
459		strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
460		strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
461		strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
462		zc28_c->zc_guid = zc->zc_guid;
463		zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
464		zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
465		zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
466		zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
467		zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
468		zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
469		zc28_c->zc_cookie = zc->zc_cookie;
470		zc28_c->zc_objset_type = zc->zc_objset_type;
471		zc28_c->zc_perm_action = zc->zc_perm_action;
472		zc28_c->zc_history = zc->zc_history;
473		zc28_c->zc_history_len = zc->zc_history_len;
474		zc28_c->zc_history_offset = zc->zc_history_offset;
475		zc28_c->zc_obj = zc->zc_obj;
476		zc28_c->zc_iflags = zc->zc_iflags;
477		zc28_c->zc_share = zc->zc_share;
478		zc28_c->zc_jailid = zc->zc_jailid;
479		zc28_c->zc_objset_stats = zc->zc_objset_stats;
480		zc28_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
481		zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
482		zc28_c->zc_temphold = 0;
483		zc28_c->zc_action_handle = zc->zc_action_handle;
484		zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
485		zc28_c->zc_simple = zc->zc_simple;
486		zc28_c->zc_sendobj = zc->zc_sendobj;
487		zc28_c->zc_fromobj = zc->zc_fromobj;
488		zc28_c->zc_createtxg = zc->zc_createtxg;
489		zc28_c->zc_stat = zc->zc_stat;
490#ifndef _KERNEL
491		if (request == ZFS_IOC_RECV)
492			strlcpy(zc28_c->zc_top_ds,
493			    zc->zc_value + strlen(zc->zc_value) + 1,
494			    MAXPATHLEN * 2 - strlen(zc->zc_value) - 1);
495#endif
496		/* zc_inject_record */
497		zc28_c->zc_inject_record.zi_objset =
498		    zc->zc_inject_record.zi_objset;
499		zc28_c->zc_inject_record.zi_object =
500		    zc->zc_inject_record.zi_object;
501		zc28_c->zc_inject_record.zi_start =
502		    zc->zc_inject_record.zi_start;
503		zc28_c->zc_inject_record.zi_end =
504		    zc->zc_inject_record.zi_end;
505		zc28_c->zc_inject_record.zi_guid =
506		    zc->zc_inject_record.zi_guid;
507		zc28_c->zc_inject_record.zi_level =
508		    zc->zc_inject_record.zi_level;
509		zc28_c->zc_inject_record.zi_error =
510		    zc->zc_inject_record.zi_error;
511		zc28_c->zc_inject_record.zi_type =
512		    zc->zc_inject_record.zi_type;
513		zc28_c->zc_inject_record.zi_freq =
514		    zc->zc_inject_record.zi_freq;
515		zc28_c->zc_inject_record.zi_failfast =
516		    zc->zc_inject_record.zi_failfast;
517		strlcpy(zc28_c->zc_inject_record.zi_func,
518		    zc->zc_inject_record.zi_func, MAXNAMELEN);
519		zc28_c->zc_inject_record.zi_iotype =
520		    zc->zc_inject_record.zi_iotype;
521		zc28_c->zc_inject_record.zi_duration =
522		    zc->zc_inject_record.zi_duration;
523		zc28_c->zc_inject_record.zi_timer =
524		    zc->zc_inject_record.zi_timer;
525		break;
526
527	case ZFS_CMD_COMPAT_V15:
528		zc_c = (void *)addr;
529
530		/* zc */
531		strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
532		strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
533		strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
534		zc_c->zc_guid = zc->zc_guid;
535		zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
536		zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
537		zc_c->zc_nvlist_src = zc->zc_nvlist_src;
538		zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
539		zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
540		zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
541		zc_c->zc_cookie = zc->zc_cookie;
542		zc_c->zc_objset_type = zc->zc_objset_type;
543		zc_c->zc_perm_action = zc->zc_perm_action;
544		zc_c->zc_history = zc->zc_history;
545		zc_c->zc_history_len = zc->zc_history_len;
546		zc_c->zc_history_offset = zc->zc_history_offset;
547		zc_c->zc_obj = zc->zc_obj;
548		zc_c->zc_share = zc->zc_share;
549		zc_c->zc_jailid = zc->zc_jailid;
550		zc_c->zc_objset_stats = zc->zc_objset_stats;
551		zc_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
552
553		/* zc_inject_record */
554		zc_c->zc_inject_record.zi_objset =
555		    zc->zc_inject_record.zi_objset;
556		zc_c->zc_inject_record.zi_object =
557		    zc->zc_inject_record.zi_object;
558		zc_c->zc_inject_record.zi_start =
559		    zc->zc_inject_record.zi_start;
560		zc_c->zc_inject_record.zi_end =
561		    zc->zc_inject_record.zi_end;
562		zc_c->zc_inject_record.zi_guid =
563		    zc->zc_inject_record.zi_guid;
564		zc_c->zc_inject_record.zi_level =
565		    zc->zc_inject_record.zi_level;
566		zc_c->zc_inject_record.zi_error =
567		    zc->zc_inject_record.zi_error;
568		zc_c->zc_inject_record.zi_type =
569		    zc->zc_inject_record.zi_type;
570		zc_c->zc_inject_record.zi_freq =
571		    zc->zc_inject_record.zi_freq;
572		zc_c->zc_inject_record.zi_failfast =
573		    zc->zc_inject_record.zi_failfast;
574
575		break;
576	}
577}
578
579static int
580zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
581    nvlist_t **nvp)
582{
583	char *packed;
584	int error;
585	nvlist_t *list = NULL;
586
587	/*
588	 * Read in and unpack the user-supplied nvlist.
589	 */
590	if (size == 0)
591		return (EINVAL);
592
593#ifdef _KERNEL
594	packed = kmem_alloc(size, KM_SLEEP);
595	if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
596	    iflag)) != 0) {
597		kmem_free(packed, size);
598		return (error);
599	}
600#else
601	packed = (void *)(uintptr_t)nvl;
602#endif
603
604	error = nvlist_unpack(packed, size, &list, 0);
605
606#ifdef _KERNEL
607	kmem_free(packed, size);
608#endif
609
610	if (error != 0)
611		return (error);
612
613	*nvp = list;
614	return (0);
615}
616
617static int
618zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
619{
620	char *packed = NULL;
621	int error = 0;
622	size_t size;
623
624	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
625
626#ifdef _KERNEL
627	packed = kmem_alloc(size, KM_SLEEP);
628	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
629	    KM_SLEEP) == 0);
630
631	if (ddi_copyout(packed,
632	    (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
633		error = EFAULT;
634	kmem_free(packed, size);
635#else
636	packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
637	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
638	    0) == 0);
639#endif
640
641	zc->zc_nvlist_dst_size = size;
642	return (error);
643}
644
645static void
646zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
647{
648	nvlist_t **child;
649	nvlist_t *nvroot = NULL;
650	vdev_stat_t *vs;
651	uint_t c, children, nelem;
652
653	if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
654	    &child, &children) == 0) {
655		for (c = 0; c < children; c++) {
656			zfs_ioctl_compat_fix_stats_nvlist(child[c]);
657		}
658	}
659
660	if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
661	    &nvroot) == 0)
662		zfs_ioctl_compat_fix_stats_nvlist(nvroot);
663#ifdef _KERNEL
664	if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
665#else
666	if ((nvlist_lookup_uint64_array(nvl, "stats",
667#endif
668
669	    (uint64_t **)&vs, &nelem) == 0)) {
670		nvlist_add_uint64_array(nvl,
671#ifdef _KERNEL
672		    "stats",
673#else
674		    ZPOOL_CONFIG_VDEV_STATS,
675#endif
676		    (uint64_t *)vs, nelem);
677#ifdef _KERNEL
678		nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
679#else
680		nvlist_remove(nvl, "stats",
681#endif
682		    DATA_TYPE_UINT64_ARRAY);
683	}
684}
685
686static int
687zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
688{
689	nvlist_t *nv, *nvp = NULL;
690	nvpair_t *elem;
691	int error;
692
693	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
694	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
695		return (error);
696
697	if (nc == 5) { /* ZFS_IOC_POOL_STATS */
698		elem = NULL;
699		while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
700			if (nvpair_value_nvlist(elem, &nvp) == 0)
701				zfs_ioctl_compat_fix_stats_nvlist(nvp);
702		}
703		elem = NULL;
704	} else
705		zfs_ioctl_compat_fix_stats_nvlist(nv);
706
707	error = zfs_ioctl_compat_put_nvlist(zc, nv);
708
709	nvlist_free(nv);
710
711	return (error);
712}
713
714static int
715zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
716{
717	nvlist_t *nv, *nva = NULL;
718	int error;
719
720	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
721	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
722		return (error);
723
724#ifdef _KERNEL
725	if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
726		nvlist_add_nvlist(nv, "used", nva);
727		nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
728	}
729
730	if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
731		nvlist_add_nvlist(nv, "available", nva);
732		nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
733	}
734#else
735	if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
736		nvlist_add_nvlist(nv, "allocated", nva);
737		nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
738	}
739
740	if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
741		nvlist_add_nvlist(nv, "free", nva);
742		nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
743	}
744#endif
745
746	error = zfs_ioctl_compat_put_nvlist(zc, nv);
747
748	nvlist_free(nv);
749
750	return (error);
751}
752
753#ifndef _KERNEL
754int
755zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
756{
757	int nc, ret;
758	void *zc_c;
759	unsigned long ncmd;
760	zfs_iocparm_t zp;
761
762	switch (cflag) {
763	case ZFS_CMD_COMPAT_NONE:
764		ncmd = _IOWR('Z', request, struct zfs_iocparm);
765		zp.zfs_cmd = (uint64_t)zc;
766		zp.zfs_cmd_size = sizeof(zfs_cmd_t);
767		zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT;
768		return (ioctl(fd, ncmd, &zp));
769	case ZFS_CMD_COMPAT_EDBP:
770		ncmd = _IOWR('Z', request, struct zfs_iocparm);
771		zp.zfs_cmd = (uint64_t)zc;
772		zp.zfs_cmd_size = sizeof(zfs_cmd_edbp_t);
773		zp.zfs_ioctl_version = ZFS_IOCVER_EDBP;
774		return (ioctl(fd, ncmd, &zp));
775	case ZFS_CMD_COMPAT_ZCMD:
776		ncmd = _IOWR('Z', request, struct zfs_iocparm);
777		zp.zfs_cmd = (uint64_t)zc;
778		zp.zfs_cmd_size = sizeof(zfs_cmd_zcmd_t);
779		zp.zfs_ioctl_version = ZFS_IOCVER_ZCMD;
780		return (ioctl(fd, ncmd, &zp));
781	case ZFS_CMD_COMPAT_LZC:
782		ncmd = _IOWR('Z', request, struct zfs_cmd);
783		return (ioctl(fd, ncmd, zc));
784	case ZFS_CMD_COMPAT_DEADMAN:
785		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
786		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
787		break;
788	case ZFS_CMD_COMPAT_V28:
789		zc_c = malloc(sizeof(zfs_cmd_v28_t));
790		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
791		break;
792	case ZFS_CMD_COMPAT_V15:
793		nc = zfs_ioctl_v28_to_v15[request];
794		zc_c = malloc(sizeof(zfs_cmd_v15_t));
795		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
796		break;
797	default:
798		return (EINVAL);
799	}
800
801	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
802		return (ENOTSUP);
803
804	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
805
806	ret = ioctl(fd, ncmd, zc_c);
807	if (cflag == ZFS_CMD_COMPAT_V15 &&
808	    nc == ZFS_IOC_POOL_IMPORT)
809		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
810		    struct zfs_cmd_v15), zc_c);
811	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
812	free(zc_c);
813
814	if (cflag == ZFS_CMD_COMPAT_V15) {
815		switch (nc) {
816		case ZFS_IOC_POOL_IMPORT:
817		case ZFS_IOC_POOL_CONFIGS:
818		case ZFS_IOC_POOL_STATS:
819		case ZFS_IOC_POOL_TRYIMPORT:
820			zfs_ioctl_compat_fix_stats(zc, nc);
821			break;
822		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
823			zfs_ioctl_compat_pool_get_props(zc);
824			break;
825		}
826	}
827
828	return (ret);
829}
830#else /* _KERNEL */
831int
832zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
833{
834	int error = 0;
835
836	/* are we creating a clone? */
837	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
838		*vec = ZFS_IOC_CLONE;
839
840	if (cflag == ZFS_CMD_COMPAT_V15) {
841		switch (*vec) {
842
843		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
844			zc->zc_cookie = POOL_SCAN_SCRUB;
845			break;
846		}
847	}
848
849	return (error);
850}
851
852void
853zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
854{
855	if (cflag == ZFS_CMD_COMPAT_V15) {
856		switch (vec) {
857		case ZFS_IOC_POOL_CONFIGS:
858		case ZFS_IOC_POOL_STATS:
859		case ZFS_IOC_POOL_TRYIMPORT:
860			zfs_ioctl_compat_fix_stats(zc, vec);
861			break;
862		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
863			zfs_ioctl_compat_pool_get_props(zc);
864			break;
865		}
866	}
867}
868
869nvlist_t *
870zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
871    const int cflag)
872{
873	nvlist_t *nvl, *tmpnvl, *hnvl;
874	nvpair_t *elem;
875	char *poolname, *snapname;
876	int err;
877
878	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
879	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP)
880		goto out;
881
882	switch (vec) {
883	case ZFS_IOC_CREATE:
884		nvl = fnvlist_alloc();
885		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
886		if (innvl != NULL) {
887			fnvlist_add_nvlist(nvl, "props", innvl);
888			nvlist_free(innvl);
889		}
890		return (nvl);
891	break;
892	case ZFS_IOC_CLONE:
893		nvl = fnvlist_alloc();
894		fnvlist_add_string(nvl, "origin", zc->zc_value);
895		if (innvl != NULL) {
896			fnvlist_add_nvlist(nvl, "props", innvl);
897			nvlist_free(innvl);
898		}
899		return (nvl);
900	break;
901	case ZFS_IOC_SNAPSHOT:
902		if (innvl == NULL)
903			goto out;
904		nvl = fnvlist_alloc();
905		fnvlist_add_nvlist(nvl, "props", innvl);
906		tmpnvl = fnvlist_alloc();
907		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
908		fnvlist_add_boolean(tmpnvl, snapname);
909		kmem_free(snapname, strlen(snapname + 1));
910		/* check if we are doing a recursive snapshot */
911		if (zc->zc_cookie)
912			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
913			    tmpnvl);
914		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
915		fnvlist_free(tmpnvl);
916		nvlist_free(innvl);
917		/* strip dataset part from zc->zc_name */
918		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
919		return (nvl);
920	break;
921	case ZFS_IOC_SPACE_SNAPS:
922		nvl = fnvlist_alloc();
923		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
924		if (innvl != NULL)
925			nvlist_free(innvl);
926		return (nvl);
927	break;
928	case ZFS_IOC_DESTROY_SNAPS:
929		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
930			goto out;
931		nvl = fnvlist_alloc();
932		if (innvl != NULL) {
933			fnvlist_add_nvlist(nvl, "snaps", innvl);
934		} else {
935			/*
936			 * We are probably called by even older binaries,
937			 * allocate and populate nvlist with recursive
938			 * snapshots
939			 */
940			if (zfs_component_namecheck(zc->zc_value, NULL,
941			    NULL) == 0) {
942				tmpnvl = fnvlist_alloc();
943				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
944				    zc->zc_value, tmpnvl) == 0)
945					fnvlist_add_nvlist(nvl, "snaps",
946					    tmpnvl);
947				nvlist_free(tmpnvl);
948			}
949		}
950		if (innvl != NULL)
951			nvlist_free(innvl);
952		/* strip dataset part from zc->zc_name */
953		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
954		return (nvl);
955	break;
956	case ZFS_IOC_HOLD:
957		nvl = fnvlist_alloc();
958		tmpnvl = fnvlist_alloc();
959		if (zc->zc_cleanup_fd != -1)
960			fnvlist_add_int32(nvl, "cleanup_fd",
961			    (int32_t)zc->zc_cleanup_fd);
962		if (zc->zc_cookie) {
963			hnvl = fnvlist_alloc();
964			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
965			    zc->zc_value, hnvl) == 0) {
966				elem = NULL;
967				while ((elem = nvlist_next_nvpair(hnvl,
968				    elem)) != NULL) {
969					nvlist_add_string(tmpnvl,
970					    nvpair_name(elem), zc->zc_string);
971				}
972			}
973			nvlist_free(hnvl);
974		} else {
975			snapname = kmem_asprintf("%s@%s", zc->zc_name,
976			    zc->zc_value);
977			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
978			kmem_free(snapname, strlen(snapname + 1));
979		}
980		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
981		nvlist_free(tmpnvl);
982		if (innvl != NULL)
983			nvlist_free(innvl);
984		/* strip dataset part from zc->zc_name */
985		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
986		return (nvl);
987	break;
988	case ZFS_IOC_RELEASE:
989		nvl = fnvlist_alloc();
990		tmpnvl = fnvlist_alloc();
991		if (zc->zc_cookie) {
992			hnvl = fnvlist_alloc();
993			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
994			    zc->zc_value, hnvl) == 0) {
995				elem = NULL;
996				while ((elem = nvlist_next_nvpair(hnvl,
997				    elem)) != NULL) {
998					fnvlist_add_boolean(tmpnvl,
999					    zc->zc_string);
1000					fnvlist_add_nvlist(nvl,
1001					    nvpair_name(elem), tmpnvl);
1002				}
1003			}
1004			nvlist_free(hnvl);
1005		} else {
1006			snapname = kmem_asprintf("%s@%s", zc->zc_name,
1007			    zc->zc_value);
1008			fnvlist_add_boolean(tmpnvl, zc->zc_string);
1009			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
1010			kmem_free(snapname, strlen(snapname + 1));
1011		}
1012		nvlist_free(tmpnvl);
1013		if (innvl != NULL)
1014			nvlist_free(innvl);
1015		/* strip dataset part from zc->zc_name */
1016		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1017		return (nvl);
1018	break;
1019	}
1020out:
1021	return (innvl);
1022}
1023
1024nvlist_t *
1025zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
1026    const int cflag)
1027{
1028	nvlist_t *tmpnvl;
1029
1030	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
1031	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP)
1032		return (outnvl);
1033
1034	switch (vec) {
1035	case ZFS_IOC_SPACE_SNAPS:
1036		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
1037		(void) nvlist_lookup_uint64(outnvl, "compressed",
1038		    &zc->zc_objset_type);
1039		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
1040		    &zc->zc_perm_action);
1041		nvlist_free(outnvl);
1042		/* return empty outnvl */
1043		tmpnvl = fnvlist_alloc();
1044		return (tmpnvl);
1045	break;
1046	case ZFS_IOC_CREATE:
1047	case ZFS_IOC_CLONE:
1048	case ZFS_IOC_HOLD:
1049	case ZFS_IOC_RELEASE:
1050		nvlist_free(outnvl);
1051		/* return empty outnvl */
1052		tmpnvl = fnvlist_alloc();
1053		return (tmpnvl);
1054	break;
1055	}
1056
1057	return (outnvl);
1058}
1059#endif /* KERNEL */
1060