zfs_ioctl_compat.c revision 268649
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_LZC:
701		ncmd = _IOWR('Z', request, struct zfs_cmd);
702		return (ioctl(fd, ncmd, zc));
703	case ZFS_CMD_COMPAT_DEADMAN:
704		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
705		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
706		break;
707	case ZFS_CMD_COMPAT_V28:
708		zc_c = malloc(sizeof(zfs_cmd_v28_t));
709		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
710		break;
711	case ZFS_CMD_COMPAT_V15:
712		nc = zfs_ioctl_v28_to_v15[request];
713		zc_c = malloc(sizeof(zfs_cmd_v15_t));
714		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
715		break;
716	default:
717		return (EINVAL);
718	}
719
720	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
721		return (ENOTSUP);
722
723	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
724
725	ret = ioctl(fd, ncmd, zc_c);
726	if (cflag == ZFS_CMD_COMPAT_V15 &&
727	    nc == ZFS_IOC_POOL_IMPORT)
728		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
729		    struct zfs_cmd_v15), zc_c);
730	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
731	free(zc_c);
732
733	if (cflag == ZFS_CMD_COMPAT_V15) {
734		switch (nc) {
735		case ZFS_IOC_POOL_IMPORT:
736		case ZFS_IOC_POOL_CONFIGS:
737		case ZFS_IOC_POOL_STATS:
738		case ZFS_IOC_POOL_TRYIMPORT:
739			zfs_ioctl_compat_fix_stats(zc, nc);
740			break;
741		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
742			zfs_ioctl_compat_pool_get_props(zc);
743			break;
744		}
745	}
746
747	return (ret);
748}
749#else /* _KERNEL */
750int
751zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
752{
753	int error = 0;
754
755	/* are we creating a clone? */
756	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
757		*vec = ZFS_IOC_CLONE;
758
759	if (cflag == ZFS_CMD_COMPAT_V15) {
760		switch (*vec) {
761
762		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
763			zc->zc_cookie = POOL_SCAN_SCRUB;
764			break;
765		}
766	}
767
768	return (error);
769}
770
771void
772zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
773{
774	if (cflag == ZFS_CMD_COMPAT_V15) {
775		switch (vec) {
776		case ZFS_IOC_POOL_CONFIGS:
777		case ZFS_IOC_POOL_STATS:
778		case ZFS_IOC_POOL_TRYIMPORT:
779			zfs_ioctl_compat_fix_stats(zc, vec);
780			break;
781		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
782			zfs_ioctl_compat_pool_get_props(zc);
783			break;
784		}
785	}
786}
787
788nvlist_t *
789zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
790    const int cflag)
791{
792	nvlist_t *nvl, *tmpnvl, *hnvl;
793	nvpair_t *elem;
794	char *poolname, *snapname;
795	int err;
796
797	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC)
798		goto out;
799
800	switch (vec) {
801	case ZFS_IOC_CREATE:
802		nvl = fnvlist_alloc();
803		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
804		if (innvl != NULL) {
805			fnvlist_add_nvlist(nvl, "props", innvl);
806			nvlist_free(innvl);
807		}
808		return (nvl);
809	break;
810	case ZFS_IOC_CLONE:
811		nvl = fnvlist_alloc();
812		fnvlist_add_string(nvl, "origin", zc->zc_value);
813		if (innvl != NULL) {
814			fnvlist_add_nvlist(nvl, "props", innvl);
815			nvlist_free(innvl);
816		}
817		return (nvl);
818	break;
819	case ZFS_IOC_SNAPSHOT:
820		if (innvl == NULL)
821			goto out;
822		nvl = fnvlist_alloc();
823		fnvlist_add_nvlist(nvl, "props", innvl);
824		tmpnvl = fnvlist_alloc();
825		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
826		fnvlist_add_boolean(tmpnvl, snapname);
827		kmem_free(snapname, strlen(snapname + 1));
828		/* check if we are doing a recursive snapshot */
829		if (zc->zc_cookie)
830			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
831			    tmpnvl);
832		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
833		fnvlist_free(tmpnvl);
834		nvlist_free(innvl);
835		/* strip dataset part from zc->zc_name */
836		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
837		return (nvl);
838	break;
839	case ZFS_IOC_SPACE_SNAPS:
840		nvl = fnvlist_alloc();
841		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
842		if (innvl != NULL)
843			nvlist_free(innvl);
844		return (nvl);
845	break;
846	case ZFS_IOC_DESTROY_SNAPS:
847		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
848			goto out;
849		nvl = fnvlist_alloc();
850		if (innvl != NULL) {
851			fnvlist_add_nvlist(nvl, "snaps", innvl);
852		} else {
853			/*
854			 * We are probably called by even older binaries,
855			 * allocate and populate nvlist with recursive
856			 * snapshots
857			 */
858			if (zfs_component_namecheck(zc->zc_value, NULL,
859			    NULL) == 0) {
860				tmpnvl = fnvlist_alloc();
861				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
862				    zc->zc_value, tmpnvl) == 0)
863					fnvlist_add_nvlist(nvl, "snaps",
864					    tmpnvl);
865				nvlist_free(tmpnvl);
866			}
867		}
868		if (innvl != NULL)
869			nvlist_free(innvl);
870		/* strip dataset part from zc->zc_name */
871		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
872		return (nvl);
873	break;
874	case ZFS_IOC_HOLD:
875		nvl = fnvlist_alloc();
876		tmpnvl = fnvlist_alloc();
877		if (zc->zc_cleanup_fd != -1)
878			fnvlist_add_int32(nvl, "cleanup_fd",
879			    (int32_t)zc->zc_cleanup_fd);
880		if (zc->zc_cookie) {
881			hnvl = fnvlist_alloc();
882			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
883			    zc->zc_value, hnvl) == 0) {
884				elem = NULL;
885				while ((elem = nvlist_next_nvpair(hnvl,
886				    elem)) != NULL) {
887					nvlist_add_string(tmpnvl,
888					    nvpair_name(elem), zc->zc_string);
889				}
890			}
891			nvlist_free(hnvl);
892		} else {
893			snapname = kmem_asprintf("%s@%s", zc->zc_name,
894			    zc->zc_value);
895			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
896			kmem_free(snapname, strlen(snapname + 1));
897		}
898		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
899		nvlist_free(tmpnvl);
900		if (innvl != NULL)
901			nvlist_free(innvl);
902		/* strip dataset part from zc->zc_name */
903		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
904		return (nvl);
905	break;
906	case ZFS_IOC_RELEASE:
907		nvl = fnvlist_alloc();
908		tmpnvl = fnvlist_alloc();
909		if (zc->zc_cookie) {
910			hnvl = fnvlist_alloc();
911			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
912			    zc->zc_value, hnvl) == 0) {
913				elem = NULL;
914				while ((elem = nvlist_next_nvpair(hnvl,
915				    elem)) != NULL) {
916					fnvlist_add_boolean(tmpnvl,
917					    zc->zc_string);
918					fnvlist_add_nvlist(nvl,
919					    nvpair_name(elem), tmpnvl);
920				}
921			}
922			nvlist_free(hnvl);
923		} else {
924			snapname = kmem_asprintf("%s@%s", zc->zc_name,
925			    zc->zc_value);
926			fnvlist_add_boolean(tmpnvl, zc->zc_string);
927			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
928			kmem_free(snapname, strlen(snapname + 1));
929		}
930		nvlist_free(tmpnvl);
931		if (innvl != NULL)
932			nvlist_free(innvl);
933		/* strip dataset part from zc->zc_name */
934		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
935		return (nvl);
936	break;
937	}
938out:
939	return (innvl);
940}
941
942nvlist_t *
943zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
944    const int cflag)
945{
946	nvlist_t *tmpnvl;
947
948	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC)
949		return (outnvl);
950
951	switch (vec) {
952	case ZFS_IOC_SPACE_SNAPS:
953		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
954		(void) nvlist_lookup_uint64(outnvl, "compressed",
955		    &zc->zc_objset_type);
956		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
957		    &zc->zc_perm_action);
958		nvlist_free(outnvl);
959		/* return empty outnvl */
960		tmpnvl = fnvlist_alloc();
961		return (tmpnvl);
962	break;
963	case ZFS_IOC_CREATE:
964	case ZFS_IOC_CLONE:
965	case ZFS_IOC_HOLD:
966	case ZFS_IOC_RELEASE:
967		nvlist_free(outnvl);
968		/* return empty outnvl */
969		tmpnvl = fnvlist_alloc();
970		return (tmpnvl);
971	break;
972	}
973
974	return (outnvl);
975}
976#endif /* KERNEL */
977