zfs_ioctl_compat.c revision 268649
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 40static int zfs_version_ioctl = ZFS_IOCVER_CURRENT; 41SYSCTL_DECL(_vfs_zfs_version); 42SYSCTL_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 */ 49void 50zfs_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 276void 277zfs_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 510static int 511zfs_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 548static int 549zfs_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 576static void 577zfs_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 617static int 618zfs_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 645static int 646zfs_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 685int 686zcmd_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_LZC: 701 ncmd = _IOWR('Z', request, struct zfs_cmd); 702 return (ioctl(fd, ncmd, zc)); 703 case ZFS_CMD_COMPAT_DEADMAN: 704 zc_c = malloc(sizeof(zfs_cmd_deadman_t)); 705 ncmd = _IOWR('Z', request, struct zfs_cmd_deadman); 706 break; 707 case ZFS_CMD_COMPAT_V28: 708 zc_c = malloc(sizeof(zfs_cmd_v28_t)); 709 ncmd = _IOWR('Z', request, struct zfs_cmd_v28); 710 break; 711 case ZFS_CMD_COMPAT_V15: 712 nc = zfs_ioctl_v28_to_v15[request]; 713 zc_c = malloc(sizeof(zfs_cmd_v15_t)); 714 ncmd = _IOWR('Z', nc, struct zfs_cmd_v15); 715 break; 716 default: 717 return (EINVAL); 718 } 719 720 if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL) 721 return (ENOTSUP); 722 723 zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag); 724 725 ret = ioctl(fd, ncmd, zc_c); 726 if (cflag == ZFS_CMD_COMPAT_V15 && 727 nc == ZFS_IOC_POOL_IMPORT) 728 ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS, 729 struct zfs_cmd_v15), zc_c); 730 zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag); 731 free(zc_c); 732 733 if (cflag == ZFS_CMD_COMPAT_V15) { 734 switch (nc) { 735 case ZFS_IOC_POOL_IMPORT: 736 case ZFS_IOC_POOL_CONFIGS: 737 case ZFS_IOC_POOL_STATS: 738 case ZFS_IOC_POOL_TRYIMPORT: 739 zfs_ioctl_compat_fix_stats(zc, nc); 740 break; 741 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 742 zfs_ioctl_compat_pool_get_props(zc); 743 break; 744 } 745 } 746 747 return (ret); 748} 749#else /* _KERNEL */ 750int 751zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag) 752{ 753 int error = 0; 754 755 /* are we creating a clone? */ 756 if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0') 757 *vec = ZFS_IOC_CLONE; 758 759 if (cflag == ZFS_CMD_COMPAT_V15) { 760 switch (*vec) { 761 762 case 7: /* ZFS_IOC_POOL_SCRUB (v15) */ 763 zc->zc_cookie = POOL_SCAN_SCRUB; 764 break; 765 } 766 } 767 768 return (error); 769} 770 771void 772zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag) 773{ 774 if (cflag == ZFS_CMD_COMPAT_V15) { 775 switch (vec) { 776 case ZFS_IOC_POOL_CONFIGS: 777 case ZFS_IOC_POOL_STATS: 778 case ZFS_IOC_POOL_TRYIMPORT: 779 zfs_ioctl_compat_fix_stats(zc, vec); 780 break; 781 case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 782 zfs_ioctl_compat_pool_get_props(zc); 783 break; 784 } 785 } 786} 787 788nvlist_t * 789zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec, 790 const int cflag) 791{ 792 nvlist_t *nvl, *tmpnvl, *hnvl; 793 nvpair_t *elem; 794 char *poolname, *snapname; 795 int err; 796 797 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 798 goto out; 799 800 switch (vec) { 801 case ZFS_IOC_CREATE: 802 nvl = fnvlist_alloc(); 803 fnvlist_add_int32(nvl, "type", zc->zc_objset_type); 804 if (innvl != NULL) { 805 fnvlist_add_nvlist(nvl, "props", innvl); 806 nvlist_free(innvl); 807 } 808 return (nvl); 809 break; 810 case ZFS_IOC_CLONE: 811 nvl = fnvlist_alloc(); 812 fnvlist_add_string(nvl, "origin", zc->zc_value); 813 if (innvl != NULL) { 814 fnvlist_add_nvlist(nvl, "props", innvl); 815 nvlist_free(innvl); 816 } 817 return (nvl); 818 break; 819 case ZFS_IOC_SNAPSHOT: 820 if (innvl == NULL) 821 goto out; 822 nvl = fnvlist_alloc(); 823 fnvlist_add_nvlist(nvl, "props", innvl); 824 tmpnvl = fnvlist_alloc(); 825 snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value); 826 fnvlist_add_boolean(tmpnvl, snapname); 827 kmem_free(snapname, strlen(snapname + 1)); 828 /* check if we are doing a recursive snapshot */ 829 if (zc->zc_cookie) 830 dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value, 831 tmpnvl); 832 fnvlist_add_nvlist(nvl, "snaps", tmpnvl); 833 fnvlist_free(tmpnvl); 834 nvlist_free(innvl); 835 /* strip dataset part from zc->zc_name */ 836 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 837 return (nvl); 838 break; 839 case ZFS_IOC_SPACE_SNAPS: 840 nvl = fnvlist_alloc(); 841 fnvlist_add_string(nvl, "firstsnap", zc->zc_value); 842 if (innvl != NULL) 843 nvlist_free(innvl); 844 return (nvl); 845 break; 846 case ZFS_IOC_DESTROY_SNAPS: 847 if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN) 848 goto out; 849 nvl = fnvlist_alloc(); 850 if (innvl != NULL) { 851 fnvlist_add_nvlist(nvl, "snaps", innvl); 852 } else { 853 /* 854 * We are probably called by even older binaries, 855 * allocate and populate nvlist with recursive 856 * snapshots 857 */ 858 if (zfs_component_namecheck(zc->zc_value, NULL, 859 NULL) == 0) { 860 tmpnvl = fnvlist_alloc(); 861 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 862 zc->zc_value, tmpnvl) == 0) 863 fnvlist_add_nvlist(nvl, "snaps", 864 tmpnvl); 865 nvlist_free(tmpnvl); 866 } 867 } 868 if (innvl != NULL) 869 nvlist_free(innvl); 870 /* strip dataset part from zc->zc_name */ 871 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 872 return (nvl); 873 break; 874 case ZFS_IOC_HOLD: 875 nvl = fnvlist_alloc(); 876 tmpnvl = fnvlist_alloc(); 877 if (zc->zc_cleanup_fd != -1) 878 fnvlist_add_int32(nvl, "cleanup_fd", 879 (int32_t)zc->zc_cleanup_fd); 880 if (zc->zc_cookie) { 881 hnvl = fnvlist_alloc(); 882 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 883 zc->zc_value, hnvl) == 0) { 884 elem = NULL; 885 while ((elem = nvlist_next_nvpair(hnvl, 886 elem)) != NULL) { 887 nvlist_add_string(tmpnvl, 888 nvpair_name(elem), zc->zc_string); 889 } 890 } 891 nvlist_free(hnvl); 892 } else { 893 snapname = kmem_asprintf("%s@%s", zc->zc_name, 894 zc->zc_value); 895 nvlist_add_string(tmpnvl, snapname, zc->zc_string); 896 kmem_free(snapname, strlen(snapname + 1)); 897 } 898 fnvlist_add_nvlist(nvl, "holds", tmpnvl); 899 nvlist_free(tmpnvl); 900 if (innvl != NULL) 901 nvlist_free(innvl); 902 /* strip dataset part from zc->zc_name */ 903 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 904 return (nvl); 905 break; 906 case ZFS_IOC_RELEASE: 907 nvl = fnvlist_alloc(); 908 tmpnvl = fnvlist_alloc(); 909 if (zc->zc_cookie) { 910 hnvl = fnvlist_alloc(); 911 if (dmu_get_recursive_snaps_nvl(zc->zc_name, 912 zc->zc_value, hnvl) == 0) { 913 elem = NULL; 914 while ((elem = nvlist_next_nvpair(hnvl, 915 elem)) != NULL) { 916 fnvlist_add_boolean(tmpnvl, 917 zc->zc_string); 918 fnvlist_add_nvlist(nvl, 919 nvpair_name(elem), tmpnvl); 920 } 921 } 922 nvlist_free(hnvl); 923 } else { 924 snapname = kmem_asprintf("%s@%s", zc->zc_name, 925 zc->zc_value); 926 fnvlist_add_boolean(tmpnvl, zc->zc_string); 927 fnvlist_add_nvlist(nvl, snapname, tmpnvl); 928 kmem_free(snapname, strlen(snapname + 1)); 929 } 930 nvlist_free(tmpnvl); 931 if (innvl != NULL) 932 nvlist_free(innvl); 933 /* strip dataset part from zc->zc_name */ 934 zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 935 return (nvl); 936 break; 937 } 938out: 939 return (innvl); 940} 941 942nvlist_t * 943zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec, 944 const int cflag) 945{ 946 nvlist_t *tmpnvl; 947 948 if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 949 return (outnvl); 950 951 switch (vec) { 952 case ZFS_IOC_SPACE_SNAPS: 953 (void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie); 954 (void) nvlist_lookup_uint64(outnvl, "compressed", 955 &zc->zc_objset_type); 956 (void) nvlist_lookup_uint64(outnvl, "uncompressed", 957 &zc->zc_perm_action); 958 nvlist_free(outnvl); 959 /* return empty outnvl */ 960 tmpnvl = fnvlist_alloc(); 961 return (tmpnvl); 962 break; 963 case ZFS_IOC_CREATE: 964 case ZFS_IOC_CLONE: 965 case ZFS_IOC_HOLD: 966 case ZFS_IOC_RELEASE: 967 nvlist_free(outnvl); 968 /* return empty outnvl */ 969 tmpnvl = fnvlist_alloc(); 970 return (tmpnvl); 971 break; 972 } 973 974 return (outnvl); 975} 976#endif /* KERNEL */ 977