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 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.
29 #include <sys/types.h>
30 #include <sys/param.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 <os/freebsd/zfs/sys/zfs_ioctl_compat.h>
41 * FreeBSD zfs_cmd compatibility with older binaries
42 * appropriately remap/extend the zfs_cmd_t structure
45 zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
51 zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
56 nvlist_t *list = NULL;
59 * Read in and unpack the user-supplied nvlist.
65 packed = kmem_alloc(size, KM_SLEEP);
66 if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
68 kmem_free(packed, size);
72 packed = (void *)(uintptr_t)nvl;
75 error = nvlist_unpack(packed, size, &list, 0);
78 kmem_free(packed, size);
89 zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
95 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
98 packed = kmem_alloc(size, KM_SLEEP);
99 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
102 if (ddi_copyout(packed,
103 (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
105 kmem_free(packed, size);
107 packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
108 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
112 zc->zc_nvlist_dst_size = size;
117 zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
120 nvlist_t *nvroot = NULL;
122 uint_t c, children, nelem;
124 if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
125 &child, &children) == 0) {
126 for (c = 0; c < children; c++) {
127 zfs_ioctl_compat_fix_stats_nvlist(child[c]);
131 if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
133 zfs_ioctl_compat_fix_stats_nvlist(nvroot);
134 if ((nvlist_lookup_uint64_array(nvl, "stats",
135 (uint64_t **)&vs, &nelem) == 0)) {
136 nvlist_add_uint64_array(nvl,
137 ZPOOL_CONFIG_VDEV_STATS,
138 (uint64_t *)vs, nelem);
139 nvlist_remove(nvl, "stats",
140 DATA_TYPE_UINT64_ARRAY);
146 zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
148 nvlist_t *nv, *nvp = NULL;
152 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
153 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
156 if (nc == 5) { /* ZFS_IOC_POOL_STATS */
158 while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
159 if (nvpair_value_nvlist(elem, &nvp) == 0)
160 zfs_ioctl_compat_fix_stats_nvlist(nvp);
164 zfs_ioctl_compat_fix_stats_nvlist(nv);
166 error = zfs_ioctl_compat_put_nvlist(zc, nv);
174 zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
176 nvlist_t *nv, *nva = NULL;
179 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
180 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
183 if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
184 nvlist_add_nvlist(nv, "allocated", nva);
185 nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
188 if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
189 nvlist_add_nvlist(nv, "free", nva);
190 nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
193 error = zfs_ioctl_compat_put_nvlist(zc, nv);
203 zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
207 /* are we creating a clone? */
208 if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
209 *vec = ZFS_IOC_CLONE;
211 if (cflag == ZFS_CMD_COMPAT_V15) {
214 case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
215 zc->zc_cookie = POOL_SCAN_SCRUB;
224 zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
226 if (cflag == ZFS_CMD_COMPAT_V15) {
228 case ZFS_IOC_POOL_CONFIGS:
229 case ZFS_IOC_POOL_STATS:
230 case ZFS_IOC_POOL_TRYIMPORT:
231 zfs_ioctl_compat_fix_stats(zc, vec);
233 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
234 zfs_ioctl_compat_pool_get_props(zc);
241 zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t *innvl, const int vec,
244 nvlist_t *nvl, *tmpnvl, *hnvl;
246 char *poolname, *snapname;
249 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
250 cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
251 cflag == ZFS_CMD_COMPAT_RESUME || cflag == ZFS_CMD_COMPAT_INLANES)
256 nvl = fnvlist_alloc();
257 fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
259 fnvlist_add_nvlist(nvl, "props", innvl);
265 nvl = fnvlist_alloc();
266 fnvlist_add_string(nvl, "origin", zc->zc_value);
268 fnvlist_add_nvlist(nvl, "props", innvl);
273 case ZFS_IOC_SNAPSHOT:
276 nvl = fnvlist_alloc();
277 fnvlist_add_nvlist(nvl, "props", innvl);
278 tmpnvl = fnvlist_alloc();
279 snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
280 fnvlist_add_boolean(tmpnvl, snapname);
281 kmem_free(snapname, strlen(snapname + 1));
282 /* check if we are doing a recursive snapshot */
284 dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
286 fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
287 fnvlist_free(tmpnvl);
289 /* strip dataset part from zc->zc_name */
290 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
293 case ZFS_IOC_SPACE_SNAPS:
294 nvl = fnvlist_alloc();
295 fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
300 case ZFS_IOC_DESTROY_SNAPS:
301 if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
303 nvl = fnvlist_alloc();
305 fnvlist_add_nvlist(nvl, "snaps", innvl);
308 * We are probably called by even older binaries,
309 * allocate and populate nvlist with recursive
312 if (zfs_component_namecheck(zc->zc_value, NULL,
314 tmpnvl = fnvlist_alloc();
315 if (dmu_get_recursive_snaps_nvl(zc->zc_name,
316 zc->zc_value, tmpnvl) == 0)
317 fnvlist_add_nvlist(nvl, "snaps",
324 /* strip dataset part from zc->zc_name */
325 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
329 nvl = fnvlist_alloc();
330 tmpnvl = fnvlist_alloc();
331 if (zc->zc_cleanup_fd != -1)
332 fnvlist_add_int32(nvl, "cleanup_fd",
333 (int32_t)zc->zc_cleanup_fd);
335 hnvl = fnvlist_alloc();
336 if (dmu_get_recursive_snaps_nvl(zc->zc_name,
337 zc->zc_value, hnvl) == 0) {
339 while ((elem = nvlist_next_nvpair(hnvl,
341 nvlist_add_string(tmpnvl,
342 nvpair_name(elem), zc->zc_string);
347 snapname = kmem_asprintf("%s@%s", zc->zc_name,
349 nvlist_add_string(tmpnvl, snapname, zc->zc_string);
350 kmem_free(snapname, strlen(snapname + 1));
352 fnvlist_add_nvlist(nvl, "holds", tmpnvl);
356 /* strip dataset part from zc->zc_name */
357 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
360 case ZFS_IOC_RELEASE:
361 nvl = fnvlist_alloc();
362 tmpnvl = fnvlist_alloc();
364 hnvl = fnvlist_alloc();
365 if (dmu_get_recursive_snaps_nvl(zc->zc_name,
366 zc->zc_value, hnvl) == 0) {
368 while ((elem = nvlist_next_nvpair(hnvl,
370 fnvlist_add_boolean(tmpnvl,
372 fnvlist_add_nvlist(nvl,
373 nvpair_name(elem), tmpnvl);
378 snapname = kmem_asprintf("%s@%s", zc->zc_name,
380 fnvlist_add_boolean(tmpnvl, zc->zc_string);
381 fnvlist_add_nvlist(nvl, snapname, tmpnvl);
382 kmem_free(snapname, strlen(snapname + 1));
387 /* strip dataset part from zc->zc_name */
388 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
397 zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t *outnvl, const int vec,
402 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
403 cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP ||
404 cflag == ZFS_CMD_COMPAT_RESUME || cflag == ZFS_CMD_COMPAT_INLANES)
408 case ZFS_IOC_SPACE_SNAPS:
409 (void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
410 (void) nvlist_lookup_uint64(outnvl, "compressed",
411 &zc->zc_objset_type);
412 (void) nvlist_lookup_uint64(outnvl, "uncompressed",
413 &zc->zc_perm_action);
415 /* return empty outnvl */
416 tmpnvl = fnvlist_alloc();
422 case ZFS_IOC_RELEASE:
424 /* return empty outnvl */
425 tmpnvl = fnvlist_alloc();