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