zfs_ioctl_compat.c revision 263407
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 23 * Portions Copyright 2005, 2010, Oracle and/or its affiliates. 24 * All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28#include <sys/types.h> 29#include <sys/param.h> 30#include <sys/cred.h> 31#include <sys/dmu.h> 32#include <sys/zio.h> 33#include <sys/nvpair.h> 34#include <sys/dsl_deleg.h> 35#include <sys/zfs_ioctl.h> 36#include "zfs_namecheck.h" 37#include "zfs_ioctl_compat.h" 38 39static int zfs_version_ioctl = ZFS_IOCVER_CURRENT; 40SYSCTL_DECL(_vfs_zfs_version); 41SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl, 42 0, "ZFS_IOCTL_VERSION"); 43 44/* 45 * FreeBSD zfs_cmd compatibility with older binaries 46 * appropriately remap/extend the zfs_cmd_t structure 47 */ 48void 49zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) 50{ 51 zfs_cmd_v15_t *zc_c; 52 zfs_cmd_v28_t *zc28_c; 53 zfs_cmd_deadman_t *zcdm_c; 54 55 switch (cflag) { 56 case ZFS_CMD_COMPAT_DEADMAN: 57 zcdm_c = (void *)addr; 58 /* zc */ 59 strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN); 60 strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2); 61 strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN); 62 zc->zc_guid = zcdm_c->zc_guid; 63 zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf; 64 zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size; 65 zc->zc_nvlist_src = zcdm_c->zc_nvlist_src; 66 zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size; 67 zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst; 68 zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size; 69 zc->zc_cookie = zcdm_c->zc_cookie; 70 zc->zc_objset_type = zcdm_c->zc_objset_type; 71 zc->zc_perm_action = zcdm_c->zc_perm_action; 72 zc->zc_history = zcdm_c->zc_history; 73 zc->zc_history_len = zcdm_c->zc_history_len; 74 zc->zc_history_offset = zcdm_c->zc_history_offset; 75 zc->zc_obj = zcdm_c->zc_obj; 76 zc->zc_iflags = zcdm_c->zc_iflags; 77 zc->zc_share = zcdm_c->zc_share; 78 zc->zc_jailid = zcdm_c->zc_jailid; 79 zc->zc_objset_stats = zcdm_c->zc_objset_stats; 80 zc->zc_begin_record = zcdm_c->zc_begin_record; 81 zc->zc_defer_destroy = zcdm_c->zc_defer_destroy; 82 zc->zc_temphold = zcdm_c->zc_temphold; 83 zc->zc_action_handle = zcdm_c->zc_action_handle; 84 zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd; 85 zc->zc_simple = zcdm_c->zc_simple; 86 bcopy(zcdm_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); 87 zc->zc_sendobj = zcdm_c->zc_sendobj; 88 zc->zc_fromobj = zcdm_c->zc_fromobj; 89 zc->zc_createtxg = zcdm_c->zc_createtxg; 90 zc->zc_stat = zcdm_c->zc_stat; 91 92 /* zc_inject_record doesn't change in libzfs_core */ 93 zcdm_c->zc_inject_record = zc->zc_inject_record; 94 95 /* we always assume zc_nvlist_dst_filled is true */ 96 zc->zc_nvlist_dst_filled = B_TRUE; 97 break; 98 99 case ZFS_CMD_COMPAT_V28: 100 zc28_c = (void *)addr; 101 102 /* zc */ 103 strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN); 104 strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2); 105 strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN); 106 zc->zc_guid = zc28_c->zc_guid; 107 zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf; 108 zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size; 109 zc->zc_nvlist_src = zc28_c->zc_nvlist_src; 110 zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size; 111 zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst; 112 zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size; 113 zc->zc_cookie = zc28_c->zc_cookie; 114 zc->zc_objset_type = zc28_c->zc_objset_type; 115 zc->zc_perm_action = zc28_c->zc_perm_action; 116 zc->zc_history = zc28_c->zc_history; 117 zc->zc_history_len = zc28_c->zc_history_len; 118 zc->zc_history_offset = zc28_c->zc_history_offset; 119 zc->zc_obj = zc28_c->zc_obj; 120 zc->zc_iflags = zc28_c->zc_iflags; 121 zc->zc_share = zc28_c->zc_share; 122 zc->zc_jailid = zc28_c->zc_jailid; 123 zc->zc_objset_stats = zc28_c->zc_objset_stats; 124 zc->zc_begin_record = zc28_c->zc_begin_record; 125 zc->zc_defer_destroy = zc28_c->zc_defer_destroy; 126 zc->zc_temphold = zc28_c->zc_temphold; 127 zc->zc_action_handle = zc28_c->zc_action_handle; 128 zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd; 129 zc->zc_simple = zc28_c->zc_simple; 130 bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); 131 zc->zc_sendobj = zc28_c->zc_sendobj; 132 zc->zc_fromobj = zc28_c->zc_fromobj; 133 zc->zc_createtxg = zc28_c->zc_createtxg; 134 zc->zc_stat = zc28_c->zc_stat; 135 136 /* zc->zc_inject_record */ 137 zc->zc_inject_record.zi_objset = 138 zc28_c->zc_inject_record.zi_objset; 139 zc->zc_inject_record.zi_object = 140 zc28_c->zc_inject_record.zi_object; 141 zc->zc_inject_record.zi_start = 142 zc28_c->zc_inject_record.zi_start; 143 zc->zc_inject_record.zi_end = 144 zc28_c->zc_inject_record.zi_end; 145 zc->zc_inject_record.zi_guid = 146 zc28_c->zc_inject_record.zi_guid; 147 zc->zc_inject_record.zi_level = 148 zc28_c->zc_inject_record.zi_level; 149 zc->zc_inject_record.zi_error = 150 zc28_c->zc_inject_record.zi_error; 151 zc->zc_inject_record.zi_type = 152 zc28_c->zc_inject_record.zi_type; 153 zc->zc_inject_record.zi_freq = 154 zc28_c->zc_inject_record.zi_freq; 155 zc->zc_inject_record.zi_failfast = 156 zc28_c->zc_inject_record.zi_failfast; 157 strlcpy(zc->zc_inject_record.zi_func, 158 zc28_c->zc_inject_record.zi_func, MAXNAMELEN); 159 zc->zc_inject_record.zi_iotype = 160 zc28_c->zc_inject_record.zi_iotype; 161 zc->zc_inject_record.zi_duration = 162 zc28_c->zc_inject_record.zi_duration; 163 zc->zc_inject_record.zi_timer = 164 zc28_c->zc_inject_record.zi_timer; 165 zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED; 166 zc->zc_inject_record.zi_pad = 0; 167 break; 168 169 case ZFS_CMD_COMPAT_V15: 170 zc_c = (void *)addr; 171 172 /* zc */ 173 strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN); 174 strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN); 175 strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN); 176 zc->zc_guid = zc_c->zc_guid; 177 zc->zc_nvlist_conf = zc_c->zc_nvlist_conf; 178 zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size; 179 zc->zc_nvlist_src = zc_c->zc_nvlist_src; 180 zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size; 181 zc->zc_nvlist_dst = zc_c->zc_nvlist_dst; 182 zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size; 183 zc->zc_cookie = zc_c->zc_cookie; 184 zc->zc_objset_type = zc_c->zc_objset_type; 185 zc->zc_perm_action = zc_c->zc_perm_action; 186 zc->zc_history = zc_c->zc_history; 187 zc->zc_history_len = zc_c->zc_history_len; 188 zc->zc_history_offset = zc_c->zc_history_offset; 189 zc->zc_obj = zc_c->zc_obj; 190 zc->zc_share = zc_c->zc_share; 191 zc->zc_jailid = zc_c->zc_jailid; 192 zc->zc_objset_stats = zc_c->zc_objset_stats; 193 zc->zc_begin_record = zc_c->zc_begin_record; 194 195 /* zc->zc_inject_record */ 196 zc->zc_inject_record.zi_objset = 197 zc_c->zc_inject_record.zi_objset; 198 zc->zc_inject_record.zi_object = 199 zc_c->zc_inject_record.zi_object; 200 zc->zc_inject_record.zi_start = 201 zc_c->zc_inject_record.zi_start; 202 zc->zc_inject_record.zi_end = 203 zc_c->zc_inject_record.zi_end; 204 zc->zc_inject_record.zi_guid = 205 zc_c->zc_inject_record.zi_guid; 206 zc->zc_inject_record.zi_level = 207 zc_c->zc_inject_record.zi_level; 208 zc->zc_inject_record.zi_error = 209 zc_c->zc_inject_record.zi_error; 210 zc->zc_inject_record.zi_type = 211 zc_c->zc_inject_record.zi_type; 212 zc->zc_inject_record.zi_freq = 213 zc_c->zc_inject_record.zi_freq; 214 zc->zc_inject_record.zi_failfast = 215 zc_c->zc_inject_record.zi_failfast; 216 break; 217 } 218} 219 220void 221zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request, 222 const int cflag) 223{ 224 zfs_cmd_v15_t *zc_c; 225 zfs_cmd_v28_t *zc28_c; 226 zfs_cmd_deadman_t *zcdm_c; 227 228 switch (cflag) { 229 case ZFS_CMD_COMPAT_DEADMAN: 230 zcdm_c = (void *)addr; 231 232 strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN); 233 strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2); 234 strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN); 235 zcdm_c->zc_guid = zc->zc_guid; 236 zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf; 237 zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 238 zcdm_c->zc_nvlist_src = zc->zc_nvlist_src; 239 zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 240 zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst; 241 zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 242 zcdm_c->zc_cookie = zc->zc_cookie; 243 zcdm_c->zc_objset_type = zc->zc_objset_type; 244 zcdm_c->zc_perm_action = zc->zc_perm_action; 245 zcdm_c->zc_history = zc->zc_history; 246 zcdm_c->zc_history_len = zc->zc_history_len; 247 zcdm_c->zc_history_offset = zc->zc_history_offset; 248 zcdm_c->zc_obj = zc->zc_obj; 249 zcdm_c->zc_iflags = zc->zc_iflags; 250 zcdm_c->zc_share = zc->zc_share; 251 zcdm_c->zc_jailid = zc->zc_jailid; 252 zcdm_c->zc_objset_stats = zc->zc_objset_stats; 253 zcdm_c->zc_begin_record = zc->zc_begin_record; 254 zcdm_c->zc_defer_destroy = zc->zc_defer_destroy; 255 zcdm_c->zc_temphold = zc->zc_temphold; 256 zcdm_c->zc_action_handle = zc->zc_action_handle; 257 zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd; 258 zcdm_c->zc_simple = zc->zc_simple; 259 bcopy(zc->zc_pad, zcdm_c->zc_pad, sizeof(zcdm_c->zc_pad)); 260 zcdm_c->zc_sendobj = zc->zc_sendobj; 261 zcdm_c->zc_fromobj = zc->zc_fromobj; 262 zcdm_c->zc_createtxg = zc->zc_createtxg; 263 zcdm_c->zc_stat = zc->zc_stat; 264 265 /* zc_inject_record doesn't change in libzfs_core */ 266 zc->zc_inject_record = zcdm_c->zc_inject_record; 267#ifndef _KERNEL 268 if (request == ZFS_IOC_RECV) 269 strlcpy(zcdm_c->zc_top_ds, 270 zc->zc_value + strlen(zc->zc_value) + 1, 271 (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1); 272#endif 273 break; 274 275 case ZFS_CMD_COMPAT_V28: 276 zc28_c = (void *)addr; 277 278 strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN); 279 strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2); 280 strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN); 281 zc28_c->zc_guid = zc->zc_guid; 282 zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf; 283 zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 284 zc28_c->zc_nvlist_src = zc->zc_nvlist_src; 285 zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 286 zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst; 287 zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 288 zc28_c->zc_cookie = zc->zc_cookie; 289 zc28_c->zc_objset_type = zc->zc_objset_type; 290 zc28_c->zc_perm_action = zc->zc_perm_action; 291 zc28_c->zc_history = zc->zc_history; 292 zc28_c->zc_history_len = zc->zc_history_len; 293 zc28_c->zc_history_offset = zc->zc_history_offset; 294 zc28_c->zc_obj = zc->zc_obj; 295 zc28_c->zc_iflags = zc->zc_iflags; 296 zc28_c->zc_share = zc->zc_share; 297 zc28_c->zc_jailid = zc->zc_jailid; 298 zc28_c->zc_objset_stats = zc->zc_objset_stats; 299 zc28_c->zc_begin_record = zc->zc_begin_record; 300 zc28_c->zc_defer_destroy = zc->zc_defer_destroy; 301 zc28_c->zc_temphold = zc->zc_temphold; 302 zc28_c->zc_action_handle = zc->zc_action_handle; 303 zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd; 304 zc28_c->zc_simple = zc->zc_simple; 305 bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad)); 306 zc28_c->zc_sendobj = zc->zc_sendobj; 307 zc28_c->zc_fromobj = zc->zc_fromobj; 308 zc28_c->zc_createtxg = zc->zc_createtxg; 309 zc28_c->zc_stat = zc->zc_stat; 310#ifndef _KERNEL 311 if (request == ZFS_IOC_RECV) 312 strlcpy(zc28_c->zc_top_ds, 313 zc->zc_value + strlen(zc->zc_value) + 1, 314 MAXPATHLEN * 2 - strlen(zc->zc_value) - 1); 315#endif 316 /* zc_inject_record */ 317 zc28_c->zc_inject_record.zi_objset = 318 zc->zc_inject_record.zi_objset; 319 zc28_c->zc_inject_record.zi_object = 320 zc->zc_inject_record.zi_object; 321 zc28_c->zc_inject_record.zi_start = 322 zc->zc_inject_record.zi_start; 323 zc28_c->zc_inject_record.zi_end = 324 zc->zc_inject_record.zi_end; 325 zc28_c->zc_inject_record.zi_guid = 326 zc->zc_inject_record.zi_guid; 327 zc28_c->zc_inject_record.zi_level = 328 zc->zc_inject_record.zi_level; 329 zc28_c->zc_inject_record.zi_error = 330 zc->zc_inject_record.zi_error; 331 zc28_c->zc_inject_record.zi_type = 332 zc->zc_inject_record.zi_type; 333 zc28_c->zc_inject_record.zi_freq = 334 zc->zc_inject_record.zi_freq; 335 zc28_c->zc_inject_record.zi_failfast = 336 zc->zc_inject_record.zi_failfast; 337 strlcpy(zc28_c->zc_inject_record.zi_func, 338 zc->zc_inject_record.zi_func, MAXNAMELEN); 339 zc28_c->zc_inject_record.zi_iotype = 340 zc->zc_inject_record.zi_iotype; 341 zc28_c->zc_inject_record.zi_duration = 342 zc->zc_inject_record.zi_duration; 343 zc28_c->zc_inject_record.zi_timer = 344 zc->zc_inject_record.zi_timer; 345 break; 346 347 case ZFS_CMD_COMPAT_V15: 348 zc_c = (void *)addr; 349 350 /* zc */ 351 strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN); 352 strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN); 353 strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN); 354 zc_c->zc_guid = zc->zc_guid; 355 zc_c->zc_nvlist_conf = zc->zc_nvlist_conf; 356 zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 357 zc_c->zc_nvlist_src = zc->zc_nvlist_src; 358 zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 359 zc_c->zc_nvlist_dst = zc->zc_nvlist_dst; 360 zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 361 zc_c->zc_cookie = zc->zc_cookie; 362 zc_c->zc_objset_type = zc->zc_objset_type; 363 zc_c->zc_perm_action = zc->zc_perm_action; 364 zc_c->zc_history = zc->zc_history; 365 zc_c->zc_history_len = zc->zc_history_len; 366 zc_c->zc_history_offset = zc->zc_history_offset; 367 zc_c->zc_obj = zc->zc_obj; 368 zc_c->zc_share = zc->zc_share; 369 zc_c->zc_jailid = zc->zc_jailid; 370 zc_c->zc_objset_stats = zc->zc_objset_stats; 371 zc_c->zc_begin_record = zc->zc_begin_record; 372 373 /* zc_inject_record */ 374 zc_c->zc_inject_record.zi_objset = 375 zc->zc_inject_record.zi_objset; 376 zc_c->zc_inject_record.zi_object = 377 zc->zc_inject_record.zi_object; 378 zc_c->zc_inject_record.zi_start = 379 zc->zc_inject_record.zi_start; 380 zc_c->zc_inject_record.zi_end = 381 zc->zc_inject_record.zi_end; 382 zc_c->zc_inject_record.zi_guid = 383 zc->zc_inject_record.zi_guid; 384 zc_c->zc_inject_record.zi_level = 385 zc->zc_inject_record.zi_level; 386 zc_c->zc_inject_record.zi_error = 387 zc->zc_inject_record.zi_error; 388 zc_c->zc_inject_record.zi_type = 389 zc->zc_inject_record.zi_type; 390 zc_c->zc_inject_record.zi_freq = 391 zc->zc_inject_record.zi_freq; 392 zc_c->zc_inject_record.zi_failfast = 393 zc->zc_inject_record.zi_failfast; 394 395 break; 396 } 397} 398 399static int 400zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag, 401 nvlist_t **nvp) 402{ 403 char *packed; 404 int error; 405 nvlist_t *list = NULL; 406 407 /* 408 * Read in and unpack the user-supplied nvlist. 409 */ 410 if (size == 0) 411 return (EINVAL); 412 413#ifdef _KERNEL 414 packed = kmem_alloc(size, KM_SLEEP); 415 if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 416 iflag)) != 0) { 417 kmem_free(packed, size); 418 return (error); 419 } 420#else 421 packed = (void *)(uintptr_t)nvl; 422#endif 423 424 error = nvlist_unpack(packed, size, &list, 0); 425 426#ifdef _KERNEL 427 kmem_free(packed, size); 428#endif 429 430 if (error != 0) 431 return (error); 432 433 *nvp = list; 434 return (0); 435} 436 437static int 438zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 439{ 440 char *packed = NULL; 441 int error = 0; 442 size_t size; 443 444 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 445 446#ifdef _KERNEL 447 packed = kmem_alloc(size, KM_SLEEP); 448 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 449 KM_SLEEP) == 0); 450 451 if (ddi_copyout(packed, 452 (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0) 453 error = EFAULT; 454 kmem_free(packed, size); 455#else 456 packed = (void *)(uintptr_t)zc->zc_nvlist_dst; 457 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 458 0) == 0); 459#endif 460 461 zc->zc_nvlist_dst_size = size; 462 return (error); 463} 464 465static void 466zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl) 467{ 468 nvlist_t **child; 469 nvlist_t *nvroot = NULL; 470 vdev_stat_t *vs; 471 uint_t c, children, nelem; 472 473 if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, 474 &child, &children) == 0) { 475 for (c = 0; c < children; c++) { 476 zfs_ioctl_compat_fix_stats_nvlist(child[c]); 477 } 478 } 479 480 if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE, 481 &nvroot) == 0) 482 zfs_ioctl_compat_fix_stats_nvlist(nvroot); 483#ifdef _KERNEL 484 if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS, 485#else 486 if ((nvlist_lookup_uint64_array(nvl, "stats", 487#endif 488 489 (uint64_t **)&vs, &nelem) == 0)) { 490 nvlist_add_uint64_array(nvl, 491#ifdef _KERNEL 492 "stats", 493#else 494 ZPOOL_CONFIG_VDEV_STATS, 495#endif 496 (uint64_t *)vs, nelem); 497#ifdef _KERNEL 498 nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS, 499#else 500 nvlist_remove(nvl, "stats", 501#endif 502 DATA_TYPE_UINT64_ARRAY); 503 } 504} 505 506static int 507zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc) 508{ 509 nvlist_t *nv, *nvp = NULL; 510 nvpair_t *elem; 511 int error; 512 513 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst, 514 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) 515 return (error); 516 517 if (nc == 5) { /* ZFS_IOC_POOL_STATS */ 518 elem = NULL; 519 while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) { 520 if (nvpair_value_nvlist(elem, &nvp) == 0) 521 zfs_ioctl_compat_fix_stats_nvlist(nvp); 522 } 523 elem = NULL; 524 } else 525 zfs_ioctl_compat_fix_stats_nvlist(nv); 526 527 error = zfs_ioctl_compat_put_nvlist(zc, nv); 528 529 nvlist_free(nv); 530 531 return (error); 532} 533 534static int 535zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc) 536{ 537 nvlist_t *nv, *nva = NULL; 538 int error; 539 540 if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst, 541 zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) 542 return (error); 543 544#ifdef _KERNEL 545 if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) { 546 nvlist_add_nvlist(nv, "used", nva); 547 nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST); 548 } 549 550 if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) { 551 nvlist_add_nvlist(nv, "available", nva); 552 nvlist_remove(nv, "free", DATA_TYPE_NVLIST); 553 } 554#else 555 if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) { 556 nvlist_add_nvlist(nv, "allocated", nva); 557 nvlist_remove(nv, "used", DATA_TYPE_NVLIST); 558 } 559 560 if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) { 561 nvlist_add_nvlist(nv, "free", nva); 562 nvlist_remove(nv, "available", DATA_TYPE_NVLIST); 563 } 564#endif 565 566 error = zfs_ioctl_compat_put_nvlist(zc, nv); 567 568 nvlist_free(nv); 569 570 return (error); 571} 572 573#ifndef _KERNEL 574int 575zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) 576{ 577 int nc, ret; 578 void *zc_c; 579 unsigned long ncmd; 580 zfs_iocparm_t zp; 581 582 switch (cflag) { 583 case ZFS_CMD_COMPAT_NONE: 584 ncmd = _IOWR('Z', request, struct zfs_iocparm); 585 zp.zfs_cmd = (uint64_t)zc; 586 zp.zfs_cmd_size = sizeof(zfs_cmd_t); 587 zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT; 588 return (ioctl(fd, ncmd, &zp)); 589 case ZFS_CMD_COMPAT_LZC: 590 ncmd = _IOWR('Z', request, struct zfs_cmd); 591 return (ioctl(fd, ncmd, zc)); 592 case ZFS_CMD_COMPAT_DEADMAN: 593 zc_c = malloc(sizeof(zfs_cmd_deadman_t)); 594 ncmd = _IOWR('Z', request, struct zfs_cmd_deadman); 595 break; 596 case ZFS_CMD_COMPAT_V28: 597 zc_c = malloc(sizeof(zfs_cmd_v28_t)); 598 ncmd = _IOWR('Z', request, struct zfs_cmd_v28); 599 break; 600 case ZFS_CMD_COMPAT_V15: 601 nc = zfs_ioctl_v28_to_v15[request]; 602 zc_c = malloc(sizeof(zfs_cmd_v15_t)); 603 ncmd = _IOWR('Z', nc, struct zfs_cmd_v15); 604 break; 605 default: 606 return (EINVAL); 607 } 608 609 if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL) 610 return (ENOTSUP); 611 612 zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag); 613 614 ret = ioctl(fd, ncmd, zc_c); 615 if (cflag == ZFS_CMD_COMPAT_V15 && 616 nc == ZFS_IOC_POOL_IMPORT) 617 ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS, 618 struct zfs_cmd_v15), zc_c); 619 zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag); 620 free(zc_c); 621 622 if (cflag == ZFS_CMD_COMPAT_V15) { 623 switch (nc) { 624 case ZFS_IOC_POOL_IMPORT: 625 case ZFS_IOC_POOL_CONFIGS: 626 case ZFS_IOC_POOL_STATS: 627 case ZFS_IOC_POOL_TRYIMPORT: 628 zfs_ioctl_compat_fix_stats(zc, nc); 629 break; 630 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 631 zfs_ioctl_compat_pool_get_props(zc); 632 break; 633 } 634 } 635 636 return (ret); 637} 638#else /* _KERNEL */ 639int 640zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag) 641{ 642 int error = 0; 643 644 /* are we creating a clone? */ 645 if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0') 646 *vec = ZFS_IOC_CLONE; 647 648 if (cflag == ZFS_CMD_COMPAT_V15) { 649 switch (*vec) { 650 651 case 7: /* ZFS_IOC_POOL_SCRUB (v15) */ 652 zc->zc_cookie = POOL_SCAN_SCRUB; 653 break; 654 } 655 } 656 657 return (error); 658} 659 660void 661zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag) 662{ 663 if (cflag == ZFS_CMD_COMPAT_V15) { 664 switch (vec) { 665 case ZFS_IOC_POOL_CONFIGS: 666 case ZFS_IOC_POOL_STATS: 667 case ZFS_IOC_POOL_TRYIMPORT: 668 zfs_ioctl_compat_fix_stats(zc, vec); 669 break; 670 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 671 zfs_ioctl_compat_pool_get_props(zc); 672 break; 673 } 674 } 675} 676 677nvlist_t * 678zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec, 679 const int cflag) 680{ 681 nvlist_t *nvl, *tmpnvl, *hnvl; 682 nvpair_t *elem; 683 char *poolname, *snapname; 684 int err; 685 686 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 687 goto out; 688 689 switch (vec) { 690 case ZFS_IOC_CREATE: 691 nvl = fnvlist_alloc(); 692 fnvlist_add_int32(nvl, "type", zc->zc_objset_type); 693 if (innvl != NULL) { 694 fnvlist_add_nvlist(nvl, "props", innvl); 695 nvlist_free(innvl); 696 } 697 return (nvl); 698 break; 699 case ZFS_IOC_CLONE: 700 nvl = fnvlist_alloc(); 701 fnvlist_add_string(nvl, "origin", zc->zc_value); 702 if (innvl != NULL) { 703 fnvlist_add_nvlist(nvl, "props", innvl); 704 nvlist_free(innvl); 705 } 706 return (nvl); 707 break; 708 case ZFS_IOC_SNAPSHOT: 709 if (innvl == NULL) 710 goto out; 711 nvl = fnvlist_alloc(); 712 fnvlist_add_nvlist(nvl, "props", innvl); 713 tmpnvl = fnvlist_alloc(); 714 snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value); 715 fnvlist_add_boolean(tmpnvl, snapname); 716 kmem_free(snapname, strlen(snapname + 1)); 717 /* check if we are doing a recursive snapshot */ 718 if (zc->zc_cookie) 719 dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value, 720 tmpnvl); 721 fnvlist_add_nvlist(nvl, "snaps", tmpnvl); 722 fnvlist_free(tmpnvl); 723 nvlist_free(innvl); 724 /* strip dataset part from zc->zc_name */ 725 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 726 return (nvl); 727 break; 728 case ZFS_IOC_SPACE_SNAPS: 729 nvl = fnvlist_alloc(); 730 fnvlist_add_string(nvl, "firstsnap", zc->zc_value); 731 if (innvl != NULL) 732 nvlist_free(innvl); 733 return (nvl); 734 break; 735 case ZFS_IOC_DESTROY_SNAPS: 736 if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN) 737 goto out; 738 nvl = fnvlist_alloc(); 739 if (innvl != NULL) { 740 fnvlist_add_nvlist(nvl, "snaps", innvl); 741 } else { 742 /* 743 * We are probably called by even older binaries, 744 * allocate and populate nvlist with recursive 745 * snapshots 746 */ 747 if (zfs_component_namecheck(zc->zc_value, NULL, 748 NULL) == 0) { 749 tmpnvl = fnvlist_alloc(); 750 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 751 zc->zc_value, tmpnvl) == 0) 752 fnvlist_add_nvlist(nvl, "snaps", 753 tmpnvl); 754 nvlist_free(tmpnvl); 755 } 756 } 757 if (innvl != NULL) 758 nvlist_free(innvl); 759 /* strip dataset part from zc->zc_name */ 760 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 761 return (nvl); 762 break; 763 case ZFS_IOC_HOLD: 764 nvl = fnvlist_alloc(); 765 tmpnvl = fnvlist_alloc(); 766 if (zc->zc_cleanup_fd != -1) 767 fnvlist_add_int32(nvl, "cleanup_fd", 768 (int32_t)zc->zc_cleanup_fd); 769 if (zc->zc_cookie) { 770 hnvl = fnvlist_alloc(); 771 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 772 zc->zc_value, hnvl) == 0) { 773 elem = NULL; 774 while ((elem = nvlist_next_nvpair(hnvl, 775 elem)) != NULL) { 776 nvlist_add_string(tmpnvl, 777 nvpair_name(elem), zc->zc_string); 778 } 779 } 780 nvlist_free(hnvl); 781 } else { 782 snapname = kmem_asprintf("%s@%s", zc->zc_name, 783 zc->zc_value); 784 nvlist_add_string(tmpnvl, snapname, zc->zc_string); 785 kmem_free(snapname, strlen(snapname + 1)); 786 } 787 fnvlist_add_nvlist(nvl, "holds", tmpnvl); 788 nvlist_free(tmpnvl); 789 if (innvl != NULL) 790 nvlist_free(innvl); 791 /* strip dataset part from zc->zc_name */ 792 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 793 return (nvl); 794 break; 795 case ZFS_IOC_RELEASE: 796 nvl = fnvlist_alloc(); 797 tmpnvl = fnvlist_alloc(); 798 if (zc->zc_cookie) { 799 hnvl = fnvlist_alloc(); 800 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 801 zc->zc_value, hnvl) == 0) { 802 elem = NULL; 803 while ((elem = nvlist_next_nvpair(hnvl, 804 elem)) != NULL) { 805 fnvlist_add_boolean(tmpnvl, 806 zc->zc_string); 807 fnvlist_add_nvlist(nvl, 808 nvpair_name(elem), tmpnvl); 809 } 810 } 811 nvlist_free(hnvl); 812 } else { 813 snapname = kmem_asprintf("%s@%s", zc->zc_name, 814 zc->zc_value); 815 fnvlist_add_boolean(tmpnvl, zc->zc_string); 816 fnvlist_add_nvlist(nvl, snapname, tmpnvl); 817 kmem_free(snapname, strlen(snapname + 1)); 818 } 819 nvlist_free(tmpnvl); 820 if (innvl != NULL) 821 nvlist_free(innvl); 822 /* strip dataset part from zc->zc_name */ 823 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 824 return (nvl); 825 break; 826 } 827out: 828 return (innvl); 829} 830 831nvlist_t * 832zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec, 833 const int cflag) 834{ 835 nvlist_t *tmpnvl; 836 837 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 838 return (outnvl); 839 840 switch (vec) { 841 case ZFS_IOC_SPACE_SNAPS: 842 (void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie); 843 (void) nvlist_lookup_uint64(outnvl, "compressed", 844 &zc->zc_objset_type); 845 (void) nvlist_lookup_uint64(outnvl, "uncompressed", 846 &zc->zc_perm_action); 847 nvlist_free(outnvl); 848 /* return empty outnvl */ 849 tmpnvl = fnvlist_alloc(); 850 return (tmpnvl); 851 break; 852 case ZFS_IOC_CREATE: 853 case ZFS_IOC_CLONE: 854 case ZFS_IOC_HOLD: 855 case ZFS_IOC_RELEASE: 856 nvlist_free(outnvl); 857 /* return empty outnvl */ 858 tmpnvl = fnvlist_alloc(); 859 return (tmpnvl); 860 break; 861 } 862 863 return (outnvl); 864} 865#endif /* KERNEL */ 866