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