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