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.
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.
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]
22 * Copyright 2010 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.
28 #include <sys/types.h>
29 #include <sys/param.h>
33 #include <sys/nvpair.h>
34 #include <sys/dsl_deleg.h>
35 #include <sys/zfs_ioctl.h>
36 #include "zfs_ioctl_compat.h"
39 * FreeBSD zfs_cmd compatibility with v15 and older binaries
40 * appropriately remap/extend the zfs_cmd_t structure
43 zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
47 if (cflag == ZFS_CMD_COMPAT_V15) {
51 strlcpy(zc->zc_name,zc_c->zc_name,MAXPATHLEN);
52 strlcpy(zc->zc_value,zc_c->zc_value,MAXPATHLEN);
53 strlcpy(zc->zc_string,zc_c->zc_string,MAXPATHLEN);
54 zc->zc_guid = zc_c->zc_guid;
55 zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
56 zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
57 zc->zc_nvlist_src = zc_c->zc_nvlist_src;
58 zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
59 zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
60 zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
61 zc->zc_cookie = zc_c->zc_cookie;
62 zc->zc_objset_type = zc_c->zc_objset_type;
63 zc->zc_perm_action = zc_c->zc_perm_action;
64 zc->zc_history = zc_c->zc_history;
65 zc->zc_history_len = zc_c->zc_history_len;
66 zc->zc_history_offset = zc_c->zc_history_offset;
67 zc->zc_obj = zc_c->zc_obj;
68 zc->zc_share = zc_c->zc_share;
69 zc->zc_jailid = zc_c->zc_jailid;
70 zc->zc_objset_stats = zc_c->zc_objset_stats;
71 zc->zc_begin_record = zc_c->zc_begin_record;
73 /* zc->zc_inject_record */
74 zc->zc_inject_record.zi_objset =
75 zc_c->zc_inject_record.zi_objset;
76 zc->zc_inject_record.zi_object =
77 zc_c->zc_inject_record.zi_object;
78 zc->zc_inject_record.zi_start =
79 zc_c->zc_inject_record.zi_start;
80 zc->zc_inject_record.zi_end =
81 zc_c->zc_inject_record.zi_end;
82 zc->zc_inject_record.zi_guid =
83 zc_c->zc_inject_record.zi_guid;
84 zc->zc_inject_record.zi_level =
85 zc_c->zc_inject_record.zi_level;
86 zc->zc_inject_record.zi_error =
87 zc_c->zc_inject_record.zi_error;
88 zc->zc_inject_record.zi_type =
89 zc_c->zc_inject_record.zi_type;
90 zc->zc_inject_record.zi_freq =
91 zc_c->zc_inject_record.zi_freq;
92 zc->zc_inject_record.zi_failfast =
93 zc_c->zc_inject_record.zi_failfast;
98 zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int cflag)
103 case ZFS_CMD_COMPAT_V15:
107 strlcpy(zc_c->zc_name,zc->zc_name,MAXPATHLEN);
108 strlcpy(zc_c->zc_value,zc->zc_value,MAXPATHLEN);
109 strlcpy(zc_c->zc_string,zc->zc_string,MAXPATHLEN);
110 zc_c->zc_guid = zc->zc_guid;
111 zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
112 zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
113 zc_c->zc_nvlist_src = zc->zc_nvlist_src;
114 zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
115 zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
116 zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
117 zc_c->zc_cookie = zc->zc_cookie;
118 zc_c->zc_objset_type = zc->zc_objset_type;
119 zc_c->zc_perm_action = zc->zc_perm_action;
120 zc_c->zc_history = zc->zc_history;
121 zc_c->zc_history_len = zc->zc_history_len;
122 zc_c->zc_history_offset = zc->zc_history_offset;
123 zc_c->zc_obj = zc->zc_obj;
124 zc_c->zc_share = zc->zc_share;
125 zc_c->zc_jailid = zc->zc_jailid;
126 zc_c->zc_objset_stats = zc->zc_objset_stats;
127 zc_c->zc_begin_record = zc->zc_begin_record;
129 /* zc_inject_record */
130 zc_c->zc_inject_record.zi_objset =
131 zc->zc_inject_record.zi_objset;
132 zc_c->zc_inject_record.zi_object =
133 zc->zc_inject_record.zi_object;
134 zc_c->zc_inject_record.zi_start =
135 zc->zc_inject_record.zi_start;
136 zc_c->zc_inject_record.zi_end =
137 zc->zc_inject_record.zi_end;
138 zc_c->zc_inject_record.zi_guid =
139 zc->zc_inject_record.zi_guid;
140 zc_c->zc_inject_record.zi_level =
141 zc->zc_inject_record.zi_level;
142 zc_c->zc_inject_record.zi_error =
143 zc->zc_inject_record.zi_error;
144 zc_c->zc_inject_record.zi_type =
145 zc->zc_inject_record.zi_type;
146 zc_c->zc_inject_record.zi_freq =
147 zc->zc_inject_record.zi_freq;
148 zc_c->zc_inject_record.zi_failfast =
149 zc->zc_inject_record.zi_failfast;
156 zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
161 nvlist_t *list = NULL;
164 * Read in and unpack the user-supplied nvlist.
170 packed = kmem_alloc(size, KM_SLEEP);
171 if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
173 kmem_free(packed, size);
177 packed = (void *)(uintptr_t)nvl;
180 error = nvlist_unpack(packed, size, &list, 0);
183 kmem_free(packed, size);
194 zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
200 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
203 packed = kmem_alloc(size, KM_SLEEP);
204 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
207 if (ddi_copyout(packed,
208 (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
210 kmem_free(packed, size);
212 packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
213 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
217 zc->zc_nvlist_dst_size = size;
222 zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
225 nvlist_t *nvroot = NULL;
227 uint_t c, children, nelem;
229 if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
230 &child, &children) == 0) {
231 for (c = 0; c < children; c++) {
232 zfs_ioctl_compat_fix_stats_nvlist(child[c]);
236 if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
238 zfs_ioctl_compat_fix_stats_nvlist(nvroot);
240 if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
242 if ((nvlist_lookup_uint64_array(nvl, "stats",
245 (uint64_t **)&vs, &nelem) == 0)) {
246 nvlist_add_uint64_array(nvl,
250 ZPOOL_CONFIG_VDEV_STATS,
252 (uint64_t *)vs, nelem);
254 nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
256 nvlist_remove(nvl, "stats",
258 DATA_TYPE_UINT64_ARRAY);
263 zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int cflag)
265 nvlist_t *nv, *nvp = NULL;
269 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
270 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
273 if (cflag == 5) { /* ZFS_IOC_POOL_STATS */
275 while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
276 if (nvpair_value_nvlist(elem, &nvp) == 0)
277 zfs_ioctl_compat_fix_stats_nvlist(nvp);
281 zfs_ioctl_compat_fix_stats_nvlist(nv);
283 error = zfs_ioctl_compat_put_nvlist(zc, nv);
291 zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
293 nvlist_t *nv, *nva = NULL;
296 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
297 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
301 if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
302 nvlist_add_nvlist(nv, "used", nva);
303 nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
306 if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
307 nvlist_add_nvlist(nv, "available", nva);
308 nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
311 if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
312 nvlist_add_nvlist(nv, "allocated", nva);
313 nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
316 if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
317 nvlist_add_nvlist(nv, "free", nva);
318 nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
322 error = zfs_ioctl_compat_put_nvlist(zc, nv);
331 zcmd_ioctl_compat(int fd, unsigned long cmd, zfs_cmd_t *zc, const int cflag)
337 if (cflag == ZFS_CMD_COMPAT_NONE) {
338 ret = ioctl(fd, cmd, zc);
342 if (cflag == ZFS_CMD_COMPAT_V15) {
343 nc = zfs_ioctl_v28_to_v15[ZFS_IOC(cmd)];
344 zc_c = malloc(sizeof(zfs_cmd_v15_t));
345 ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
349 if (ZFS_IOC(ncmd) == ZFS_IOC_COMPAT_FAIL)
352 zfs_cmd_compat_put(zc, (caddr_t)zc_c, cflag);
353 ret = ioctl(fd, ncmd, zc_c);
354 if (cflag == ZFS_CMD_COMPAT_V15 &&
355 nc == 2 /* ZFS_IOC_POOL_IMPORT */)
356 ret = ioctl(fd, _IOWR('Z', 4 /* ZFS_IOC_POOL_CONFIGS */,
357 struct zfs_cmd_v15), zc_c);
358 zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
362 case 2: /* ZFS_IOC_POOL_IMPORT */
363 case 4: /* ZFS_IOC_POOL_CONFIGS */
364 case 5: /* ZFS_IOC_POOL_STATS */
365 case 6: /* ZFS_IOC_POOL_TRYIMPORT */
366 zfs_ioctl_compat_fix_stats(zc, nc);
368 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
369 zfs_ioctl_compat_pool_get_props(zc);
377 zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
379 if (cflag == ZFS_CMD_COMPAT_V15)
382 case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
383 zc->zc_cookie = POOL_SCAN_SCRUB;
389 zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
391 if (cflag == ZFS_CMD_COMPAT_V15) {
393 case 4: /* ZFS_IOC_POOL_CONFIGS */
394 case 5: /* ZFS_IOC_POOL_STATS */
395 case 6: /* ZFS_IOC_POOL_TRYIMPORT */
396 zfs_ioctl_compat_fix_stats(zc, vec);
398 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
399 zfs_ioctl_compat_pool_get_props(zc);