]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/cddl/contrib/opensolaris/common/zfs/zfs_ioctl_compat.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / cddl / contrib / opensolaris / common / zfs / zfs_ioctl_compat.c
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
39 static int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
40 SYSCTL_DECL(_vfs_zfs_version);
41 SYSCTL_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  */
48 void
49 zfs_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
220 void
221 zfs_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
399 static int
400 zfs_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
437 static int
438 zfs_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
465 static void
466 zfs_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
506 static int
507 zfs_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
534 static int
535 zfs_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
574 int
575 zcmd_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 */
639 int
640 zfs_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
660 void
661 zfs_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
677 nvlist_t *
678 zfs_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 (snapshot_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         }
827 out:
828         return (innvl);
829 }
830
831 nvlist_t *
832 zfs_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 */