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