zfs_ioctl_compat.c revision 297108
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	zfs_cmd_resume_t *resume_c;
58
59	switch (cflag) {
60	case ZFS_CMD_COMPAT_RESUME:
61		resume_c = (void *)addr;
62		/* zc */
63		strlcpy(zc->zc_name, resume_c->zc_name, MAXPATHLEN);
64		strlcpy(zc->zc_value, resume_c->zc_value, MAXPATHLEN * 2);
65		strlcpy(zc->zc_string, resume_c->zc_string, MAXPATHLEN);
66
67#define FIELD_COPY(field) zc->field = resume_c->field
68		FIELD_COPY(zc_nvlist_src);
69		FIELD_COPY(zc_nvlist_src_size);
70		FIELD_COPY(zc_nvlist_dst);
71		FIELD_COPY(zc_nvlist_dst_size);
72		FIELD_COPY(zc_nvlist_dst_filled);
73		FIELD_COPY(zc_pad2);
74		FIELD_COPY(zc_history);
75		FIELD_COPY(zc_guid);
76		FIELD_COPY(zc_nvlist_conf);
77		FIELD_COPY(zc_nvlist_conf_size);
78		FIELD_COPY(zc_cookie);
79		FIELD_COPY(zc_objset_type);
80		FIELD_COPY(zc_perm_action);
81		FIELD_COPY(zc_history_len);
82		FIELD_COPY(zc_history_offset);
83		FIELD_COPY(zc_obj);
84		FIELD_COPY(zc_iflags);
85		FIELD_COPY(zc_share);
86		FIELD_COPY(zc_jailid);
87		FIELD_COPY(zc_objset_stats);
88		FIELD_COPY(zc_begin_record);
89		FIELD_COPY(zc_inject_record.zi_objset);
90		FIELD_COPY(zc_inject_record.zi_object);
91		FIELD_COPY(zc_inject_record.zi_start);
92		FIELD_COPY(zc_inject_record.zi_end);
93		FIELD_COPY(zc_inject_record.zi_guid);
94		FIELD_COPY(zc_inject_record.zi_level);
95		FIELD_COPY(zc_inject_record.zi_error);
96		FIELD_COPY(zc_inject_record.zi_type);
97		FIELD_COPY(zc_inject_record.zi_freq);
98		FIELD_COPY(zc_inject_record.zi_failfast);
99		strlcpy(zc->zc_inject_record.zi_func,
100		    resume_c->zc_inject_record.zi_func, MAXNAMELEN);
101		FIELD_COPY(zc_inject_record.zi_iotype);
102		FIELD_COPY(zc_inject_record.zi_duration);
103		FIELD_COPY(zc_inject_record.zi_timer);
104		zc->zc_inject_record.zi_nlanes = 1;
105		FIELD_COPY(zc_inject_record.zi_cmd);
106		FIELD_COPY(zc_inject_record.zi_pad);
107		FIELD_COPY(zc_defer_destroy);
108		FIELD_COPY(zc_flags);
109		FIELD_COPY(zc_action_handle);
110		FIELD_COPY(zc_cleanup_fd);
111		FIELD_COPY(zc_simple);
112		FIELD_COPY(zc_resumable);
113		FIELD_COPY(zc_sendobj);
114		FIELD_COPY(zc_fromobj);
115		FIELD_COPY(zc_createtxg);
116		FIELD_COPY(zc_stat);
117#undef FIELD_COPY
118		break;
119
120	case ZFS_CMD_COMPAT_EDBP:
121		edbp_c = (void *)addr;
122		/* zc */
123		strlcpy(zc->zc_name, edbp_c->zc_name, MAXPATHLEN);
124		strlcpy(zc->zc_value, edbp_c->zc_value, MAXPATHLEN * 2);
125		strlcpy(zc->zc_string, edbp_c->zc_string, MAXPATHLEN);
126
127#define FIELD_COPY(field) zc->field = edbp_c->field
128		FIELD_COPY(zc_nvlist_src);
129		FIELD_COPY(zc_nvlist_src_size);
130		FIELD_COPY(zc_nvlist_dst);
131		FIELD_COPY(zc_nvlist_dst_size);
132		FIELD_COPY(zc_nvlist_dst_filled);
133		FIELD_COPY(zc_pad2);
134		FIELD_COPY(zc_history);
135		FIELD_COPY(zc_guid);
136		FIELD_COPY(zc_nvlist_conf);
137		FIELD_COPY(zc_nvlist_conf_size);
138		FIELD_COPY(zc_cookie);
139		FIELD_COPY(zc_objset_type);
140		FIELD_COPY(zc_perm_action);
141		FIELD_COPY(zc_history_len);
142		FIELD_COPY(zc_history_offset);
143		FIELD_COPY(zc_obj);
144		FIELD_COPY(zc_iflags);
145		FIELD_COPY(zc_share);
146		FIELD_COPY(zc_jailid);
147		FIELD_COPY(zc_objset_stats);
148		zc->zc_begin_record.drr_u.drr_begin = edbp_c->zc_begin_record;
149		FIELD_COPY(zc_inject_record.zi_objset);
150		FIELD_COPY(zc_inject_record.zi_object);
151		FIELD_COPY(zc_inject_record.zi_start);
152		FIELD_COPY(zc_inject_record.zi_end);
153		FIELD_COPY(zc_inject_record.zi_guid);
154		FIELD_COPY(zc_inject_record.zi_level);
155		FIELD_COPY(zc_inject_record.zi_error);
156		FIELD_COPY(zc_inject_record.zi_type);
157		FIELD_COPY(zc_inject_record.zi_freq);
158		FIELD_COPY(zc_inject_record.zi_failfast);
159		strlcpy(zc->zc_inject_record.zi_func,
160		    edbp_c->zc_inject_record.zi_func, MAXNAMELEN);
161		FIELD_COPY(zc_inject_record.zi_iotype);
162		FIELD_COPY(zc_inject_record.zi_duration);
163		FIELD_COPY(zc_inject_record.zi_timer);
164		zc->zc_inject_record.zi_nlanes = 1;
165		FIELD_COPY(zc_inject_record.zi_cmd);
166		FIELD_COPY(zc_inject_record.zi_pad);
167		FIELD_COPY(zc_defer_destroy);
168		FIELD_COPY(zc_flags);
169		FIELD_COPY(zc_action_handle);
170		FIELD_COPY(zc_cleanup_fd);
171		FIELD_COPY(zc_simple);
172		zc->zc_resumable = B_FALSE;
173		FIELD_COPY(zc_sendobj);
174		FIELD_COPY(zc_fromobj);
175		FIELD_COPY(zc_createtxg);
176		FIELD_COPY(zc_stat);
177#undef FIELD_COPY
178		break;
179
180	case ZFS_CMD_COMPAT_ZCMD:
181		zcmd_c = (void *)addr;
182		/* zc */
183		strlcpy(zc->zc_name, zcmd_c->zc_name, MAXPATHLEN);
184		strlcpy(zc->zc_value, zcmd_c->zc_value, MAXPATHLEN * 2);
185		strlcpy(zc->zc_string, zcmd_c->zc_string, MAXPATHLEN);
186
187#define FIELD_COPY(field) zc->field = zcmd_c->field
188		FIELD_COPY(zc_nvlist_src);
189		FIELD_COPY(zc_nvlist_src_size);
190		FIELD_COPY(zc_nvlist_dst);
191		FIELD_COPY(zc_nvlist_dst_size);
192		FIELD_COPY(zc_nvlist_dst_filled);
193		FIELD_COPY(zc_pad2);
194		FIELD_COPY(zc_history);
195		FIELD_COPY(zc_guid);
196		FIELD_COPY(zc_nvlist_conf);
197		FIELD_COPY(zc_nvlist_conf_size);
198		FIELD_COPY(zc_cookie);
199		FIELD_COPY(zc_objset_type);
200		FIELD_COPY(zc_perm_action);
201		FIELD_COPY(zc_history_len);
202		FIELD_COPY(zc_history_offset);
203		FIELD_COPY(zc_obj);
204		FIELD_COPY(zc_iflags);
205		FIELD_COPY(zc_share);
206		FIELD_COPY(zc_jailid);
207		FIELD_COPY(zc_objset_stats);
208		zc->zc_begin_record.drr_u.drr_begin = zcmd_c->zc_begin_record;
209		FIELD_COPY(zc_inject_record.zi_objset);
210		FIELD_COPY(zc_inject_record.zi_object);
211		FIELD_COPY(zc_inject_record.zi_start);
212		FIELD_COPY(zc_inject_record.zi_end);
213		FIELD_COPY(zc_inject_record.zi_guid);
214		FIELD_COPY(zc_inject_record.zi_level);
215		FIELD_COPY(zc_inject_record.zi_error);
216		FIELD_COPY(zc_inject_record.zi_type);
217		FIELD_COPY(zc_inject_record.zi_freq);
218		FIELD_COPY(zc_inject_record.zi_failfast);
219		strlcpy(zc->zc_inject_record.zi_func,
220		    zcmd_c->zc_inject_record.zi_func, MAXNAMELEN);
221		FIELD_COPY(zc_inject_record.zi_iotype);
222		FIELD_COPY(zc_inject_record.zi_duration);
223		FIELD_COPY(zc_inject_record.zi_timer);
224		zc->zc_inject_record.zi_nlanes = 1;
225		FIELD_COPY(zc_inject_record.zi_cmd);
226		FIELD_COPY(zc_inject_record.zi_pad);
227
228		/* boolean_t -> uint32_t */
229		zc->zc_defer_destroy = (uint32_t)(zcmd_c->zc_defer_destroy);
230		zc->zc_flags = 0;
231
232		FIELD_COPY(zc_action_handle);
233		FIELD_COPY(zc_cleanup_fd);
234		FIELD_COPY(zc_simple);
235		zc->zc_resumable = B_FALSE;
236		FIELD_COPY(zc_sendobj);
237		FIELD_COPY(zc_fromobj);
238		FIELD_COPY(zc_createtxg);
239		FIELD_COPY(zc_stat);
240#undef FIELD_COPY
241
242		break;
243
244	case ZFS_CMD_COMPAT_DEADMAN:
245		zcdm_c = (void *)addr;
246		/* zc */
247		strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN);
248		strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2);
249		strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN);
250
251#define FIELD_COPY(field) zc->field = zcdm_c->field
252		zc->zc_guid = zcdm_c->zc_guid;
253		zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf;
254		zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size;
255		zc->zc_nvlist_src = zcdm_c->zc_nvlist_src;
256		zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size;
257		zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst;
258		zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size;
259		zc->zc_cookie = zcdm_c->zc_cookie;
260		zc->zc_objset_type = zcdm_c->zc_objset_type;
261		zc->zc_perm_action = zcdm_c->zc_perm_action;
262		zc->zc_history = zcdm_c->zc_history;
263		zc->zc_history_len = zcdm_c->zc_history_len;
264		zc->zc_history_offset = zcdm_c->zc_history_offset;
265		zc->zc_obj = zcdm_c->zc_obj;
266		zc->zc_iflags = zcdm_c->zc_iflags;
267		zc->zc_share = zcdm_c->zc_share;
268		zc->zc_jailid = zcdm_c->zc_jailid;
269		zc->zc_objset_stats = zcdm_c->zc_objset_stats;
270		zc->zc_begin_record.drr_u.drr_begin = zcdm_c->zc_begin_record;
271		zc->zc_defer_destroy = zcdm_c->zc_defer_destroy;
272		(void)zcdm_c->zc_temphold;
273		zc->zc_action_handle = zcdm_c->zc_action_handle;
274		zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd;
275		zc->zc_simple = zcdm_c->zc_simple;
276		zc->zc_resumable = B_FALSE;
277		zc->zc_sendobj = zcdm_c->zc_sendobj;
278		zc->zc_fromobj = zcdm_c->zc_fromobj;
279		zc->zc_createtxg = zcdm_c->zc_createtxg;
280		zc->zc_stat = zcdm_c->zc_stat;
281		FIELD_COPY(zc_inject_record.zi_objset);
282		FIELD_COPY(zc_inject_record.zi_object);
283		FIELD_COPY(zc_inject_record.zi_start);
284		FIELD_COPY(zc_inject_record.zi_end);
285		FIELD_COPY(zc_inject_record.zi_guid);
286		FIELD_COPY(zc_inject_record.zi_level);
287		FIELD_COPY(zc_inject_record.zi_error);
288		FIELD_COPY(zc_inject_record.zi_type);
289		FIELD_COPY(zc_inject_record.zi_freq);
290		FIELD_COPY(zc_inject_record.zi_failfast);
291		strlcpy(zc->zc_inject_record.zi_func,
292		    resume_c->zc_inject_record.zi_func, MAXNAMELEN);
293		FIELD_COPY(zc_inject_record.zi_iotype);
294		FIELD_COPY(zc_inject_record.zi_duration);
295		FIELD_COPY(zc_inject_record.zi_timer);
296		zc->zc_inject_record.zi_nlanes = 1;
297		FIELD_COPY(zc_inject_record.zi_cmd);
298		FIELD_COPY(zc_inject_record.zi_pad);
299
300		/* we always assume zc_nvlist_dst_filled is true */
301		zc->zc_nvlist_dst_filled = B_TRUE;
302#undef FIELD_COPY
303		break;
304
305	case ZFS_CMD_COMPAT_V28:
306		zc28_c = (void *)addr;
307
308		/* zc */
309		strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
310		strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
311		strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
312		zc->zc_guid = zc28_c->zc_guid;
313		zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
314		zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
315		zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
316		zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
317		zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
318		zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
319		zc->zc_cookie = zc28_c->zc_cookie;
320		zc->zc_objset_type = zc28_c->zc_objset_type;
321		zc->zc_perm_action = zc28_c->zc_perm_action;
322		zc->zc_history = zc28_c->zc_history;
323		zc->zc_history_len = zc28_c->zc_history_len;
324		zc->zc_history_offset = zc28_c->zc_history_offset;
325		zc->zc_obj = zc28_c->zc_obj;
326		zc->zc_iflags = zc28_c->zc_iflags;
327		zc->zc_share = zc28_c->zc_share;
328		zc->zc_jailid = zc28_c->zc_jailid;
329		zc->zc_objset_stats = zc28_c->zc_objset_stats;
330		zc->zc_begin_record.drr_u.drr_begin = zc28_c->zc_begin_record;
331		zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
332		(void)zc28_c->zc_temphold;
333		zc->zc_action_handle = zc28_c->zc_action_handle;
334		zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
335		zc->zc_simple = zc28_c->zc_simple;
336		zc->zc_resumable = B_FALSE;
337		zc->zc_sendobj = zc28_c->zc_sendobj;
338		zc->zc_fromobj = zc28_c->zc_fromobj;
339		zc->zc_createtxg = zc28_c->zc_createtxg;
340		zc->zc_stat = zc28_c->zc_stat;
341
342		/* zc->zc_inject_record */
343		zc->zc_inject_record.zi_objset =
344		    zc28_c->zc_inject_record.zi_objset;
345		zc->zc_inject_record.zi_object =
346		    zc28_c->zc_inject_record.zi_object;
347		zc->zc_inject_record.zi_start =
348		    zc28_c->zc_inject_record.zi_start;
349		zc->zc_inject_record.zi_end =
350		    zc28_c->zc_inject_record.zi_end;
351		zc->zc_inject_record.zi_guid =
352		    zc28_c->zc_inject_record.zi_guid;
353		zc->zc_inject_record.zi_level =
354		    zc28_c->zc_inject_record.zi_level;
355		zc->zc_inject_record.zi_error =
356		    zc28_c->zc_inject_record.zi_error;
357		zc->zc_inject_record.zi_type =
358		    zc28_c->zc_inject_record.zi_type;
359		zc->zc_inject_record.zi_freq =
360		    zc28_c->zc_inject_record.zi_freq;
361		zc->zc_inject_record.zi_failfast =
362		    zc28_c->zc_inject_record.zi_failfast;
363		strlcpy(zc->zc_inject_record.zi_func,
364		    zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
365		zc->zc_inject_record.zi_iotype =
366		    zc28_c->zc_inject_record.zi_iotype;
367		zc->zc_inject_record.zi_duration =
368		    zc28_c->zc_inject_record.zi_duration;
369		zc->zc_inject_record.zi_timer =
370		    zc28_c->zc_inject_record.zi_timer;
371		zc->zc_inject_record.zi_nlanes = 1;
372		zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
373		zc->zc_inject_record.zi_pad = 0;
374		break;
375
376	case ZFS_CMD_COMPAT_V15:
377		zc_c = (void *)addr;
378
379		/* zc */
380		strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
381		strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
382		strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
383		zc->zc_guid = zc_c->zc_guid;
384		zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
385		zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
386		zc->zc_nvlist_src = zc_c->zc_nvlist_src;
387		zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
388		zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
389		zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
390		zc->zc_cookie = zc_c->zc_cookie;
391		zc->zc_objset_type = zc_c->zc_objset_type;
392		zc->zc_perm_action = zc_c->zc_perm_action;
393		zc->zc_history = zc_c->zc_history;
394		zc->zc_history_len = zc_c->zc_history_len;
395		zc->zc_history_offset = zc_c->zc_history_offset;
396		zc->zc_obj = zc_c->zc_obj;
397		zc->zc_share = zc_c->zc_share;
398		zc->zc_jailid = zc_c->zc_jailid;
399		zc->zc_objset_stats = zc_c->zc_objset_stats;
400		zc->zc_begin_record.drr_u.drr_begin = zc_c->zc_begin_record;
401
402		/* zc->zc_inject_record */
403		zc->zc_inject_record.zi_objset =
404		    zc_c->zc_inject_record.zi_objset;
405		zc->zc_inject_record.zi_object =
406		    zc_c->zc_inject_record.zi_object;
407		zc->zc_inject_record.zi_start =
408		    zc_c->zc_inject_record.zi_start;
409		zc->zc_inject_record.zi_end =
410		    zc_c->zc_inject_record.zi_end;
411		zc->zc_inject_record.zi_guid =
412		    zc_c->zc_inject_record.zi_guid;
413		zc->zc_inject_record.zi_level =
414		    zc_c->zc_inject_record.zi_level;
415		zc->zc_inject_record.zi_error =
416		    zc_c->zc_inject_record.zi_error;
417		zc->zc_inject_record.zi_type =
418		    zc_c->zc_inject_record.zi_type;
419		zc->zc_inject_record.zi_freq =
420		    zc_c->zc_inject_record.zi_freq;
421		zc->zc_inject_record.zi_failfast =
422		    zc_c->zc_inject_record.zi_failfast;
423		break;
424	}
425}
426
427void
428zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request,
429    const int cflag)
430{
431	zfs_cmd_v15_t *zc_c;
432	zfs_cmd_v28_t *zc28_c;
433	zfs_cmd_deadman_t *zcdm_c;
434	zfs_cmd_zcmd_t *zcmd_c;
435	zfs_cmd_edbp_t *edbp_c;
436	zfs_cmd_resume_t *resume_c;
437
438	switch (cflag) {
439	case ZFS_CMD_COMPAT_RESUME:
440		resume_c = (void *)addr;
441		strlcpy(resume_c->zc_name, zc->zc_name, MAXPATHLEN);
442		strlcpy(resume_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
443		strlcpy(resume_c->zc_string, zc->zc_string, MAXPATHLEN);
444
445#define FIELD_COPY(field) resume_c->field = zc->field
446		FIELD_COPY(zc_nvlist_src);
447		FIELD_COPY(zc_nvlist_src_size);
448		FIELD_COPY(zc_nvlist_dst);
449		FIELD_COPY(zc_nvlist_dst_size);
450		FIELD_COPY(zc_nvlist_dst_filled);
451		FIELD_COPY(zc_pad2);
452		FIELD_COPY(zc_history);
453		FIELD_COPY(zc_guid);
454		FIELD_COPY(zc_nvlist_conf);
455		FIELD_COPY(zc_nvlist_conf_size);
456		FIELD_COPY(zc_cookie);
457		FIELD_COPY(zc_objset_type);
458		FIELD_COPY(zc_perm_action);
459		FIELD_COPY(zc_history_len);
460		FIELD_COPY(zc_history_offset);
461		FIELD_COPY(zc_obj);
462		FIELD_COPY(zc_iflags);
463		FIELD_COPY(zc_share);
464		FIELD_COPY(zc_jailid);
465		FIELD_COPY(zc_objset_stats);
466		FIELD_COPY(zc_begin_record);
467		FIELD_COPY(zc_inject_record.zi_objset);
468		FIELD_COPY(zc_inject_record.zi_object);
469		FIELD_COPY(zc_inject_record.zi_start);
470		FIELD_COPY(zc_inject_record.zi_end);
471		FIELD_COPY(zc_inject_record.zi_guid);
472		FIELD_COPY(zc_inject_record.zi_level);
473		FIELD_COPY(zc_inject_record.zi_error);
474		FIELD_COPY(zc_inject_record.zi_type);
475		FIELD_COPY(zc_inject_record.zi_freq);
476		FIELD_COPY(zc_inject_record.zi_failfast);
477		strlcpy(resume_c->zc_inject_record.zi_func,
478		    zc->zc_inject_record.zi_func, MAXNAMELEN);
479		FIELD_COPY(zc_inject_record.zi_iotype);
480		FIELD_COPY(zc_inject_record.zi_duration);
481		FIELD_COPY(zc_inject_record.zi_timer);
482		FIELD_COPY(zc_inject_record.zi_cmd);
483		FIELD_COPY(zc_inject_record.zi_pad);
484		FIELD_COPY(zc_defer_destroy);
485		FIELD_COPY(zc_flags);
486		FIELD_COPY(zc_action_handle);
487		FIELD_COPY(zc_cleanup_fd);
488		FIELD_COPY(zc_simple);
489		FIELD_COPY(zc_sendobj);
490		FIELD_COPY(zc_fromobj);
491		FIELD_COPY(zc_createtxg);
492		FIELD_COPY(zc_stat);
493#undef FIELD_COPY
494		break;
495
496	case ZFS_CMD_COMPAT_EDBP:
497		edbp_c = (void *)addr;
498		strlcpy(edbp_c->zc_name, zc->zc_name, MAXPATHLEN);
499		strlcpy(edbp_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
500		strlcpy(edbp_c->zc_string, zc->zc_string, MAXPATHLEN);
501
502#define FIELD_COPY(field) edbp_c->field = zc->field
503		FIELD_COPY(zc_nvlist_src);
504		FIELD_COPY(zc_nvlist_src_size);
505		FIELD_COPY(zc_nvlist_dst);
506		FIELD_COPY(zc_nvlist_dst_size);
507		FIELD_COPY(zc_nvlist_dst_filled);
508		FIELD_COPY(zc_pad2);
509		FIELD_COPY(zc_history);
510		FIELD_COPY(zc_guid);
511		FIELD_COPY(zc_nvlist_conf);
512		FIELD_COPY(zc_nvlist_conf_size);
513		FIELD_COPY(zc_cookie);
514		FIELD_COPY(zc_objset_type);
515		FIELD_COPY(zc_perm_action);
516		FIELD_COPY(zc_history_len);
517		FIELD_COPY(zc_history_offset);
518		FIELD_COPY(zc_obj);
519		FIELD_COPY(zc_iflags);
520		FIELD_COPY(zc_share);
521		FIELD_COPY(zc_jailid);
522		FIELD_COPY(zc_objset_stats);
523		edbp_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
524		FIELD_COPY(zc_inject_record.zi_objset);
525		FIELD_COPY(zc_inject_record.zi_object);
526		FIELD_COPY(zc_inject_record.zi_start);
527		FIELD_COPY(zc_inject_record.zi_end);
528		FIELD_COPY(zc_inject_record.zi_guid);
529		FIELD_COPY(zc_inject_record.zi_level);
530		FIELD_COPY(zc_inject_record.zi_error);
531		FIELD_COPY(zc_inject_record.zi_type);
532		FIELD_COPY(zc_inject_record.zi_freq);
533		FIELD_COPY(zc_inject_record.zi_failfast);
534		strlcpy(resume_c->zc_inject_record.zi_func,
535		    zc->zc_inject_record.zi_func, MAXNAMELEN);
536		FIELD_COPY(zc_inject_record.zi_iotype);
537		FIELD_COPY(zc_inject_record.zi_duration);
538		FIELD_COPY(zc_inject_record.zi_timer);
539		FIELD_COPY(zc_inject_record.zi_cmd);
540		FIELD_COPY(zc_inject_record.zi_pad);
541		FIELD_COPY(zc_defer_destroy);
542		FIELD_COPY(zc_flags);
543		FIELD_COPY(zc_action_handle);
544		FIELD_COPY(zc_cleanup_fd);
545		FIELD_COPY(zc_simple);
546		FIELD_COPY(zc_sendobj);
547		FIELD_COPY(zc_fromobj);
548		FIELD_COPY(zc_createtxg);
549		FIELD_COPY(zc_stat);
550#undef FIELD_COPY
551		break;
552
553	case ZFS_CMD_COMPAT_ZCMD:
554		zcmd_c = (void *)addr;
555		/* zc */
556		strlcpy(zcmd_c->zc_name, zc->zc_name, MAXPATHLEN);
557		strlcpy(zcmd_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
558		strlcpy(zcmd_c->zc_string, zc->zc_string, MAXPATHLEN);
559
560#define FIELD_COPY(field) zcmd_c->field = zc->field
561		FIELD_COPY(zc_nvlist_src);
562		FIELD_COPY(zc_nvlist_src_size);
563		FIELD_COPY(zc_nvlist_dst);
564		FIELD_COPY(zc_nvlist_dst_size);
565		FIELD_COPY(zc_nvlist_dst_filled);
566		FIELD_COPY(zc_pad2);
567		FIELD_COPY(zc_history);
568		FIELD_COPY(zc_guid);
569		FIELD_COPY(zc_nvlist_conf);
570		FIELD_COPY(zc_nvlist_conf_size);
571		FIELD_COPY(zc_cookie);
572		FIELD_COPY(zc_objset_type);
573		FIELD_COPY(zc_perm_action);
574		FIELD_COPY(zc_history_len);
575		FIELD_COPY(zc_history_offset);
576		FIELD_COPY(zc_obj);
577		FIELD_COPY(zc_iflags);
578		FIELD_COPY(zc_share);
579		FIELD_COPY(zc_jailid);
580		FIELD_COPY(zc_objset_stats);
581		zcmd_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
582		FIELD_COPY(zc_inject_record.zi_objset);
583		FIELD_COPY(zc_inject_record.zi_object);
584		FIELD_COPY(zc_inject_record.zi_start);
585		FIELD_COPY(zc_inject_record.zi_end);
586		FIELD_COPY(zc_inject_record.zi_guid);
587		FIELD_COPY(zc_inject_record.zi_level);
588		FIELD_COPY(zc_inject_record.zi_error);
589		FIELD_COPY(zc_inject_record.zi_type);
590		FIELD_COPY(zc_inject_record.zi_freq);
591		FIELD_COPY(zc_inject_record.zi_failfast);
592		strlcpy(resume_c->zc_inject_record.zi_func,
593		    zc->zc_inject_record.zi_func, MAXNAMELEN);
594		FIELD_COPY(zc_inject_record.zi_iotype);
595		FIELD_COPY(zc_inject_record.zi_duration);
596		FIELD_COPY(zc_inject_record.zi_timer);
597		FIELD_COPY(zc_inject_record.zi_cmd);
598		FIELD_COPY(zc_inject_record.zi_pad);
599
600		/* boolean_t -> uint32_t */
601		zcmd_c->zc_defer_destroy = (uint32_t)(zc->zc_defer_destroy);
602		zcmd_c->zc_temphold = 0;
603
604		FIELD_COPY(zc_action_handle);
605		FIELD_COPY(zc_cleanup_fd);
606		FIELD_COPY(zc_simple);
607		FIELD_COPY(zc_sendobj);
608		FIELD_COPY(zc_fromobj);
609		FIELD_COPY(zc_createtxg);
610		FIELD_COPY(zc_stat);
611#undef FIELD_COPY
612
613		break;
614
615	case ZFS_CMD_COMPAT_DEADMAN:
616		zcdm_c = (void *)addr;
617
618		strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN);
619		strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
620		strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN);
621
622#define FIELD_COPY(field) zcdm_c->field = zc->field
623		zcdm_c->zc_guid = zc->zc_guid;
624		zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf;
625		zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
626		zcdm_c->zc_nvlist_src = zc->zc_nvlist_src;
627		zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
628		zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst;
629		zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
630		zcdm_c->zc_cookie = zc->zc_cookie;
631		zcdm_c->zc_objset_type = zc->zc_objset_type;
632		zcdm_c->zc_perm_action = zc->zc_perm_action;
633		zcdm_c->zc_history = zc->zc_history;
634		zcdm_c->zc_history_len = zc->zc_history_len;
635		zcdm_c->zc_history_offset = zc->zc_history_offset;
636		zcdm_c->zc_obj = zc->zc_obj;
637		zcdm_c->zc_iflags = zc->zc_iflags;
638		zcdm_c->zc_share = zc->zc_share;
639		zcdm_c->zc_jailid = zc->zc_jailid;
640		zcdm_c->zc_objset_stats = zc->zc_objset_stats;
641		zcdm_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
642		zcdm_c->zc_defer_destroy = zc->zc_defer_destroy;
643		zcdm_c->zc_temphold = 0;
644		zcdm_c->zc_action_handle = zc->zc_action_handle;
645		zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd;
646		zcdm_c->zc_simple = zc->zc_simple;
647		zcdm_c->zc_sendobj = zc->zc_sendobj;
648		zcdm_c->zc_fromobj = zc->zc_fromobj;
649		zcdm_c->zc_createtxg = zc->zc_createtxg;
650		zcdm_c->zc_stat = zc->zc_stat;
651		FIELD_COPY(zc_inject_record.zi_objset);
652		FIELD_COPY(zc_inject_record.zi_object);
653		FIELD_COPY(zc_inject_record.zi_start);
654		FIELD_COPY(zc_inject_record.zi_end);
655		FIELD_COPY(zc_inject_record.zi_guid);
656		FIELD_COPY(zc_inject_record.zi_level);
657		FIELD_COPY(zc_inject_record.zi_error);
658		FIELD_COPY(zc_inject_record.zi_type);
659		FIELD_COPY(zc_inject_record.zi_freq);
660		FIELD_COPY(zc_inject_record.zi_failfast);
661		strlcpy(resume_c->zc_inject_record.zi_func,
662		    zc->zc_inject_record.zi_func, MAXNAMELEN);
663		FIELD_COPY(zc_inject_record.zi_iotype);
664		FIELD_COPY(zc_inject_record.zi_duration);
665		FIELD_COPY(zc_inject_record.zi_timer);
666		FIELD_COPY(zc_inject_record.zi_cmd);
667		FIELD_COPY(zc_inject_record.zi_pad);
668#undef FIELD_COPY
669#ifndef _KERNEL
670		if (request == ZFS_IOC_RECV)
671			strlcpy(zcdm_c->zc_top_ds,
672			    zc->zc_value + strlen(zc->zc_value) + 1,
673			    (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1);
674#endif
675		break;
676
677	case ZFS_CMD_COMPAT_V28:
678		zc28_c = (void *)addr;
679
680		strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
681		strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
682		strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
683		zc28_c->zc_guid = zc->zc_guid;
684		zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
685		zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
686		zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
687		zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
688		zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
689		zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
690		zc28_c->zc_cookie = zc->zc_cookie;
691		zc28_c->zc_objset_type = zc->zc_objset_type;
692		zc28_c->zc_perm_action = zc->zc_perm_action;
693		zc28_c->zc_history = zc->zc_history;
694		zc28_c->zc_history_len = zc->zc_history_len;
695		zc28_c->zc_history_offset = zc->zc_history_offset;
696		zc28_c->zc_obj = zc->zc_obj;
697		zc28_c->zc_iflags = zc->zc_iflags;
698		zc28_c->zc_share = zc->zc_share;
699		zc28_c->zc_jailid = zc->zc_jailid;
700		zc28_c->zc_objset_stats = zc->zc_objset_stats;
701		zc28_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
702		zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
703		zc28_c->zc_temphold = 0;
704		zc28_c->zc_action_handle = zc->zc_action_handle;
705		zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
706		zc28_c->zc_simple = zc->zc_simple;
707		zc28_c->zc_sendobj = zc->zc_sendobj;
708		zc28_c->zc_fromobj = zc->zc_fromobj;
709		zc28_c->zc_createtxg = zc->zc_createtxg;
710		zc28_c->zc_stat = zc->zc_stat;
711#ifndef _KERNEL
712		if (request == ZFS_IOC_RECV)
713			strlcpy(zc28_c->zc_top_ds,
714			    zc->zc_value + strlen(zc->zc_value) + 1,
715			    MAXPATHLEN * 2 - strlen(zc->zc_value) - 1);
716#endif
717		/* zc_inject_record */
718		zc28_c->zc_inject_record.zi_objset =
719		    zc->zc_inject_record.zi_objset;
720		zc28_c->zc_inject_record.zi_object =
721		    zc->zc_inject_record.zi_object;
722		zc28_c->zc_inject_record.zi_start =
723		    zc->zc_inject_record.zi_start;
724		zc28_c->zc_inject_record.zi_end =
725		    zc->zc_inject_record.zi_end;
726		zc28_c->zc_inject_record.zi_guid =
727		    zc->zc_inject_record.zi_guid;
728		zc28_c->zc_inject_record.zi_level =
729		    zc->zc_inject_record.zi_level;
730		zc28_c->zc_inject_record.zi_error =
731		    zc->zc_inject_record.zi_error;
732		zc28_c->zc_inject_record.zi_type =
733		    zc->zc_inject_record.zi_type;
734		zc28_c->zc_inject_record.zi_freq =
735		    zc->zc_inject_record.zi_freq;
736		zc28_c->zc_inject_record.zi_failfast =
737		    zc->zc_inject_record.zi_failfast;
738		strlcpy(zc28_c->zc_inject_record.zi_func,
739		    zc->zc_inject_record.zi_func, MAXNAMELEN);
740		zc28_c->zc_inject_record.zi_iotype =
741		    zc->zc_inject_record.zi_iotype;
742		zc28_c->zc_inject_record.zi_duration =
743		    zc->zc_inject_record.zi_duration;
744		zc28_c->zc_inject_record.zi_timer =
745		    zc->zc_inject_record.zi_timer;
746		break;
747
748	case ZFS_CMD_COMPAT_V15:
749		zc_c = (void *)addr;
750
751		/* zc */
752		strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
753		strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
754		strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
755		zc_c->zc_guid = zc->zc_guid;
756		zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
757		zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
758		zc_c->zc_nvlist_src = zc->zc_nvlist_src;
759		zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
760		zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
761		zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
762		zc_c->zc_cookie = zc->zc_cookie;
763		zc_c->zc_objset_type = zc->zc_objset_type;
764		zc_c->zc_perm_action = zc->zc_perm_action;
765		zc_c->zc_history = zc->zc_history;
766		zc_c->zc_history_len = zc->zc_history_len;
767		zc_c->zc_history_offset = zc->zc_history_offset;
768		zc_c->zc_obj = zc->zc_obj;
769		zc_c->zc_share = zc->zc_share;
770		zc_c->zc_jailid = zc->zc_jailid;
771		zc_c->zc_objset_stats = zc->zc_objset_stats;
772		zc_c->zc_begin_record = zc->zc_begin_record.drr_u.drr_begin;
773
774		/* zc_inject_record */
775		zc_c->zc_inject_record.zi_objset =
776		    zc->zc_inject_record.zi_objset;
777		zc_c->zc_inject_record.zi_object =
778		    zc->zc_inject_record.zi_object;
779		zc_c->zc_inject_record.zi_start =
780		    zc->zc_inject_record.zi_start;
781		zc_c->zc_inject_record.zi_end =
782		    zc->zc_inject_record.zi_end;
783		zc_c->zc_inject_record.zi_guid =
784		    zc->zc_inject_record.zi_guid;
785		zc_c->zc_inject_record.zi_level =
786		    zc->zc_inject_record.zi_level;
787		zc_c->zc_inject_record.zi_error =
788		    zc->zc_inject_record.zi_error;
789		zc_c->zc_inject_record.zi_type =
790		    zc->zc_inject_record.zi_type;
791		zc_c->zc_inject_record.zi_freq =
792		    zc->zc_inject_record.zi_freq;
793		zc_c->zc_inject_record.zi_failfast =
794		    zc->zc_inject_record.zi_failfast;
795
796		break;
797	}
798}
799
800static int
801zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
802    nvlist_t **nvp)
803{
804	char *packed;
805	int error;
806	nvlist_t *list = NULL;
807
808	/*
809	 * Read in and unpack the user-supplied nvlist.
810	 */
811	if (size == 0)
812		return (EINVAL);
813
814#ifdef _KERNEL
815	packed = kmem_alloc(size, KM_SLEEP);
816	if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
817	    iflag)) != 0) {
818		kmem_free(packed, size);
819		return (error);
820	}
821#else
822	packed = (void *)(uintptr_t)nvl;
823#endif
824
825	error = nvlist_unpack(packed, size, &list, 0);
826
827#ifdef _KERNEL
828	kmem_free(packed, size);
829#endif
830
831	if (error != 0)
832		return (error);
833
834	*nvp = list;
835	return (0);
836}
837
838static int
839zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
840{
841	char *packed = NULL;
842	int error = 0;
843	size_t size;
844
845	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
846
847#ifdef _KERNEL
848	packed = kmem_alloc(size, KM_SLEEP);
849	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
850	    KM_SLEEP) == 0);
851
852	if (ddi_copyout(packed,
853	    (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
854		error = EFAULT;
855	kmem_free(packed, size);
856#else
857	packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
858	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
859	    0) == 0);
860#endif
861
862	zc->zc_nvlist_dst_size = size;
863	return (error);
864}
865
866static void
867zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
868{
869	nvlist_t **child;
870	nvlist_t *nvroot = NULL;
871	vdev_stat_t *vs;
872	uint_t c, children, nelem;
873
874	if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
875	    &child, &children) == 0) {
876		for (c = 0; c < children; c++) {
877			zfs_ioctl_compat_fix_stats_nvlist(child[c]);
878		}
879	}
880
881	if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
882	    &nvroot) == 0)
883		zfs_ioctl_compat_fix_stats_nvlist(nvroot);
884#ifdef _KERNEL
885	if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
886#else
887	if ((nvlist_lookup_uint64_array(nvl, "stats",
888#endif
889
890	    (uint64_t **)&vs, &nelem) == 0)) {
891		nvlist_add_uint64_array(nvl,
892#ifdef _KERNEL
893		    "stats",
894#else
895		    ZPOOL_CONFIG_VDEV_STATS,
896#endif
897		    (uint64_t *)vs, nelem);
898#ifdef _KERNEL
899		nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
900#else
901		nvlist_remove(nvl, "stats",
902#endif
903		    DATA_TYPE_UINT64_ARRAY);
904	}
905}
906
907static int
908zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
909{
910	nvlist_t *nv, *nvp = NULL;
911	nvpair_t *elem;
912	int error;
913
914	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
915	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
916		return (error);
917
918	if (nc == 5) { /* ZFS_IOC_POOL_STATS */
919		elem = NULL;
920		while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
921			if (nvpair_value_nvlist(elem, &nvp) == 0)
922				zfs_ioctl_compat_fix_stats_nvlist(nvp);
923		}
924		elem = NULL;
925	} else
926		zfs_ioctl_compat_fix_stats_nvlist(nv);
927
928	error = zfs_ioctl_compat_put_nvlist(zc, nv);
929
930	nvlist_free(nv);
931
932	return (error);
933}
934
935static int
936zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
937{
938	nvlist_t *nv, *nva = NULL;
939	int error;
940
941	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
942	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
943		return (error);
944
945#ifdef _KERNEL
946	if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
947		nvlist_add_nvlist(nv, "used", nva);
948		nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
949	}
950
951	if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
952		nvlist_add_nvlist(nv, "available", nva);
953		nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
954	}
955#else
956	if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
957		nvlist_add_nvlist(nv, "allocated", nva);
958		nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
959	}
960
961	if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
962		nvlist_add_nvlist(nv, "free", nva);
963		nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
964	}
965#endif
966
967	error = zfs_ioctl_compat_put_nvlist(zc, nv);
968
969	nvlist_free(nv);
970
971	return (error);
972}
973
974#ifndef _KERNEL
975int
976zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
977{
978	int nc, ret;
979	void *zc_c;
980	unsigned long ncmd;
981	zfs_iocparm_t zp;
982
983	switch (cflag) {
984	case ZFS_CMD_COMPAT_NONE:
985		ncmd = _IOWR('Z', request, struct zfs_iocparm);
986		zp.zfs_cmd = (uint64_t)zc;
987		zp.zfs_cmd_size = sizeof(zfs_cmd_t);
988		zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT;
989		return (ioctl(fd, ncmd, &zp));
990	case ZFS_CMD_COMPAT_RESUME:
991		ncmd = _IOWR('Z', request, struct zfs_iocparm);
992		zp.zfs_cmd = (uint64_t)zc;
993		zp.zfs_cmd_size = sizeof(zfs_cmd_resume_t);
994		zp.zfs_ioctl_version = ZFS_IOCVER_RESUME;
995		return (ioctl(fd, ncmd, &zp));
996	case ZFS_CMD_COMPAT_EDBP:
997		ncmd = _IOWR('Z', request, struct zfs_iocparm);
998		zp.zfs_cmd = (uint64_t)zc;
999		zp.zfs_cmd_size = sizeof(zfs_cmd_edbp_t);
1000		zp.zfs_ioctl_version = ZFS_IOCVER_EDBP;
1001		return (ioctl(fd, ncmd, &zp));
1002	case ZFS_CMD_COMPAT_ZCMD:
1003		ncmd = _IOWR('Z', request, struct zfs_iocparm);
1004		zp.zfs_cmd = (uint64_t)zc;
1005		zp.zfs_cmd_size = sizeof(zfs_cmd_zcmd_t);
1006		zp.zfs_ioctl_version = ZFS_IOCVER_ZCMD;
1007		return (ioctl(fd, ncmd, &zp));
1008	case ZFS_CMD_COMPAT_LZC:
1009		ncmd = _IOWR('Z', request, struct zfs_cmd);
1010		return (ioctl(fd, ncmd, zc));
1011	case ZFS_CMD_COMPAT_DEADMAN:
1012		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
1013		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
1014		break;
1015	case ZFS_CMD_COMPAT_V28:
1016		zc_c = malloc(sizeof(zfs_cmd_v28_t));
1017		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
1018		break;
1019	case ZFS_CMD_COMPAT_V15:
1020		nc = zfs_ioctl_v28_to_v15[request];
1021		zc_c = malloc(sizeof(zfs_cmd_v15_t));
1022		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
1023		break;
1024	default:
1025		return (EINVAL);
1026	}
1027
1028	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
1029		return (ENOTSUP);
1030
1031	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
1032
1033	ret = ioctl(fd, ncmd, zc_c);
1034	if (cflag == ZFS_CMD_COMPAT_V15 &&
1035	    nc == ZFS_IOC_POOL_IMPORT)
1036		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
1037		    struct zfs_cmd_v15), zc_c);
1038	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
1039	free(zc_c);
1040
1041	if (cflag == ZFS_CMD_COMPAT_V15) {
1042		switch (nc) {
1043		case ZFS_IOC_POOL_IMPORT:
1044		case ZFS_IOC_POOL_CONFIGS:
1045		case ZFS_IOC_POOL_STATS:
1046		case ZFS_IOC_POOL_TRYIMPORT:
1047			zfs_ioctl_compat_fix_stats(zc, nc);
1048			break;
1049		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
1050			zfs_ioctl_compat_pool_get_props(zc);
1051			break;
1052		}
1053	}
1054
1055	return (ret);
1056}
1057#else /* _KERNEL */
1058int
1059zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
1060{
1061	int error = 0;
1062
1063	/* are we creating a clone? */
1064	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
1065		*vec = ZFS_IOC_CLONE;
1066
1067	if (cflag == ZFS_CMD_COMPAT_V15) {
1068		switch (*vec) {
1069
1070		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
1071			zc->zc_cookie = POOL_SCAN_SCRUB;
1072			break;
1073		}
1074	}
1075
1076	return (error);
1077}
1078
1079void
1080zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
1081{
1082	if (cflag == ZFS_CMD_COMPAT_V15) {
1083		switch (vec) {
1084		case ZFS_IOC_POOL_CONFIGS:
1085		case ZFS_IOC_POOL_STATS:
1086		case ZFS_IOC_POOL_TRYIMPORT:
1087			zfs_ioctl_compat_fix_stats(zc, vec);
1088			break;
1089		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
1090			zfs_ioctl_compat_pool_get_props(zc);
1091			break;
1092		}
1093	}
1094}
1095
1096nvlist_t *
1097zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
1098    const int cflag)
1099{
1100	nvlist_t *nvl, *tmpnvl, *hnvl;
1101	nvpair_t *elem;
1102	char *poolname, *snapname;
1103	int err;
1104
1105	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
1106	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
1107	    cflag == ZFS_CMD_COMPAT_RESUME)
1108		goto out;
1109
1110	switch (vec) {
1111	case ZFS_IOC_CREATE:
1112		nvl = fnvlist_alloc();
1113		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
1114		if (innvl != NULL) {
1115			fnvlist_add_nvlist(nvl, "props", innvl);
1116			nvlist_free(innvl);
1117		}
1118		return (nvl);
1119	break;
1120	case ZFS_IOC_CLONE:
1121		nvl = fnvlist_alloc();
1122		fnvlist_add_string(nvl, "origin", zc->zc_value);
1123		if (innvl != NULL) {
1124			fnvlist_add_nvlist(nvl, "props", innvl);
1125			nvlist_free(innvl);
1126		}
1127		return (nvl);
1128	break;
1129	case ZFS_IOC_SNAPSHOT:
1130		if (innvl == NULL)
1131			goto out;
1132		nvl = fnvlist_alloc();
1133		fnvlist_add_nvlist(nvl, "props", innvl);
1134		tmpnvl = fnvlist_alloc();
1135		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
1136		fnvlist_add_boolean(tmpnvl, snapname);
1137		kmem_free(snapname, strlen(snapname + 1));
1138		/* check if we are doing a recursive snapshot */
1139		if (zc->zc_cookie)
1140			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
1141			    tmpnvl);
1142		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
1143		fnvlist_free(tmpnvl);
1144		nvlist_free(innvl);
1145		/* strip dataset part from zc->zc_name */
1146		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1147		return (nvl);
1148	break;
1149	case ZFS_IOC_SPACE_SNAPS:
1150		nvl = fnvlist_alloc();
1151		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
1152		if (innvl != NULL)
1153			nvlist_free(innvl);
1154		return (nvl);
1155	break;
1156	case ZFS_IOC_DESTROY_SNAPS:
1157		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
1158			goto out;
1159		nvl = fnvlist_alloc();
1160		if (innvl != NULL) {
1161			fnvlist_add_nvlist(nvl, "snaps", innvl);
1162		} else {
1163			/*
1164			 * We are probably called by even older binaries,
1165			 * allocate and populate nvlist with recursive
1166			 * snapshots
1167			 */
1168			if (zfs_component_namecheck(zc->zc_value, NULL,
1169			    NULL) == 0) {
1170				tmpnvl = fnvlist_alloc();
1171				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
1172				    zc->zc_value, tmpnvl) == 0)
1173					fnvlist_add_nvlist(nvl, "snaps",
1174					    tmpnvl);
1175				nvlist_free(tmpnvl);
1176			}
1177		}
1178		if (innvl != NULL)
1179			nvlist_free(innvl);
1180		/* strip dataset part from zc->zc_name */
1181		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1182		return (nvl);
1183	break;
1184	case ZFS_IOC_HOLD:
1185		nvl = fnvlist_alloc();
1186		tmpnvl = fnvlist_alloc();
1187		if (zc->zc_cleanup_fd != -1)
1188			fnvlist_add_int32(nvl, "cleanup_fd",
1189			    (int32_t)zc->zc_cleanup_fd);
1190		if (zc->zc_cookie) {
1191			hnvl = fnvlist_alloc();
1192			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
1193			    zc->zc_value, hnvl) == 0) {
1194				elem = NULL;
1195				while ((elem = nvlist_next_nvpair(hnvl,
1196				    elem)) != NULL) {
1197					nvlist_add_string(tmpnvl,
1198					    nvpair_name(elem), zc->zc_string);
1199				}
1200			}
1201			nvlist_free(hnvl);
1202		} else {
1203			snapname = kmem_asprintf("%s@%s", zc->zc_name,
1204			    zc->zc_value);
1205			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
1206			kmem_free(snapname, strlen(snapname + 1));
1207		}
1208		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
1209		nvlist_free(tmpnvl);
1210		if (innvl != NULL)
1211			nvlist_free(innvl);
1212		/* strip dataset part from zc->zc_name */
1213		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1214		return (nvl);
1215	break;
1216	case ZFS_IOC_RELEASE:
1217		nvl = fnvlist_alloc();
1218		tmpnvl = fnvlist_alloc();
1219		if (zc->zc_cookie) {
1220			hnvl = fnvlist_alloc();
1221			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
1222			    zc->zc_value, hnvl) == 0) {
1223				elem = NULL;
1224				while ((elem = nvlist_next_nvpair(hnvl,
1225				    elem)) != NULL) {
1226					fnvlist_add_boolean(tmpnvl,
1227					    zc->zc_string);
1228					fnvlist_add_nvlist(nvl,
1229					    nvpair_name(elem), tmpnvl);
1230				}
1231			}
1232			nvlist_free(hnvl);
1233		} else {
1234			snapname = kmem_asprintf("%s@%s", zc->zc_name,
1235			    zc->zc_value);
1236			fnvlist_add_boolean(tmpnvl, zc->zc_string);
1237			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
1238			kmem_free(snapname, strlen(snapname + 1));
1239		}
1240		nvlist_free(tmpnvl);
1241		if (innvl != NULL)
1242			nvlist_free(innvl);
1243		/* strip dataset part from zc->zc_name */
1244		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1245		return (nvl);
1246	break;
1247	}
1248out:
1249	return (innvl);
1250}
1251
1252nvlist_t *
1253zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
1254    const int cflag)
1255{
1256	nvlist_t *tmpnvl;
1257
1258	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
1259	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
1260	    cflag == ZFS_CMD_COMPAT_RESUME)
1261		return (outnvl);
1262
1263	switch (vec) {
1264	case ZFS_IOC_SPACE_SNAPS:
1265		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
1266		(void) nvlist_lookup_uint64(outnvl, "compressed",
1267		    &zc->zc_objset_type);
1268		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
1269		    &zc->zc_perm_action);
1270		nvlist_free(outnvl);
1271		/* return empty outnvl */
1272		tmpnvl = fnvlist_alloc();
1273		return (tmpnvl);
1274	break;
1275	case ZFS_IOC_CREATE:
1276	case ZFS_IOC_CLONE:
1277	case ZFS_IOC_HOLD:
1278	case ZFS_IOC_RELEASE:
1279		nvlist_free(outnvl);
1280		/* return empty outnvl */
1281		tmpnvl = fnvlist_alloc();
1282		return (tmpnvl);
1283	break;
1284	}
1285
1286	return (outnvl);
1287}
1288#endif /* KERNEL */
1289