1219089Spjd/* 2219089Spjd * CDDL HEADER START 3219089Spjd * 4219089Spjd * The contents of this file are subject to the terms of the 5219089Spjd * Common Development and Distribution License (the "License"). 6219089Spjd * You may not use this file except in compliance with the License. 7219089Spjd * 8219089Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9219089Spjd * or http://www.opensolaris.org/os/licensing. 10219089Spjd * See the License for the specific language governing permissions 11219089Spjd * and limitations under the License. 12219089Spjd * 13219089Spjd * When distributing Covered Code, include this CDDL HEADER in each 14219089Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15219089Spjd * If applicable, add the following below this CDDL HEADER, with the 16219089Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17219089Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18219089Spjd * 19219089Spjd * CDDL HEADER END 20219089Spjd */ 21219089Spjd/* 22248369Smm * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 23220447Smm * Portions Copyright 2005, 2010, Oracle and/or its affiliates. 24220447Smm * All rights reserved. 25219089Spjd * Use is subject to license terms. 26219089Spjd */ 27219089Spjd 28219089Spjd#include <sys/types.h> 29219089Spjd#include <sys/param.h> 30219089Spjd#include <sys/cred.h> 31219089Spjd#include <sys/dmu.h> 32219089Spjd#include <sys/zio.h> 33219089Spjd#include <sys/nvpair.h> 34219089Spjd#include <sys/dsl_deleg.h> 35219089Spjd#include <sys/zfs_ioctl.h> 36249643Smm#include "zfs_namecheck.h" 37219089Spjd#include "zfs_ioctl_compat.h" 38219089Spjd 39248369Smmstatic int zfs_version_ioctl = ZFS_IOCVER_CURRENT; 40248369SmmSYSCTL_DECL(_vfs_zfs_version); 41248369SmmSYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl, 42248369Smm 0, "ZFS_IOCTL_VERSION"); 43248369Smm 44219089Spjd/* 45248369Smm * FreeBSD zfs_cmd compatibility with older binaries 46219089Spjd * appropriately remap/extend the zfs_cmd_t structure 47219089Spjd */ 48219089Spjdvoid 49219089Spjdzfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag) 50219089Spjd{ 51219089Spjd zfs_cmd_v15_t *zc_c; 52248369Smm zfs_cmd_v28_t *zc28_c; 53249643Smm zfs_cmd_deadman_t *zcdm_c; 54219089Spjd 55248369Smm switch (cflag) { 56249643Smm case ZFS_CMD_COMPAT_DEADMAN: 57249643Smm zcdm_c = (void *)addr; 58249643Smm /* zc */ 59249643Smm strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN); 60249643Smm strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2); 61249643Smm strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN); 62249643Smm zc->zc_guid = zcdm_c->zc_guid; 63249643Smm zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf; 64249643Smm zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size; 65249643Smm zc->zc_nvlist_src = zcdm_c->zc_nvlist_src; 66249643Smm zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size; 67249643Smm zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst; 68249643Smm zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size; 69249643Smm zc->zc_cookie = zcdm_c->zc_cookie; 70249643Smm zc->zc_objset_type = zcdm_c->zc_objset_type; 71249643Smm zc->zc_perm_action = zcdm_c->zc_perm_action; 72249643Smm zc->zc_history = zcdm_c->zc_history; 73249643Smm zc->zc_history_len = zcdm_c->zc_history_len; 74249643Smm zc->zc_history_offset = zcdm_c->zc_history_offset; 75249643Smm zc->zc_obj = zcdm_c->zc_obj; 76249643Smm zc->zc_iflags = zcdm_c->zc_iflags; 77249643Smm zc->zc_share = zcdm_c->zc_share; 78249643Smm zc->zc_jailid = zcdm_c->zc_jailid; 79249643Smm zc->zc_objset_stats = zcdm_c->zc_objset_stats; 80249643Smm zc->zc_begin_record = zcdm_c->zc_begin_record; 81249643Smm zc->zc_defer_destroy = zcdm_c->zc_defer_destroy; 82249643Smm zc->zc_temphold = zcdm_c->zc_temphold; 83249643Smm zc->zc_action_handle = zcdm_c->zc_action_handle; 84249643Smm zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd; 85249643Smm zc->zc_simple = zcdm_c->zc_simple; 86249643Smm bcopy(zcdm_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); 87249643Smm zc->zc_sendobj = zcdm_c->zc_sendobj; 88249643Smm zc->zc_fromobj = zcdm_c->zc_fromobj; 89249643Smm zc->zc_createtxg = zcdm_c->zc_createtxg; 90249643Smm zc->zc_stat = zcdm_c->zc_stat; 91249643Smm 92249643Smm /* zc_inject_record doesn't change in libzfs_core */ 93249643Smm zcdm_c->zc_inject_record = zc->zc_inject_record; 94249643Smm 95249643Smm /* we always assume zc_nvlist_dst_filled is true */ 96249643Smm zc->zc_nvlist_dst_filled = B_TRUE; 97249643Smm break; 98249643Smm 99248369Smm case ZFS_CMD_COMPAT_V28: 100248369Smm zc28_c = (void *)addr; 101248369Smm 102248369Smm /* zc */ 103248369Smm strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN); 104248369Smm strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2); 105248369Smm strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN); 106248369Smm zc->zc_guid = zc28_c->zc_guid; 107248369Smm zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf; 108248369Smm zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size; 109248369Smm zc->zc_nvlist_src = zc28_c->zc_nvlist_src; 110248369Smm zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size; 111248369Smm zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst; 112248369Smm zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size; 113248369Smm zc->zc_cookie = zc28_c->zc_cookie; 114248369Smm zc->zc_objset_type = zc28_c->zc_objset_type; 115248369Smm zc->zc_perm_action = zc28_c->zc_perm_action; 116248369Smm zc->zc_history = zc28_c->zc_history; 117248369Smm zc->zc_history_len = zc28_c->zc_history_len; 118248369Smm zc->zc_history_offset = zc28_c->zc_history_offset; 119248369Smm zc->zc_obj = zc28_c->zc_obj; 120248369Smm zc->zc_iflags = zc28_c->zc_iflags; 121248369Smm zc->zc_share = zc28_c->zc_share; 122248369Smm zc->zc_jailid = zc28_c->zc_jailid; 123248369Smm zc->zc_objset_stats = zc28_c->zc_objset_stats; 124248369Smm zc->zc_begin_record = zc28_c->zc_begin_record; 125248369Smm zc->zc_defer_destroy = zc28_c->zc_defer_destroy; 126248369Smm zc->zc_temphold = zc28_c->zc_temphold; 127248369Smm zc->zc_action_handle = zc28_c->zc_action_handle; 128248369Smm zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd; 129248369Smm zc->zc_simple = zc28_c->zc_simple; 130248369Smm bcopy(zc28_c->zc_pad, zc->zc_pad, sizeof(zc->zc_pad)); 131248369Smm zc->zc_sendobj = zc28_c->zc_sendobj; 132248369Smm zc->zc_fromobj = zc28_c->zc_fromobj; 133248369Smm zc->zc_createtxg = zc28_c->zc_createtxg; 134248369Smm zc->zc_stat = zc28_c->zc_stat; 135248369Smm 136248369Smm /* zc->zc_inject_record */ 137248369Smm zc->zc_inject_record.zi_objset = 138248369Smm zc28_c->zc_inject_record.zi_objset; 139248369Smm zc->zc_inject_record.zi_object = 140248369Smm zc28_c->zc_inject_record.zi_object; 141248369Smm zc->zc_inject_record.zi_start = 142248369Smm zc28_c->zc_inject_record.zi_start; 143248369Smm zc->zc_inject_record.zi_end = 144248369Smm zc28_c->zc_inject_record.zi_end; 145248369Smm zc->zc_inject_record.zi_guid = 146248369Smm zc28_c->zc_inject_record.zi_guid; 147248369Smm zc->zc_inject_record.zi_level = 148248369Smm zc28_c->zc_inject_record.zi_level; 149248369Smm zc->zc_inject_record.zi_error = 150248369Smm zc28_c->zc_inject_record.zi_error; 151248369Smm zc->zc_inject_record.zi_type = 152248369Smm zc28_c->zc_inject_record.zi_type; 153248369Smm zc->zc_inject_record.zi_freq = 154248369Smm zc28_c->zc_inject_record.zi_freq; 155248369Smm zc->zc_inject_record.zi_failfast = 156248369Smm zc28_c->zc_inject_record.zi_failfast; 157248369Smm strlcpy(zc->zc_inject_record.zi_func, 158248369Smm zc28_c->zc_inject_record.zi_func, MAXNAMELEN); 159248369Smm zc->zc_inject_record.zi_iotype = 160248369Smm zc28_c->zc_inject_record.zi_iotype; 161248369Smm zc->zc_inject_record.zi_duration = 162248369Smm zc28_c->zc_inject_record.zi_duration; 163248369Smm zc->zc_inject_record.zi_timer = 164248369Smm zc28_c->zc_inject_record.zi_timer; 165248369Smm zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED; 166248369Smm zc->zc_inject_record.zi_pad = 0; 167248369Smm break; 168248369Smm 169248369Smm case ZFS_CMD_COMPAT_V15: 170219089Spjd zc_c = (void *)addr; 171219089Spjd 172219089Spjd /* zc */ 173248369Smm strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN); 174248369Smm strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN); 175248369Smm strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN); 176219089Spjd zc->zc_guid = zc_c->zc_guid; 177219089Spjd zc->zc_nvlist_conf = zc_c->zc_nvlist_conf; 178219089Spjd zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size; 179219089Spjd zc->zc_nvlist_src = zc_c->zc_nvlist_src; 180219089Spjd zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size; 181219089Spjd zc->zc_nvlist_dst = zc_c->zc_nvlist_dst; 182219089Spjd zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size; 183219089Spjd zc->zc_cookie = zc_c->zc_cookie; 184219089Spjd zc->zc_objset_type = zc_c->zc_objset_type; 185219089Spjd zc->zc_perm_action = zc_c->zc_perm_action; 186219089Spjd zc->zc_history = zc_c->zc_history; 187219089Spjd zc->zc_history_len = zc_c->zc_history_len; 188219089Spjd zc->zc_history_offset = zc_c->zc_history_offset; 189219089Spjd zc->zc_obj = zc_c->zc_obj; 190219089Spjd zc->zc_share = zc_c->zc_share; 191219089Spjd zc->zc_jailid = zc_c->zc_jailid; 192219089Spjd zc->zc_objset_stats = zc_c->zc_objset_stats; 193219089Spjd zc->zc_begin_record = zc_c->zc_begin_record; 194219089Spjd 195219089Spjd /* zc->zc_inject_record */ 196219089Spjd zc->zc_inject_record.zi_objset = 197219089Spjd zc_c->zc_inject_record.zi_objset; 198219089Spjd zc->zc_inject_record.zi_object = 199219089Spjd zc_c->zc_inject_record.zi_object; 200219089Spjd zc->zc_inject_record.zi_start = 201219089Spjd zc_c->zc_inject_record.zi_start; 202219089Spjd zc->zc_inject_record.zi_end = 203219089Spjd zc_c->zc_inject_record.zi_end; 204219089Spjd zc->zc_inject_record.zi_guid = 205219089Spjd zc_c->zc_inject_record.zi_guid; 206219089Spjd zc->zc_inject_record.zi_level = 207219089Spjd zc_c->zc_inject_record.zi_level; 208219089Spjd zc->zc_inject_record.zi_error = 209219089Spjd zc_c->zc_inject_record.zi_error; 210219089Spjd zc->zc_inject_record.zi_type = 211219089Spjd zc_c->zc_inject_record.zi_type; 212219089Spjd zc->zc_inject_record.zi_freq = 213219089Spjd zc_c->zc_inject_record.zi_freq; 214219089Spjd zc->zc_inject_record.zi_failfast = 215219089Spjd zc_c->zc_inject_record.zi_failfast; 216248369Smm break; 217219089Spjd } 218219089Spjd} 219219089Spjd 220219089Spjdvoid 221249643Smmzfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request, 222249643Smm const int cflag) 223219089Spjd{ 224219089Spjd zfs_cmd_v15_t *zc_c; 225248369Smm zfs_cmd_v28_t *zc28_c; 226249643Smm zfs_cmd_deadman_t *zcdm_c; 227219089Spjd 228219089Spjd switch (cflag) { 229249643Smm case ZFS_CMD_COMPAT_DEADMAN: 230249643Smm zcdm_c = (void *)addr; 231249643Smm 232249643Smm strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN); 233249643Smm strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2); 234249643Smm strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN); 235249643Smm zcdm_c->zc_guid = zc->zc_guid; 236249643Smm zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf; 237249643Smm zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 238249643Smm zcdm_c->zc_nvlist_src = zc->zc_nvlist_src; 239249643Smm zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 240249643Smm zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst; 241249643Smm zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 242249643Smm zcdm_c->zc_cookie = zc->zc_cookie; 243249643Smm zcdm_c->zc_objset_type = zc->zc_objset_type; 244249643Smm zcdm_c->zc_perm_action = zc->zc_perm_action; 245249643Smm zcdm_c->zc_history = zc->zc_history; 246249643Smm zcdm_c->zc_history_len = zc->zc_history_len; 247249643Smm zcdm_c->zc_history_offset = zc->zc_history_offset; 248249643Smm zcdm_c->zc_obj = zc->zc_obj; 249249643Smm zcdm_c->zc_iflags = zc->zc_iflags; 250249643Smm zcdm_c->zc_share = zc->zc_share; 251249643Smm zcdm_c->zc_jailid = zc->zc_jailid; 252249643Smm zcdm_c->zc_objset_stats = zc->zc_objset_stats; 253249643Smm zcdm_c->zc_begin_record = zc->zc_begin_record; 254249643Smm zcdm_c->zc_defer_destroy = zc->zc_defer_destroy; 255249643Smm zcdm_c->zc_temphold = zc->zc_temphold; 256249643Smm zcdm_c->zc_action_handle = zc->zc_action_handle; 257249643Smm zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd; 258249643Smm zcdm_c->zc_simple = zc->zc_simple; 259249643Smm bcopy(zc->zc_pad, zcdm_c->zc_pad, sizeof(zcdm_c->zc_pad)); 260249643Smm zcdm_c->zc_sendobj = zc->zc_sendobj; 261249643Smm zcdm_c->zc_fromobj = zc->zc_fromobj; 262249643Smm zcdm_c->zc_createtxg = zc->zc_createtxg; 263249643Smm zcdm_c->zc_stat = zc->zc_stat; 264249643Smm 265249643Smm /* zc_inject_record doesn't change in libzfs_core */ 266249643Smm zc->zc_inject_record = zcdm_c->zc_inject_record; 267249643Smm#ifndef _KERNEL 268249643Smm if (request == ZFS_IOC_RECV) 269249643Smm strlcpy(zcdm_c->zc_top_ds, 270249643Smm zc->zc_value + strlen(zc->zc_value) + 1, 271249643Smm (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1); 272249643Smm#endif 273249643Smm break; 274249643Smm 275248369Smm case ZFS_CMD_COMPAT_V28: 276248369Smm zc28_c = (void *)addr; 277248369Smm 278248369Smm strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN); 279248369Smm strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2); 280248369Smm strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN); 281248369Smm zc28_c->zc_guid = zc->zc_guid; 282248369Smm zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf; 283248369Smm zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 284248369Smm zc28_c->zc_nvlist_src = zc->zc_nvlist_src; 285248369Smm zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 286248369Smm zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst; 287248369Smm zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 288248369Smm zc28_c->zc_cookie = zc->zc_cookie; 289248369Smm zc28_c->zc_objset_type = zc->zc_objset_type; 290248369Smm zc28_c->zc_perm_action = zc->zc_perm_action; 291248369Smm zc28_c->zc_history = zc->zc_history; 292248369Smm zc28_c->zc_history_len = zc->zc_history_len; 293248369Smm zc28_c->zc_history_offset = zc->zc_history_offset; 294248369Smm zc28_c->zc_obj = zc->zc_obj; 295248369Smm zc28_c->zc_iflags = zc->zc_iflags; 296248369Smm zc28_c->zc_share = zc->zc_share; 297248369Smm zc28_c->zc_jailid = zc->zc_jailid; 298248369Smm zc28_c->zc_objset_stats = zc->zc_objset_stats; 299248369Smm zc28_c->zc_begin_record = zc->zc_begin_record; 300248369Smm zc28_c->zc_defer_destroy = zc->zc_defer_destroy; 301248369Smm zc28_c->zc_temphold = zc->zc_temphold; 302248369Smm zc28_c->zc_action_handle = zc->zc_action_handle; 303248369Smm zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd; 304248369Smm zc28_c->zc_simple = zc->zc_simple; 305248369Smm bcopy(zc->zc_pad, zc28_c->zc_pad, sizeof(zc28_c->zc_pad)); 306248369Smm zc28_c->zc_sendobj = zc->zc_sendobj; 307248369Smm zc28_c->zc_fromobj = zc->zc_fromobj; 308248369Smm zc28_c->zc_createtxg = zc->zc_createtxg; 309248369Smm zc28_c->zc_stat = zc->zc_stat; 310249643Smm#ifndef _KERNEL 311249643Smm if (request == ZFS_IOC_RECV) 312249643Smm strlcpy(zc28_c->zc_top_ds, 313249643Smm zc->zc_value + strlen(zc->zc_value) + 1, 314249643Smm MAXPATHLEN * 2 - strlen(zc->zc_value) - 1); 315249643Smm#endif 316248369Smm /* zc_inject_record */ 317248369Smm zc28_c->zc_inject_record.zi_objset = 318248369Smm zc->zc_inject_record.zi_objset; 319248369Smm zc28_c->zc_inject_record.zi_object = 320248369Smm zc->zc_inject_record.zi_object; 321248369Smm zc28_c->zc_inject_record.zi_start = 322248369Smm zc->zc_inject_record.zi_start; 323248369Smm zc28_c->zc_inject_record.zi_end = 324248369Smm zc->zc_inject_record.zi_end; 325248369Smm zc28_c->zc_inject_record.zi_guid = 326248369Smm zc->zc_inject_record.zi_guid; 327248369Smm zc28_c->zc_inject_record.zi_level = 328248369Smm zc->zc_inject_record.zi_level; 329248369Smm zc28_c->zc_inject_record.zi_error = 330248369Smm zc->zc_inject_record.zi_error; 331248369Smm zc28_c->zc_inject_record.zi_type = 332248369Smm zc->zc_inject_record.zi_type; 333248369Smm zc28_c->zc_inject_record.zi_freq = 334248369Smm zc->zc_inject_record.zi_freq; 335248369Smm zc28_c->zc_inject_record.zi_failfast = 336248369Smm zc->zc_inject_record.zi_failfast; 337248369Smm strlcpy(zc28_c->zc_inject_record.zi_func, 338248369Smm zc->zc_inject_record.zi_func, MAXNAMELEN); 339248369Smm zc28_c->zc_inject_record.zi_iotype = 340248369Smm zc->zc_inject_record.zi_iotype; 341248369Smm zc28_c->zc_inject_record.zi_duration = 342248369Smm zc->zc_inject_record.zi_duration; 343248369Smm zc28_c->zc_inject_record.zi_timer = 344248369Smm zc->zc_inject_record.zi_timer; 345248369Smm break; 346248369Smm 347219089Spjd case ZFS_CMD_COMPAT_V15: 348219089Spjd zc_c = (void *)addr; 349219089Spjd 350219089Spjd /* zc */ 351248369Smm strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN); 352248369Smm strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN); 353248369Smm strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN); 354219089Spjd zc_c->zc_guid = zc->zc_guid; 355219089Spjd zc_c->zc_nvlist_conf = zc->zc_nvlist_conf; 356219089Spjd zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size; 357219089Spjd zc_c->zc_nvlist_src = zc->zc_nvlist_src; 358219089Spjd zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size; 359219089Spjd zc_c->zc_nvlist_dst = zc->zc_nvlist_dst; 360219089Spjd zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size; 361219089Spjd zc_c->zc_cookie = zc->zc_cookie; 362219089Spjd zc_c->zc_objset_type = zc->zc_objset_type; 363219089Spjd zc_c->zc_perm_action = zc->zc_perm_action; 364219089Spjd zc_c->zc_history = zc->zc_history; 365219089Spjd zc_c->zc_history_len = zc->zc_history_len; 366219089Spjd zc_c->zc_history_offset = zc->zc_history_offset; 367219089Spjd zc_c->zc_obj = zc->zc_obj; 368219089Spjd zc_c->zc_share = zc->zc_share; 369219089Spjd zc_c->zc_jailid = zc->zc_jailid; 370219089Spjd zc_c->zc_objset_stats = zc->zc_objset_stats; 371219089Spjd zc_c->zc_begin_record = zc->zc_begin_record; 372219089Spjd 373219089Spjd /* zc_inject_record */ 374219089Spjd zc_c->zc_inject_record.zi_objset = 375219089Spjd zc->zc_inject_record.zi_objset; 376219089Spjd zc_c->zc_inject_record.zi_object = 377219089Spjd zc->zc_inject_record.zi_object; 378219089Spjd zc_c->zc_inject_record.zi_start = 379219089Spjd zc->zc_inject_record.zi_start; 380219089Spjd zc_c->zc_inject_record.zi_end = 381219089Spjd zc->zc_inject_record.zi_end; 382219089Spjd zc_c->zc_inject_record.zi_guid = 383219089Spjd zc->zc_inject_record.zi_guid; 384219089Spjd zc_c->zc_inject_record.zi_level = 385219089Spjd zc->zc_inject_record.zi_level; 386219089Spjd zc_c->zc_inject_record.zi_error = 387219089Spjd zc->zc_inject_record.zi_error; 388219089Spjd zc_c->zc_inject_record.zi_type = 389219089Spjd zc->zc_inject_record.zi_type; 390219089Spjd zc_c->zc_inject_record.zi_freq = 391219089Spjd zc->zc_inject_record.zi_freq; 392219089Spjd zc_c->zc_inject_record.zi_failfast = 393219089Spjd zc->zc_inject_record.zi_failfast; 394219089Spjd 395219089Spjd break; 396219089Spjd } 397219089Spjd} 398219089Spjd 399219089Spjdstatic int 400220447Smmzfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag, 401220447Smm nvlist_t **nvp) 402219089Spjd{ 403220447Smm char *packed; 404220447Smm int error; 405220447Smm nvlist_t *list = NULL; 406219089Spjd 407220447Smm /* 408220447Smm * Read in and unpack the user-supplied nvlist. 409220447Smm */ 410220447Smm if (size == 0) 411220447Smm return (EINVAL); 412219089Spjd 413220447Smm#ifdef _KERNEL 414220447Smm packed = kmem_alloc(size, KM_SLEEP); 415220447Smm if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size, 416220447Smm iflag)) != 0) { 417220447Smm kmem_free(packed, size); 418220447Smm return (error); 419220447Smm } 420220447Smm#else 421220447Smm packed = (void *)(uintptr_t)nvl; 422220447Smm#endif 423220447Smm 424220447Smm error = nvlist_unpack(packed, size, &list, 0); 425220447Smm 426220447Smm#ifdef _KERNEL 427220447Smm kmem_free(packed, size); 428220447Smm#endif 429220447Smm 430220447Smm if (error != 0) 431220447Smm return (error); 432220447Smm 433220447Smm *nvp = list; 434220447Smm return (0); 435219089Spjd} 436219089Spjd 437220447Smmstatic int 438220447Smmzfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) 439220447Smm{ 440220447Smm char *packed = NULL; 441220447Smm int error = 0; 442220447Smm size_t size; 443220447Smm 444220447Smm VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); 445220447Smm 446220447Smm#ifdef _KERNEL 447220447Smm packed = kmem_alloc(size, KM_SLEEP); 448220447Smm VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 449220447Smm KM_SLEEP) == 0); 450220447Smm 451220447Smm if (ddi_copyout(packed, 452220447Smm (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0) 453220447Smm error = EFAULT; 454220447Smm kmem_free(packed, size); 455220447Smm#else 456220447Smm packed = (void *)(uintptr_t)zc->zc_nvlist_dst; 457220447Smm VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, 458220447Smm 0) == 0); 459220447Smm#endif 460220447Smm 461220447Smm zc->zc_nvlist_dst_size = size; 462220447Smm return (error); 463220447Smm} 464220447Smm 465219089Spjdstatic void 466219089Spjdzfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl) 467219089Spjd{ 468219089Spjd nvlist_t **child; 469219089Spjd nvlist_t *nvroot = NULL; 470219089Spjd vdev_stat_t *vs; 471219089Spjd uint_t c, children, nelem; 472219089Spjd 473219089Spjd if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, 474219089Spjd &child, &children) == 0) { 475219089Spjd for (c = 0; c < children; c++) { 476219089Spjd zfs_ioctl_compat_fix_stats_nvlist(child[c]); 477219089Spjd } 478219089Spjd } 479219089Spjd 480219089Spjd if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE, 481219089Spjd &nvroot) == 0) 482219089Spjd zfs_ioctl_compat_fix_stats_nvlist(nvroot); 483219089Spjd#ifdef _KERNEL 484219089Spjd if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS, 485219089Spjd#else 486219089Spjd if ((nvlist_lookup_uint64_array(nvl, "stats", 487219089Spjd#endif 488219089Spjd 489219089Spjd (uint64_t **)&vs, &nelem) == 0)) { 490219089Spjd nvlist_add_uint64_array(nvl, 491219089Spjd#ifdef _KERNEL 492219089Spjd "stats", 493219089Spjd#else 494219089Spjd ZPOOL_CONFIG_VDEV_STATS, 495219089Spjd#endif 496219089Spjd (uint64_t *)vs, nelem); 497219089Spjd#ifdef _KERNEL 498219089Spjd nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS, 499219089Spjd#else 500219089Spjd nvlist_remove(nvl, "stats", 501219089Spjd#endif 502219089Spjd DATA_TYPE_UINT64_ARRAY); 503219089Spjd } 504219089Spjd} 505219089Spjd 506220447Smmstatic int 507248369Smmzfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc) 508219089Spjd{ 509219089Spjd nvlist_t *nv, *nvp = NULL; 510219089Spjd nvpair_t *elem; 511220447Smm int error; 512219089Spjd 513220447Smm if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst, 514220447Smm zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) 515220447Smm return (error); 516219089Spjd 517248369Smm if (nc == 5) { /* ZFS_IOC_POOL_STATS */ 518219089Spjd elem = NULL; 519219089Spjd while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) { 520219089Spjd if (nvpair_value_nvlist(elem, &nvp) == 0) 521219089Spjd zfs_ioctl_compat_fix_stats_nvlist(nvp); 522219089Spjd } 523219089Spjd elem = NULL; 524219089Spjd } else 525219089Spjd zfs_ioctl_compat_fix_stats_nvlist(nv); 526219089Spjd 527220447Smm error = zfs_ioctl_compat_put_nvlist(zc, nv); 528219089Spjd 529219089Spjd nvlist_free(nv); 530220447Smm 531220447Smm return (error); 532219089Spjd} 533219089Spjd 534220447Smmstatic int 535219089Spjdzfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc) 536219089Spjd{ 537219089Spjd nvlist_t *nv, *nva = NULL; 538220447Smm int error; 539219089Spjd 540220447Smm if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst, 541220447Smm zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0) 542220447Smm return (error); 543219089Spjd 544219089Spjd#ifdef _KERNEL 545219089Spjd if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) { 546219089Spjd nvlist_add_nvlist(nv, "used", nva); 547219089Spjd nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST); 548219089Spjd } 549219089Spjd 550219089Spjd if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) { 551219089Spjd nvlist_add_nvlist(nv, "available", nva); 552219089Spjd nvlist_remove(nv, "free", DATA_TYPE_NVLIST); 553219089Spjd } 554219089Spjd#else 555219089Spjd if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) { 556219089Spjd nvlist_add_nvlist(nv, "allocated", nva); 557219089Spjd nvlist_remove(nv, "used", DATA_TYPE_NVLIST); 558219089Spjd } 559219089Spjd 560219089Spjd if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) { 561219089Spjd nvlist_add_nvlist(nv, "free", nva); 562219089Spjd nvlist_remove(nv, "available", DATA_TYPE_NVLIST); 563219089Spjd } 564219089Spjd#endif 565219089Spjd 566220447Smm error = zfs_ioctl_compat_put_nvlist(zc, nv); 567219089Spjd 568219089Spjd nvlist_free(nv); 569220447Smm 570220447Smm return (error); 571219089Spjd} 572219089Spjd 573219089Spjd#ifndef _KERNEL 574219089Spjdint 575249643Smmzcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) 576219089Spjd{ 577219089Spjd int nc, ret; 578219089Spjd void *zc_c; 579219089Spjd unsigned long ncmd; 580249643Smm zfs_iocparm_t zp; 581219089Spjd 582248369Smm switch (cflag) { 583248369Smm case ZFS_CMD_COMPAT_NONE: 584249643Smm ncmd = _IOWR('Z', request, struct zfs_iocparm); 585249643Smm zp.zfs_cmd = (uint64_t)zc; 586249643Smm zp.zfs_cmd_size = sizeof(zfs_cmd_t); 587249643Smm zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT; 588249643Smm return (ioctl(fd, ncmd, &zp)); 589249643Smm case ZFS_CMD_COMPAT_LZC: 590249643Smm ncmd = _IOWR('Z', request, struct zfs_cmd); 591249643Smm return (ioctl(fd, ncmd, zc)); 592249643Smm case ZFS_CMD_COMPAT_DEADMAN: 593249643Smm zc_c = malloc(sizeof(zfs_cmd_deadman_t)); 594249643Smm ncmd = _IOWR('Z', request, struct zfs_cmd_deadman); 595249643Smm break; 596248369Smm case ZFS_CMD_COMPAT_V28: 597248369Smm zc_c = malloc(sizeof(zfs_cmd_v28_t)); 598249643Smm ncmd = _IOWR('Z', request, struct zfs_cmd_v28); 599248369Smm break; 600248369Smm case ZFS_CMD_COMPAT_V15: 601249643Smm nc = zfs_ioctl_v28_to_v15[request]; 602219089Spjd zc_c = malloc(sizeof(zfs_cmd_v15_t)); 603219089Spjd ncmd = _IOWR('Z', nc, struct zfs_cmd_v15); 604248369Smm break; 605248369Smm default: 606219089Spjd return (EINVAL); 607248369Smm } 608219089Spjd 609249643Smm if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL) 610219089Spjd return (ENOTSUP); 611219089Spjd 612249643Smm zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag); 613249643Smm 614219089Spjd ret = ioctl(fd, ncmd, zc_c); 615219089Spjd if (cflag == ZFS_CMD_COMPAT_V15 && 616249643Smm nc == ZFS_IOC_POOL_IMPORT) 617249643Smm ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS, 618219089Spjd struct zfs_cmd_v15), zc_c); 619219089Spjd zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag); 620219089Spjd free(zc_c); 621219089Spjd 622248369Smm if (cflag == ZFS_CMD_COMPAT_V15) { 623248369Smm switch (nc) { 624249643Smm case ZFS_IOC_POOL_IMPORT: 625249643Smm case ZFS_IOC_POOL_CONFIGS: 626249643Smm case ZFS_IOC_POOL_STATS: 627249643Smm case ZFS_IOC_POOL_TRYIMPORT: 628248369Smm zfs_ioctl_compat_fix_stats(zc, nc); 629248369Smm break; 630248369Smm case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 631248369Smm zfs_ioctl_compat_pool_get_props(zc); 632248369Smm break; 633248369Smm } 634219089Spjd } 635219089Spjd 636219089Spjd return (ret); 637219089Spjd} 638219089Spjd#else /* _KERNEL */ 639249643Smmint 640219089Spjdzfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag) 641219089Spjd{ 642249643Smm int error = 0; 643249643Smm 644249643Smm /* are we creating a clone? */ 645249643Smm if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0') 646249643Smm *vec = ZFS_IOC_CLONE; 647249643Smm 648249643Smm if (cflag == ZFS_CMD_COMPAT_V15) { 649219089Spjd switch (*vec) { 650219089Spjd 651219089Spjd case 7: /* ZFS_IOC_POOL_SCRUB (v15) */ 652219089Spjd zc->zc_cookie = POOL_SCAN_SCRUB; 653219089Spjd break; 654219089Spjd } 655249643Smm } 656249643Smm 657249643Smm return (error); 658219089Spjd} 659219089Spjd 660219089Spjdvoid 661219089Spjdzfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag) 662219089Spjd{ 663219089Spjd if (cflag == ZFS_CMD_COMPAT_V15) { 664219089Spjd switch (vec) { 665249643Smm case ZFS_IOC_POOL_CONFIGS: 666249643Smm case ZFS_IOC_POOL_STATS: 667249643Smm case ZFS_IOC_POOL_TRYIMPORT: 668219089Spjd zfs_ioctl_compat_fix_stats(zc, vec); 669219089Spjd break; 670219089Spjd case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */ 671219089Spjd zfs_ioctl_compat_pool_get_props(zc); 672219089Spjd break; 673219089Spjd } 674219089Spjd } 675219089Spjd} 676249643Smm 677249643Smmnvlist_t * 678249643Smmzfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec, 679249643Smm const int cflag) 680249643Smm{ 681249643Smm nvlist_t *nvl, *tmpnvl, *hnvl; 682249643Smm nvpair_t *elem; 683249643Smm char *poolname, *snapname; 684249643Smm int err; 685249643Smm 686249643Smm if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 687249643Smm goto out; 688249643Smm 689249643Smm switch (vec) { 690249643Smm case ZFS_IOC_CREATE: 691249643Smm nvl = fnvlist_alloc(); 692249643Smm fnvlist_add_int32(nvl, "type", zc->zc_objset_type); 693249643Smm if (innvl != NULL) { 694249643Smm fnvlist_add_nvlist(nvl, "props", innvl); 695249643Smm nvlist_free(innvl); 696249643Smm } 697249643Smm return (nvl); 698249643Smm break; 699249643Smm case ZFS_IOC_CLONE: 700249643Smm nvl = fnvlist_alloc(); 701249643Smm fnvlist_add_string(nvl, "origin", zc->zc_value); 702249643Smm if (innvl != NULL) { 703249643Smm fnvlist_add_nvlist(nvl, "props", innvl); 704249643Smm nvlist_free(innvl); 705249643Smm } 706249643Smm return (nvl); 707249643Smm break; 708249643Smm case ZFS_IOC_SNAPSHOT: 709249643Smm if (innvl == NULL) 710249643Smm goto out; 711249643Smm nvl = fnvlist_alloc(); 712249643Smm fnvlist_add_nvlist(nvl, "props", innvl); 713249643Smm tmpnvl = fnvlist_alloc(); 714249643Smm snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value); 715249643Smm fnvlist_add_boolean(tmpnvl, snapname); 716249643Smm kmem_free(snapname, strlen(snapname + 1)); 717249643Smm /* check if we are doing a recursive snapshot */ 718249643Smm if (zc->zc_cookie) 719249643Smm dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value, 720249643Smm tmpnvl); 721249643Smm fnvlist_add_nvlist(nvl, "snaps", tmpnvl); 722249643Smm fnvlist_free(tmpnvl); 723249643Smm nvlist_free(innvl); 724249643Smm /* strip dataset part from zc->zc_name */ 725249643Smm zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 726249643Smm return (nvl); 727249643Smm break; 728249643Smm case ZFS_IOC_SPACE_SNAPS: 729249643Smm nvl = fnvlist_alloc(); 730249643Smm fnvlist_add_string(nvl, "firstsnap", zc->zc_value); 731249643Smm if (innvl != NULL) 732249643Smm nvlist_free(innvl); 733249643Smm return (nvl); 734249643Smm break; 735249643Smm case ZFS_IOC_DESTROY_SNAPS: 736249643Smm if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN) 737249643Smm goto out; 738249643Smm nvl = fnvlist_alloc(); 739249643Smm if (innvl != NULL) { 740249643Smm fnvlist_add_nvlist(nvl, "snaps", innvl); 741249643Smm } else { 742249643Smm /* 743249643Smm * We are probably called by even older binaries, 744249643Smm * allocate and populate nvlist with recursive 745249643Smm * snapshots 746249643Smm */ 747263410Sdelphij if (zfs_component_namecheck(zc->zc_value, NULL, 748249643Smm NULL) == 0) { 749249643Smm tmpnvl = fnvlist_alloc(); 750249643Smm if (dmu_get_recursive_snaps_nvl(zc->zc_name, 751249643Smm zc->zc_value, tmpnvl) == 0) 752249643Smm fnvlist_add_nvlist(nvl, "snaps", 753249643Smm tmpnvl); 754249643Smm nvlist_free(tmpnvl); 755249643Smm } 756249643Smm } 757249643Smm if (innvl != NULL) 758249643Smm nvlist_free(innvl); 759249643Smm /* strip dataset part from zc->zc_name */ 760249643Smm zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 761249643Smm return (nvl); 762249643Smm break; 763249643Smm case ZFS_IOC_HOLD: 764249643Smm nvl = fnvlist_alloc(); 765249643Smm tmpnvl = fnvlist_alloc(); 766249643Smm if (zc->zc_cleanup_fd != -1) 767249643Smm fnvlist_add_int32(nvl, "cleanup_fd", 768249643Smm (int32_t)zc->zc_cleanup_fd); 769249643Smm if (zc->zc_cookie) { 770249643Smm hnvl = fnvlist_alloc(); 771249643Smm if (dmu_get_recursive_snaps_nvl(zc->zc_name, 772249643Smm zc->zc_value, hnvl) == 0) { 773249643Smm elem = NULL; 774249643Smm while ((elem = nvlist_next_nvpair(hnvl, 775249643Smm elem)) != NULL) { 776249643Smm nvlist_add_string(tmpnvl, 777249643Smm nvpair_name(elem), zc->zc_string); 778249643Smm } 779249643Smm } 780249643Smm nvlist_free(hnvl); 781249643Smm } else { 782249643Smm snapname = kmem_asprintf("%s@%s", zc->zc_name, 783249643Smm zc->zc_value); 784249643Smm nvlist_add_string(tmpnvl, snapname, zc->zc_string); 785249643Smm kmem_free(snapname, strlen(snapname + 1)); 786249643Smm } 787249643Smm fnvlist_add_nvlist(nvl, "holds", tmpnvl); 788249643Smm nvlist_free(tmpnvl); 789249643Smm if (innvl != NULL) 790249643Smm nvlist_free(innvl); 791249643Smm /* strip dataset part from zc->zc_name */ 792249643Smm zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 793249643Smm return (nvl); 794249643Smm break; 795249643Smm case ZFS_IOC_RELEASE: 796249643Smm nvl = fnvlist_alloc(); 797249643Smm tmpnvl = fnvlist_alloc(); 798249643Smm if (zc->zc_cookie) { 799249643Smm hnvl = fnvlist_alloc(); 800249643Smm if (dmu_get_recursive_snaps_nvl(zc->zc_name, 801249643Smm zc->zc_value, hnvl) == 0) { 802249643Smm elem = NULL; 803249643Smm while ((elem = nvlist_next_nvpair(hnvl, 804249643Smm elem)) != NULL) { 805249643Smm fnvlist_add_boolean(tmpnvl, 806249643Smm zc->zc_string); 807249643Smm fnvlist_add_nvlist(nvl, 808249643Smm nvpair_name(elem), tmpnvl); 809249643Smm } 810249643Smm } 811249643Smm nvlist_free(hnvl); 812249643Smm } else { 813249643Smm snapname = kmem_asprintf("%s@%s", zc->zc_name, 814249643Smm zc->zc_value); 815249643Smm fnvlist_add_boolean(tmpnvl, zc->zc_string); 816249643Smm fnvlist_add_nvlist(nvl, snapname, tmpnvl); 817249643Smm kmem_free(snapname, strlen(snapname + 1)); 818249643Smm } 819249643Smm nvlist_free(tmpnvl); 820249643Smm if (innvl != NULL) 821249643Smm nvlist_free(innvl); 822249643Smm /* strip dataset part from zc->zc_name */ 823249643Smm zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0'; 824249643Smm return (nvl); 825249643Smm break; 826249643Smm } 827249643Smmout: 828249643Smm return (innvl); 829249643Smm} 830249643Smm 831249643Smmnvlist_t * 832249643Smmzfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec, 833249643Smm const int cflag) 834249643Smm{ 835249643Smm nvlist_t *tmpnvl; 836249643Smm 837249643Smm if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC) 838249643Smm return (outnvl); 839249643Smm 840249643Smm switch (vec) { 841249643Smm case ZFS_IOC_SPACE_SNAPS: 842249643Smm (void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie); 843249643Smm (void) nvlist_lookup_uint64(outnvl, "compressed", 844249643Smm &zc->zc_objset_type); 845249643Smm (void) nvlist_lookup_uint64(outnvl, "uncompressed", 846249643Smm &zc->zc_perm_action); 847249643Smm nvlist_free(outnvl); 848249643Smm /* return empty outnvl */ 849249643Smm tmpnvl = fnvlist_alloc(); 850249643Smm return (tmpnvl); 851249643Smm break; 852249643Smm case ZFS_IOC_CREATE: 853249643Smm case ZFS_IOC_CLONE: 854249643Smm case ZFS_IOC_HOLD: 855249643Smm case ZFS_IOC_RELEASE: 856249643Smm nvlist_free(outnvl); 857249643Smm /* return empty outnvl */ 858249643Smm tmpnvl = fnvlist_alloc(); 859249643Smm return (tmpnvl); 860249643Smm break; 861249643Smm } 862249643Smm 863249643Smm return (outnvl); 864249643Smm} 865219089Spjd#endif /* KERNEL */ 866