17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5aa59c4cbSrsb  * Common Development and Distribution License (the "License").
6aa59c4cbSrsb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2197eda132Sraf 
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * System call I/F to doors (outside of vnodes I/F) and misc support
317c478bd9Sstevel@tonic-gate  * routines
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/door.h>
367c478bd9Sstevel@tonic-gate #include <sys/door_data.h>
377c478bd9Sstevel@tonic-gate #include <sys/proc.h>
387c478bd9Sstevel@tonic-gate #include <sys/thread.h>
397c478bd9Sstevel@tonic-gate #include <sys/class.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/stack.h>
447c478bd9Sstevel@tonic-gate #include <sys/debug.h>
457c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
487c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
497c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
50aa59c4cbSrsb #include <sys/vfs_opreg.h>
517c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
527c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
537c478bd9Sstevel@tonic-gate #include <sys/callb.h>
547c478bd9Sstevel@tonic-gate #include <sys/ucred.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <sys/mman.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
587c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
597c478bd9Sstevel@tonic-gate #include <vm/as.h>
607c478bd9Sstevel@tonic-gate #include <vm/hat.h>
617c478bd9Sstevel@tonic-gate #include <vm/page.h>
627c478bd9Sstevel@tonic-gate #include <vm/seg.h>
637c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
647c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
677c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
687c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
697c478bd9Sstevel@tonic-gate #include <sys/rctl.h>
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
72da6c28aaSamw  * The maximum amount of data (in bytes) that will be transferred using
737c478bd9Sstevel@tonic-gate  * an intermediate kernel buffer.  For sizes greater than this we map
747c478bd9Sstevel@tonic-gate  * in the destination pages and perform a 1-copy transfer.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate size_t	door_max_arg = 16 * 1024;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
79da6c28aaSamw  * Maximum amount of data that will be transferred in a reply to a
807c478bd9Sstevel@tonic-gate  * door_upcall.  Need to guard against a process returning huge amounts
817c478bd9Sstevel@tonic-gate  * of data and getting the kernel stuck in kmem_alloc.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate size_t	door_max_upcall_reply = 1024 * 1024;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Maximum number of descriptors allowed to be passed in a single
877c478bd9Sstevel@tonic-gate  * door_call or door_return.  We need to allocate kernel memory
887c478bd9Sstevel@tonic-gate  * for all of them at once, so we can't let it scale without limit.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate uint_t door_max_desc = 1024;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Definition of a door handle, used by other kernel subsystems when
947c478bd9Sstevel@tonic-gate  * calling door functions.  This is really a file structure but we
957c478bd9Sstevel@tonic-gate  * want to hide that fact.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate struct __door_handle {
987c478bd9Sstevel@tonic-gate 	file_t dh_file;
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	DHTOF(dh) ((file_t *)(dh))
1027c478bd9Sstevel@tonic-gate #define	FTODH(fp) ((door_handle_t)(fp))
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static int doorfs(long, long, long, long, long, long);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static struct sysent door_sysent = {
1077c478bd9Sstevel@tonic-gate 	6,
1087c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1097c478bd9Sstevel@tonic-gate 	(int (*)())doorfs,
1107c478bd9Sstevel@tonic-gate };
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1137c478bd9Sstevel@tonic-gate 	&mod_syscallops, "doors", &door_sysent
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int
1197c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
1207c478bd9Sstevel@tonic-gate     int32_t arg5, int32_t subcode);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static struct sysent door_sysent32 = {
1237c478bd9Sstevel@tonic-gate 	6,
1247c478bd9Sstevel@tonic-gate 	SE_ARGC | SE_NOUNLOAD,
1257c478bd9Sstevel@tonic-gate 	(int (*)())doorfs32,
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1297c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
1307c478bd9Sstevel@tonic-gate 	"32-bit door syscalls",
1317c478bd9Sstevel@tonic-gate 	&door_sysent32
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate #endif
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1367c478bd9Sstevel@tonic-gate 	MODREV_1,
1377c478bd9Sstevel@tonic-gate 	&modlsys,
1387c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1397c478bd9Sstevel@tonic-gate 	&modlsys32,
1407c478bd9Sstevel@tonic-gate #endif
1417c478bd9Sstevel@tonic-gate 	NULL
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate dev_t	doordev;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate extern	struct vfs door_vfs;
1477c478bd9Sstevel@tonic-gate extern	struct vnodeops *door_vnodeops;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate int
1507c478bd9Sstevel@tonic-gate _init(void)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	static const fs_operation_def_t door_vfsops_template[] = {
1537c478bd9Sstevel@tonic-gate 		NULL, NULL
1547c478bd9Sstevel@tonic-gate 	};
1557c478bd9Sstevel@tonic-gate 	extern const fs_operation_def_t door_vnodeops_template[];
1567c478bd9Sstevel@tonic-gate 	vfsops_t *door_vfsops;
1577c478bd9Sstevel@tonic-gate 	major_t major;
1587c478bd9Sstevel@tonic-gate 	int error;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	mutex_init(&door_knob, NULL, MUTEX_DEFAULT, NULL);
1617c478bd9Sstevel@tonic-gate 	if ((major = getudev()) == (major_t)-1)
1627c478bd9Sstevel@tonic-gate 		return (ENXIO);
1637c478bd9Sstevel@tonic-gate 	doordev = makedevice(major, 0);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* Create a dummy vfs */
1667c478bd9Sstevel@tonic-gate 	error = vfs_makefsops(door_vfsops_template, &door_vfsops);
1677c478bd9Sstevel@tonic-gate 	if (error != 0) {
1687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vfs ops");
1697c478bd9Sstevel@tonic-gate 		return (error);
1707c478bd9Sstevel@tonic-gate 	}
171da6c28aaSamw 	VFS_INIT(&door_vfs, door_vfsops, NULL);
1727c478bd9Sstevel@tonic-gate 	door_vfs.vfs_flag = VFS_RDONLY;
1737c478bd9Sstevel@tonic-gate 	door_vfs.vfs_dev = doordev;
1747c478bd9Sstevel@tonic-gate 	vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	error = vn_make_ops("doorfs", door_vnodeops_template, &door_vnodeops);
1777c478bd9Sstevel@tonic-gate 	if (error != 0) {
1787c478bd9Sstevel@tonic-gate 		vfs_freevfsops(door_vfsops);
1797c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "door init: bad vnode ops");
1807c478bd9Sstevel@tonic-gate 		return (error);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate int
1867c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /* system call functions */
1927c478bd9Sstevel@tonic-gate static int door_call(int, void *);
1937c478bd9Sstevel@tonic-gate static int door_return(caddr_t, size_t, door_desc_t *, uint_t, caddr_t, size_t);
1947c478bd9Sstevel@tonic-gate static int door_create(void (*pc_cookie)(void *, char *, size_t, door_desc_t *,
1957c478bd9Sstevel@tonic-gate     uint_t), void *data_cookie, uint_t);
1967c478bd9Sstevel@tonic-gate static int door_revoke(int);
1977c478bd9Sstevel@tonic-gate static int door_info(int, struct door_info *);
1987c478bd9Sstevel@tonic-gate static int door_ucred(struct ucred_s *);
1997c478bd9Sstevel@tonic-gate static int door_bind(int);
2007c478bd9Sstevel@tonic-gate static int door_unbind(void);
2017c478bd9Sstevel@tonic-gate static int door_unref(void);
2027c478bd9Sstevel@tonic-gate static int door_getparam(int, int, size_t *);
2037c478bd9Sstevel@tonic-gate static int door_setparam(int, int, size_t);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate #define	DOOR_RETURN_OLD	4		/* historic value, for s10 */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate static int
2117c478bd9Sstevel@tonic-gate doorfs(long arg1, long arg2, long arg3, long arg4, long arg5, long subcode)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	switch (subcode) {
2147c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2157c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)arg2));
2167c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2177c478bd9Sstevel@tonic-gate 		door_return_desc_t *drdp = (door_return_desc_t *)arg3;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2207c478bd9Sstevel@tonic-gate 			door_return_desc_t drd;
2217c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2227c478bd9Sstevel@tonic-gate 				return (EFAULT);
2237c478bd9Sstevel@tonic-gate 			return (door_return((caddr_t)arg1, arg2, drd.desc_ptr,
2247c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)arg4, arg5));
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, NULL,
2277c478bd9Sstevel@tonic-gate 		    0, (caddr_t)arg4, arg5));
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2307c478bd9Sstevel@tonic-gate 		/*
2317c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2327c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2337c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2347c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2357c478bd9Sstevel@tonic-gate 		 */
2367c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)arg1, arg2, (door_desc_t *)arg3,
2377c478bd9Sstevel@tonic-gate 		    arg4, (caddr_t)arg5, 0));
2387c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
2397c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())arg1, (void *)arg2, arg3));
2407c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
2417c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
2427c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
2437c478bd9Sstevel@tonic-gate 		return (door_info(arg1, (struct door_info *)arg2));
2447c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
2457c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
2467c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
2477c478bd9Sstevel@tonic-gate 		return (door_unbind());
2487c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
2497c478bd9Sstevel@tonic-gate 		return (door_unref());
2507c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
2517c478bd9Sstevel@tonic-gate 		return (door_ucred((struct ucred_s *)arg1));
2527c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
2537c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2, (size_t *)arg3));
2547c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
2557c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, arg3));
2567c478bd9Sstevel@tonic-gate 	default:
2577c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * System call wrapper for all door related system calls from 32-bit programs.
2647c478bd9Sstevel@tonic-gate  * Needed at the moment because of the casts - they undo some damage
2657c478bd9Sstevel@tonic-gate  * that truss causes (sign-extending the stack pointer) when truss'ing
2667c478bd9Sstevel@tonic-gate  * a 32-bit program using doors.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate static int
2697c478bd9Sstevel@tonic-gate doorfs32(int32_t arg1, int32_t arg2, int32_t arg3,
2707c478bd9Sstevel@tonic-gate     int32_t arg4, int32_t arg5, int32_t subcode)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	switch (subcode) {
2737c478bd9Sstevel@tonic-gate 	case DOOR_CALL:
2747c478bd9Sstevel@tonic-gate 		return (door_call(arg1, (void *)(uintptr_t)(caddr32_t)arg2));
2757c478bd9Sstevel@tonic-gate 	case DOOR_RETURN: {
2767c478bd9Sstevel@tonic-gate 		door_return_desc32_t *drdp =
2777c478bd9Sstevel@tonic-gate 		    (door_return_desc32_t *)(uintptr_t)(caddr32_t)arg3;
2787c478bd9Sstevel@tonic-gate 		if (drdp != NULL) {
2797c478bd9Sstevel@tonic-gate 			door_return_desc32_t drd;
2807c478bd9Sstevel@tonic-gate 			if (copyin(drdp, &drd, sizeof (drd)))
2817c478bd9Sstevel@tonic-gate 				return (EFAULT);
2827c478bd9Sstevel@tonic-gate 			return (door_return(
2837c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
2847c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)drd.desc_ptr,
2857c478bd9Sstevel@tonic-gate 			    drd.desc_num, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2867c478bd9Sstevel@tonic-gate 			    (size_t)(uintptr_t)(size32_t)arg5));
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1,
2897c478bd9Sstevel@tonic-gate 		    arg2, NULL, 0, (caddr_t)(uintptr_t)(caddr32_t)arg4,
2907c478bd9Sstevel@tonic-gate 		    (size_t)(uintptr_t)(size32_t)arg5));
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	case DOOR_RETURN_OLD:
2937c478bd9Sstevel@tonic-gate 		/*
2947c478bd9Sstevel@tonic-gate 		 * In order to support the S10 runtime environment, we
2957c478bd9Sstevel@tonic-gate 		 * still respond to the old syscall subcode for door_return.
2967c478bd9Sstevel@tonic-gate 		 * We treat it as having no stack limits.  This code should
2977c478bd9Sstevel@tonic-gate 		 * be removed when such support is no longer needed.
2987c478bd9Sstevel@tonic-gate 		 */
2997c478bd9Sstevel@tonic-gate 		return (door_return((caddr_t)(uintptr_t)(caddr32_t)arg1, arg2,
3007c478bd9Sstevel@tonic-gate 		    (door_desc_t *)(uintptr_t)(caddr32_t)arg3, arg4,
3017c478bd9Sstevel@tonic-gate 		    (caddr_t)(uintptr_t)(caddr32_t)arg5, 0));
3027c478bd9Sstevel@tonic-gate 	case DOOR_CREATE:
3037c478bd9Sstevel@tonic-gate 		return (door_create((void (*)())(uintptr_t)(caddr32_t)arg1,
3047c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)(caddr32_t)arg2, arg3));
3057c478bd9Sstevel@tonic-gate 	case DOOR_REVOKE:
3067c478bd9Sstevel@tonic-gate 		return (door_revoke(arg1));
3077c478bd9Sstevel@tonic-gate 	case DOOR_INFO:
3087c478bd9Sstevel@tonic-gate 		return (door_info(arg1,
3097c478bd9Sstevel@tonic-gate 		    (struct door_info *)(uintptr_t)(caddr32_t)arg2));
3107c478bd9Sstevel@tonic-gate 	case DOOR_BIND:
3117c478bd9Sstevel@tonic-gate 		return (door_bind(arg1));
3127c478bd9Sstevel@tonic-gate 	case DOOR_UNBIND:
3137c478bd9Sstevel@tonic-gate 		return (door_unbind());
3147c478bd9Sstevel@tonic-gate 	case DOOR_UNREFSYS:
3157c478bd9Sstevel@tonic-gate 		return (door_unref());
3167c478bd9Sstevel@tonic-gate 	case DOOR_UCRED:
3177c478bd9Sstevel@tonic-gate 		return (door_ucred(
3187c478bd9Sstevel@tonic-gate 		    (struct ucred_s *)(uintptr_t)(caddr32_t)arg1));
3197c478bd9Sstevel@tonic-gate 	case DOOR_GETPARAM:
3207c478bd9Sstevel@tonic-gate 		return (door_getparam(arg1, arg2,
3217c478bd9Sstevel@tonic-gate 		    (size_t *)(uintptr_t)(caddr32_t)arg3));
3227c478bd9Sstevel@tonic-gate 	case DOOR_SETPARAM:
3237c478bd9Sstevel@tonic-gate 		return (door_setparam(arg1, arg2, (size_t)(size32_t)arg3));
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	default:
3267c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate #endif
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate void shuttle_resume(kthread_t *, kmutex_t *);
3327c478bd9Sstevel@tonic-gate void shuttle_swtch(kmutex_t *);
3337c478bd9Sstevel@tonic-gate void shuttle_sleep(kthread_t *);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * Support routines
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate static int door_create_common(void (*)(), void *, uint_t, int, int *,
3397c478bd9Sstevel@tonic-gate     file_t **);
3407c478bd9Sstevel@tonic-gate static int door_overflow(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3417c478bd9Sstevel@tonic-gate static int door_args(kthread_t *, int);
3427c478bd9Sstevel@tonic-gate static int door_results(kthread_t *, caddr_t, size_t, door_desc_t *, uint_t);
3437c478bd9Sstevel@tonic-gate static int door_copy(struct as *, caddr_t, caddr_t, uint_t);
344c4ace179Sdm static void	door_server_exit(proc_t *, kthread_t *);
3457c478bd9Sstevel@tonic-gate static void	door_release_server(door_node_t *, kthread_t *);
3467c478bd9Sstevel@tonic-gate static kthread_t	*door_get_server(door_node_t *);
3477c478bd9Sstevel@tonic-gate static door_node_t	*door_lookup(int, file_t **);
3487c478bd9Sstevel@tonic-gate static int	door_translate_in(void);
3497c478bd9Sstevel@tonic-gate static int	door_translate_out(void);
3507c478bd9Sstevel@tonic-gate static void	door_fd_rele(door_desc_t *, uint_t, int);
3517c478bd9Sstevel@tonic-gate static void	door_list_insert(door_node_t *);
3527c478bd9Sstevel@tonic-gate static void	door_info_common(door_node_t *, door_info_t *, file_t *);
3537c478bd9Sstevel@tonic-gate static int	door_release_fds(door_desc_t *, uint_t);
3547c478bd9Sstevel@tonic-gate static void	door_fd_close(door_desc_t *, uint_t);
3557c478bd9Sstevel@tonic-gate static void	door_fp_close(struct file **, uint_t);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static door_data_t *
3587c478bd9Sstevel@tonic-gate door_my_data(int create_if_missing)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	door_data_t *ddp;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	ddp = curthread->t_door;
3637c478bd9Sstevel@tonic-gate 	if (create_if_missing && ddp == NULL)
3647c478bd9Sstevel@tonic-gate 		ddp = curthread->t_door = kmem_zalloc(sizeof (*ddp), KM_SLEEP);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	return (ddp);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static door_server_t *
3707c478bd9Sstevel@tonic-gate door_my_server(int create_if_missing)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_SERVER(ddp) : NULL);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static door_client_t *
3787c478bd9Sstevel@tonic-gate door_my_client(int create_if_missing)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	door_data_t *ddp = door_my_data(create_if_missing);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	return ((ddp != NULL)? DOOR_CLIENT(ddp) : NULL);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * System call to create a door
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate int
3897c478bd9Sstevel@tonic-gate door_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	int fd;
3927c478bd9Sstevel@tonic-gate 	int err;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_CREATE_MASK) ||
3957c478bd9Sstevel@tonic-gate 	    ((attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
3967c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI)))
3977c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if ((err = door_create_common(pc_cookie, data_cookie, attributes, 0,
4007c478bd9Sstevel@tonic-gate 	    &fd, NULL)) != 0)
4017c478bd9Sstevel@tonic-gate 		return (set_errno(err));
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	f_setfd(fd, FD_CLOEXEC);
4047c478bd9Sstevel@tonic-gate 	return (fd);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * Common code for creating user and kernel doors.  If a door was
4097c478bd9Sstevel@tonic-gate  * created, stores a file structure pointer in the location pointed
4107c478bd9Sstevel@tonic-gate  * to by fpp (if fpp is non-NULL) and returns 0.  Also, if a non-NULL
4117c478bd9Sstevel@tonic-gate  * pointer to a file descriptor is passed in as fdp, allocates a file
4127c478bd9Sstevel@tonic-gate  * descriptor representing the door.  If a door could not be created,
4137c478bd9Sstevel@tonic-gate  * returns an error.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static int
4167c478bd9Sstevel@tonic-gate door_create_common(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
4177c478bd9Sstevel@tonic-gate     int from_kernel, int *fdp, file_t **fpp)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
4207c478bd9Sstevel@tonic-gate 	vnode_t		*vp;
4217c478bd9Sstevel@tonic-gate 	struct file	*fp;
4227c478bd9Sstevel@tonic-gate 	static door_id_t index = 0;
4237c478bd9Sstevel@tonic-gate 	proc_t		*p = (from_kernel)? &p0 : curproc;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	dp = kmem_zalloc(sizeof (door_node_t), KM_SLEEP);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	dp->door_vnode = vn_alloc(KM_SLEEP);
4287c478bd9Sstevel@tonic-gate 	dp->door_target = p;
4297c478bd9Sstevel@tonic-gate 	dp->door_data = data_cookie;
4307c478bd9Sstevel@tonic-gate 	dp->door_pc = pc_cookie;
4317c478bd9Sstevel@tonic-gate 	dp->door_flags = attributes;
4327c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
4337c478bd9Sstevel@tonic-gate 	if (!from_kernel && get_udatamodel() != DATAMODEL_NATIVE)
4347c478bd9Sstevel@tonic-gate 		dp->door_data_max = UINT32_MAX;
4357c478bd9Sstevel@tonic-gate 	else
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate 		dp->door_data_max = SIZE_MAX;
4387c478bd9Sstevel@tonic-gate 	dp->door_data_min = 0UL;
4397c478bd9Sstevel@tonic-gate 	dp->door_desc_max = (attributes & DOOR_REFUSE_DESC)? 0 : INT_MAX;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	vp = DTOV(dp);
4427c478bd9Sstevel@tonic-gate 	vn_setops(vp, door_vnodeops);
4437c478bd9Sstevel@tonic-gate 	vp->v_type = VDOOR;
4447c478bd9Sstevel@tonic-gate 	vp->v_vfsp = &door_vfs;
4457c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)dp;
4467c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
4477c478bd9Sstevel@tonic-gate 	dp->door_index = index++;
4487c478bd9Sstevel@tonic-gate 	/* add to per-process door list */
4497c478bd9Sstevel@tonic-gate 	door_list_insert(dp);
4507c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (falloc(vp, FREAD | FWRITE, &fp, fdp)) {
4537c478bd9Sstevel@tonic-gate 		/*
4547c478bd9Sstevel@tonic-gate 		 * If the file table is full, remove the door from the
4557c478bd9Sstevel@tonic-gate 		 * per-process list, free the door, and return NULL.
4567c478bd9Sstevel@tonic-gate 		 */
4577c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
4587c478bd9Sstevel@tonic-gate 		door_list_delete(dp);
4597c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
4607c478bd9Sstevel@tonic-gate 		vn_free(vp);
4617c478bd9Sstevel@tonic-gate 		kmem_free(dp, sizeof (door_node_t));
4627c478bd9Sstevel@tonic-gate 		return (EMFILE);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 	vn_exists(vp);
4657c478bd9Sstevel@tonic-gate 	if (fdp != NULL)
4667c478bd9Sstevel@tonic-gate 		setf(*fdp, fp);
4677c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
4707c478bd9Sstevel@tonic-gate 		*fpp = fp;
4717c478bd9Sstevel@tonic-gate 	return (0);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate static int
4757c478bd9Sstevel@tonic-gate door_check_limits(door_node_t *dp, door_arg_t *da, int upcall)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* we allow unref upcalls through, despite any minimum */
4807c478bd9Sstevel@tonic-gate 	if (da->data_size < dp->door_data_min &&
4817c478bd9Sstevel@tonic-gate 	    !(upcall && da->data_ptr == DOOR_UNREF_DATA))
4827c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (da->data_size > dp->door_data_max)
4857c478bd9Sstevel@tonic-gate 		return (ENOBUFS);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (da->desc_num > 0 && (dp->door_flags & DOOR_REFUSE_DESC))
4887c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (da->desc_num > dp->door_desc_max)
4917c478bd9Sstevel@tonic-gate 		return (ENFILE);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (0);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * Door invocation.
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate int
5007c478bd9Sstevel@tonic-gate door_call(int did, void *args)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	/* Locals */
5037c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
5047c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
5057c478bd9Sstevel@tonic-gate 	int		error = 0;
5067c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
5077c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
5087c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
5097c478bd9Sstevel@tonic-gate 	door_desc_t	*start = NULL;
5107c478bd9Sstevel@tonic-gate 	uint_t		ncopied = 0;
5117c478bd9Sstevel@tonic-gate 	size_t		dsize;
5127c478bd9Sstevel@tonic-gate 	/* destructor for data returned by a kernel server */
5137c478bd9Sstevel@tonic-gate 	void		(*destfn)() = NULL;
5147c478bd9Sstevel@tonic-gate 	void		*destarg;
5157c478bd9Sstevel@tonic-gate 	model_t		datamodel;
5167c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
517a574db85Sraf 	int		cancel_pending;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
5207c478bd9Sstevel@tonic-gate 	datamodel = lwp_getdatamodel(lwp);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/*
5257c478bd9Sstevel@tonic-gate 	 * Get the arguments
5267c478bd9Sstevel@tonic-gate 	 */
5277c478bd9Sstevel@tonic-gate 	if (args) {
5287c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
5297c478bd9Sstevel@tonic-gate 			if (copyin(args, &ct->d_args, sizeof (door_arg_t)) != 0)
5307c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5317c478bd9Sstevel@tonic-gate 		} else {
5327c478bd9Sstevel@tonic-gate 			door_arg32_t    da32;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 			if (copyin(args, &da32, sizeof (door_arg32_t)) != 0)
5357c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
5367c478bd9Sstevel@tonic-gate 			ct->d_args.data_ptr =
5377c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.data_ptr;
5387c478bd9Sstevel@tonic-gate 			ct->d_args.data_size = da32.data_size;
5397c478bd9Sstevel@tonic-gate 			ct->d_args.desc_ptr =
5407c478bd9Sstevel@tonic-gate 			    (door_desc_t *)(uintptr_t)da32.desc_ptr;
5417c478bd9Sstevel@tonic-gate 			ct->d_args.desc_num = da32.desc_num;
5427c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf =
5437c478bd9Sstevel@tonic-gate 			    (char *)(uintptr_t)da32.rbuf;
5447c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = da32.rsize;
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 	} else {
5477c478bd9Sstevel@tonic-gate 		/* No arguments, and no results allowed */
5487c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
5497c478bd9Sstevel@tonic-gate 		ct->d_args.data_size = 0;
5507c478bd9Sstevel@tonic-gate 		ct->d_args.desc_num = 0;
5517c478bd9Sstevel@tonic-gate 		ct->d_args.rsize = 0;
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
5557c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
5567c478bd9Sstevel@tonic-gate 
557*289175a0Sjwadams 	/*
558*289175a0Sjwadams 	 * We don't want to hold the door FD over the entire operation;
559*289175a0Sjwadams 	 * instead, we put a hold on the door vnode and release the FD
560*289175a0Sjwadams 	 * immediately
561*289175a0Sjwadams 	 */
562*289175a0Sjwadams 	VN_HOLD(DTOV(dp));
563*289175a0Sjwadams 	releasef(did);
564*289175a0Sjwadams 
5657c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
5667c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
5677c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5687c478bd9Sstevel@tonic-gate 		error = EBADF;
5697c478bd9Sstevel@tonic-gate 		goto out;
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	/*
5737c478bd9Sstevel@tonic-gate 	 * before we do anything, check that we are not overflowing the
5747c478bd9Sstevel@tonic-gate 	 * required limits.
5757c478bd9Sstevel@tonic-gate 	 */
5767c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, &ct->d_args, 0);
5777c478bd9Sstevel@tonic-gate 	if (error != 0) {
5787c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5797c478bd9Sstevel@tonic-gate 		goto out;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * Check for in-kernel door server.
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
5867c478bd9Sstevel@tonic-gate 		caddr_t rbuf = ct->d_args.rbuf;
5877c478bd9Sstevel@tonic-gate 		size_t rsize = ct->d_args.rsize;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		dp->door_active++;
5907c478bd9Sstevel@tonic-gate 		ct->d_kernel = 1;
5917c478bd9Sstevel@tonic-gate 		ct->d_error = DOOR_WAIT;
5927c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
5937c478bd9Sstevel@tonic-gate 		/* translate file descriptors to vnodes */
5947c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
5957c478bd9Sstevel@tonic-gate 			error = door_translate_in();
5967c478bd9Sstevel@tonic-gate 			if (error)
5977c478bd9Sstevel@tonic-gate 				goto out;
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 		/*
6007c478bd9Sstevel@tonic-gate 		 * Call kernel door server.  Arguments are passed and
6017c478bd9Sstevel@tonic-gate 		 * returned as a door_arg pointer.  When called, data_ptr
6027c478bd9Sstevel@tonic-gate 		 * points to user data and desc_ptr points to a kernel list
6037c478bd9Sstevel@tonic-gate 		 * of door descriptors that have been converted to file
6047c478bd9Sstevel@tonic-gate 		 * structure pointers.  It's the server function's
6057c478bd9Sstevel@tonic-gate 		 * responsibility to copyin the data pointed to by data_ptr
6067c478bd9Sstevel@tonic-gate 		 * (this avoids extra copying in some cases).  On return,
6077c478bd9Sstevel@tonic-gate 		 * data_ptr points to a user buffer of data, and desc_ptr
6087c478bd9Sstevel@tonic-gate 		 * points to a kernel list of door descriptors representing
6097c478bd9Sstevel@tonic-gate 		 * files.  When a reference is passed to a kernel server,
6107c478bd9Sstevel@tonic-gate 		 * it is the server's responsibility to release the reference
6117c478bd9Sstevel@tonic-gate 		 * (by calling closef).  When the server includes a
6127c478bd9Sstevel@tonic-gate 		 * reference in its reply, it is released as part of the
6137c478bd9Sstevel@tonic-gate 		 * the call (the server must duplicate the reference if
6147c478bd9Sstevel@tonic-gate 		 * it wants to retain a copy).  The destfn, if set to
6157c478bd9Sstevel@tonic-gate 		 * non-NULL, is a destructor to be called when the returned
6167c478bd9Sstevel@tonic-gate 		 * kernel data (if any) is no longer needed (has all been
6177c478bd9Sstevel@tonic-gate 		 * translated and copied to user level).
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &ct->d_args,
6207c478bd9Sstevel@tonic-gate 		    &destfn, &destarg, &error);
6217c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6227c478bd9Sstevel@tonic-gate 		/* not implemented yet */
6237c478bd9Sstevel@tonic-gate 		if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
6247c478bd9Sstevel@tonic-gate 			door_deliver_unref(dp);
6257c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6267c478bd9Sstevel@tonic-gate 		if (error)
6277c478bd9Sstevel@tonic-gate 			goto out;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		/* translate vnodes to files */
6307c478bd9Sstevel@tonic-gate 		if (ct->d_args.desc_num) {
6317c478bd9Sstevel@tonic-gate 			error = door_translate_out();
6327c478bd9Sstevel@tonic-gate 			if (error)
6337c478bd9Sstevel@tonic-gate 				goto out;
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		ct->d_buf = ct->d_args.rbuf;
6367c478bd9Sstevel@tonic-gate 		ct->d_bufsize = ct->d_args.rsize;
6377c478bd9Sstevel@tonic-gate 		if (rsize < (ct->d_args.data_size +
6387c478bd9Sstevel@tonic-gate 		    (ct->d_args.desc_num * sizeof (door_desc_t)))) {
6397c478bd9Sstevel@tonic-gate 			/* handle overflow */
6407c478bd9Sstevel@tonic-gate 			error = door_overflow(curthread, ct->d_args.data_ptr,
6417c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size, ct->d_args.desc_ptr,
6427c478bd9Sstevel@tonic-gate 			    ct->d_args.desc_num);
6437c478bd9Sstevel@tonic-gate 			if (error)
6447c478bd9Sstevel@tonic-gate 				goto out;
6457c478bd9Sstevel@tonic-gate 			/* door_overflow sets d_args rbuf and rsize */
6467c478bd9Sstevel@tonic-gate 		} else {
6477c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = rbuf;
6487c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = rsize;
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 		goto results;
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/*
6547c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
6557c478bd9Sstevel@tonic-gate 	 */
6567c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
6577c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
6587c478bd9Sstevel@tonic-gate 			error = EBADF;
6597c478bd9Sstevel@tonic-gate 		else
6607c478bd9Sstevel@tonic-gate 			error = EAGAIN;
6617c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6627c478bd9Sstevel@tonic-gate 		goto out;
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
6667c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num || ct->d_args.data_size) {
6677c478bd9Sstevel@tonic-gate 		int is_private = (dp->door_flags & DOOR_PRIVATE);
6687c478bd9Sstevel@tonic-gate 		/*
6697c478bd9Sstevel@tonic-gate 		 * Move data from client to server
6707c478bd9Sstevel@tonic-gate 		 */
6717c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
6727c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
6737c478bd9Sstevel@tonic-gate 		error = door_args(server_thread, is_private);
6747c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
6757c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
6767c478bd9Sstevel@tonic-gate 		if (error) {
6777c478bd9Sstevel@tonic-gate 			/*
6787c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
6797c478bd9Sstevel@tonic-gate 			 */
6807c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
6817c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
6827c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
6837c478bd9Sstevel@tonic-gate 			goto out;
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	dp->door_active++;
6887c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
689*289175a0Sjwadams 	ct->d_args_done = 0;
6907c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
6917c478bd9Sstevel@tonic-gate 	st->d_active = dp;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
6967c478bd9Sstevel@tonic-gate shuttle_return:
6977c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
6987c478bd9Sstevel@tonic-gate 		/*
6997c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
7007c478bd9Sstevel@tonic-gate 		 */
7017c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
702a574db85Sraf 		cancel_pending = 0;
703a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
704a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
705a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
7067c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
7077c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
708a574db85Sraf 			if (cancel_pending)
709a574db85Sraf 				schedctl_cancel_eintr();
7107c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7117c478bd9Sstevel@tonic-gate 			error = EINTR;
7127c478bd9Sstevel@tonic-gate 			/*
7137c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
7147c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
7157c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
7167c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
7177c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
7187c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
7197c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
7207c478bd9Sstevel@tonic-gate 			 */
7217c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
7227c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
7237c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
7267c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
7297c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
7307c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
7337c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
7347c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
7377c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
7387c478bd9Sstevel@tonic-gate 				}
7397c478bd9Sstevel@tonic-gate 			}
7407c478bd9Sstevel@tonic-gate 		} else {
7417c478bd9Sstevel@tonic-gate 			/*
7427c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
7437c478bd9Sstevel@tonic-gate 			 *
7447c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
7457c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
7467c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
7477c478bd9Sstevel@tonic-gate 			 * is updated by the server.
7487c478bd9Sstevel@tonic-gate 			 */
7497c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
7507c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
7517c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
7527c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
7537c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
7547c478bd9Sstevel@tonic-gate 				lwp->lwp_asleep = 0;
7557c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
7567c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
7577c478bd9Sstevel@tonic-gate 				/* Server exit */
7587c478bd9Sstevel@tonic-gate 				error = EINTR;
7597c478bd9Sstevel@tonic-gate 			} else {
7607c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
7617c478bd9Sstevel@tonic-gate 				error = ct->d_error;
7627c478bd9Sstevel@tonic-gate 			}
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 		/*
7657c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
7667c478bd9Sstevel@tonic-gate 		 * results for me.
7677c478bd9Sstevel@tonic-gate 		 */
7687c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
7697c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
7707c478bd9Sstevel@tonic-gate 
771*289175a0Sjwadams 		/*
772*289175a0Sjwadams 		 * If the server has not processed our message, free the
773*289175a0Sjwadams 		 * descriptors.
774*289175a0Sjwadams 		 */
775*289175a0Sjwadams 		if (!ct->d_args_done) {
776*289175a0Sjwadams 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
777*289175a0Sjwadams 			ct->d_args_done = 1;
778*289175a0Sjwadams 		}
779*289175a0Sjwadams 
7807c478bd9Sstevel@tonic-gate 		/*
7817c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
7827c478bd9Sstevel@tonic-gate 		 */
7837c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
7847c478bd9Sstevel@tonic-gate 			gotresults = 1;
7857c478bd9Sstevel@tonic-gate 	}
786*289175a0Sjwadams 	ASSERT(ct->d_args_done);
7877c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;		/* /proc */
7887c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;		/* /proc */
7897c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
7907c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
7917c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate results:
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * Move the results to userland (if any)
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
7997c478bd9Sstevel@tonic-gate 		goto out;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	if (error) {
8027c478bd9Sstevel@tonic-gate 		/*
8037c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
8047c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
8057c478bd9Sstevel@tonic-gate 		 */
8067c478bd9Sstevel@tonic-gate 		if (gotresults) {
8077c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
8087c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 		goto out;
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	/*
8147c478bd9Sstevel@tonic-gate 	 * Copy back data if we haven't caused an overflow (already
8157c478bd9Sstevel@tonic-gate 	 * handled) and we are using a 2 copy transfer, or we are
8167c478bd9Sstevel@tonic-gate 	 * returning data from a kernel server.
8177c478bd9Sstevel@tonic-gate 	 */
8187c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size) {
8197c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
8207c478bd9Sstevel@tonic-gate 		if (ct->d_kernel || (!ct->d_overflow &&
8217c478bd9Sstevel@tonic-gate 		    ct->d_args.data_size <= door_max_arg)) {
822*289175a0Sjwadams 			if (copyout_nowatch(ct->d_buf, ct->d_args.rbuf,
8237c478bd9Sstevel@tonic-gate 			    ct->d_args.data_size)) {
8247c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, ct->d_args.desc_num);
8257c478bd9Sstevel@tonic-gate 				error = EFAULT;
8267c478bd9Sstevel@tonic-gate 				goto out;
8277c478bd9Sstevel@tonic-gate 			}
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	/*
8327c478bd9Sstevel@tonic-gate 	 * stuff returned doors into our proc, copyout the descriptors
8337c478bd9Sstevel@tonic-gate 	 */
8347c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
8357c478bd9Sstevel@tonic-gate 		struct file	**fpp;
8367c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
8377c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		dsize = n * sizeof (door_desc_t);
8407c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
8417c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		while (n--) {
8447c478bd9Sstevel@tonic-gate 			if (door_insert(*fpp, didpp) == -1) {
8457c478bd9Sstevel@tonic-gate 				/* Close remaining files */
8467c478bd9Sstevel@tonic-gate 				door_fp_close(fpp, n + 1);
8477c478bd9Sstevel@tonic-gate 				error = EMFILE;
8487c478bd9Sstevel@tonic-gate 				goto out;
8497c478bd9Sstevel@tonic-gate 			}
8507c478bd9Sstevel@tonic-gate 			fpp++; didpp++; ncopied++;
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
8547c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
8557c478bd9Sstevel@tonic-gate 
856*289175a0Sjwadams 		if (copyout_nowatch(start, ct->d_args.desc_ptr, dsize)) {
8577c478bd9Sstevel@tonic-gate 			error = EFAULT;
8587c478bd9Sstevel@tonic-gate 			goto out;
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/*
8637c478bd9Sstevel@tonic-gate 	 * Return the results
8647c478bd9Sstevel@tonic-gate 	 */
8657c478bd9Sstevel@tonic-gate 	if (datamodel == DATAMODEL_NATIVE) {
866*289175a0Sjwadams 		if (copyout_nowatch(&ct->d_args, args,
867*289175a0Sjwadams 		    sizeof (door_arg_t)) != 0)
8687c478bd9Sstevel@tonic-gate 			error = EFAULT;
8697c478bd9Sstevel@tonic-gate 	} else {
8707c478bd9Sstevel@tonic-gate 		door_arg32_t    da32;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 		da32.data_ptr = (caddr32_t)(uintptr_t)ct->d_args.data_ptr;
8737c478bd9Sstevel@tonic-gate 		da32.data_size = ct->d_args.data_size;
8747c478bd9Sstevel@tonic-gate 		da32.desc_ptr = (caddr32_t)(uintptr_t)ct->d_args.desc_ptr;
8757c478bd9Sstevel@tonic-gate 		da32.desc_num = ct->d_args.desc_num;
8767c478bd9Sstevel@tonic-gate 		da32.rbuf = (caddr32_t)(uintptr_t)ct->d_args.rbuf;
8777c478bd9Sstevel@tonic-gate 		da32.rsize = ct->d_args.rsize;
878*289175a0Sjwadams 		if (copyout_nowatch(&da32, args, sizeof (door_arg32_t)) != 0) {
8797c478bd9Sstevel@tonic-gate 			error = EFAULT;
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate out:
8847c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	/* clean up the overflow buffer if an error occurred */
8877c478bd9Sstevel@tonic-gate 	if (error != 0 && ct->d_overflow) {
8887c478bd9Sstevel@tonic-gate 		(void) as_unmap(curproc->p_as, ct->d_args.rbuf,
8897c478bd9Sstevel@tonic-gate 		    ct->d_args.rsize);
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 	ct->d_overflow = 0;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* call destructor */
8947c478bd9Sstevel@tonic-gate 	if (destfn) {
8957c478bd9Sstevel@tonic-gate 		ASSERT(ct->d_kernel);
8967c478bd9Sstevel@tonic-gate 		(*destfn)(dp->door_data, destarg);
8977c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
8987c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	if (dp)
902*289175a0Sjwadams 		VN_RELE(DTOV(dp));
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if (ct->d_buf) {
9057c478bd9Sstevel@tonic-gate 		ASSERT(!ct->d_kernel);
9067c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_buf, ct->d_bufsize);
9077c478bd9Sstevel@tonic-gate 		ct->d_buf = NULL;
9087c478bd9Sstevel@tonic-gate 		ct->d_bufsize = 0;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 	ct->d_kernel = 0;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	/* clean up the descriptor copyout buffer */
9137c478bd9Sstevel@tonic-gate 	if (start != NULL) {
9147c478bd9Sstevel@tonic-gate 		if (error != 0)
9157c478bd9Sstevel@tonic-gate 			door_fd_close(start, ncopied);
9167c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
9207c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
9217c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
9227c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if (error)
9267c478bd9Sstevel@tonic-gate 		return (set_errno(error));
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	return (0);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate static int
9327c478bd9Sstevel@tonic-gate door_setparam_common(door_node_t *dp, int from_kernel, int type, size_t val)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate 	int error = 0;
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
9397c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9407c478bd9Sstevel@tonic-gate 		return (EBADF);
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	/*
9447c478bd9Sstevel@tonic-gate 	 * door_ki_setparam() can only affect kernel doors.
9457c478bd9Sstevel@tonic-gate 	 * door_setparam() can only affect doors attached to the current
9467c478bd9Sstevel@tonic-gate 	 * process.
9477c478bd9Sstevel@tonic-gate 	 */
9487c478bd9Sstevel@tonic-gate 	if ((from_kernel && dp->door_target != &p0) ||
9497c478bd9Sstevel@tonic-gate 	    (!from_kernel && dp->door_target != curproc)) {
9507c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
9517c478bd9Sstevel@tonic-gate 		return (EPERM);
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	switch (type) {
9557c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
9567c478bd9Sstevel@tonic-gate 		if (val > INT_MAX)
9577c478bd9Sstevel@tonic-gate 			error = ERANGE;
9587c478bd9Sstevel@tonic-gate 		else if ((dp->door_flags & DOOR_REFUSE_DESC) && val != 0)
9597c478bd9Sstevel@tonic-gate 			error = ENOTSUP;
9607c478bd9Sstevel@tonic-gate 		else
9617c478bd9Sstevel@tonic-gate 			dp->door_desc_max = (uint_t)val;
9627c478bd9Sstevel@tonic-gate 		break;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
9657c478bd9Sstevel@tonic-gate 		if (val > dp->door_data_max)
9667c478bd9Sstevel@tonic-gate 			error = EINVAL;
9677c478bd9Sstevel@tonic-gate 		else
9687c478bd9Sstevel@tonic-gate 			dp->door_data_min = val;
9697c478bd9Sstevel@tonic-gate 		break;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
9727c478bd9Sstevel@tonic-gate 		if (val < dp->door_data_min)
9737c478bd9Sstevel@tonic-gate 			error = EINVAL;
9747c478bd9Sstevel@tonic-gate 		else
9757c478bd9Sstevel@tonic-gate 			dp->door_data_max = val;
9767c478bd9Sstevel@tonic-gate 		break;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	default:
9797c478bd9Sstevel@tonic-gate 		error = EINVAL;
9807c478bd9Sstevel@tonic-gate 		break;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
9847c478bd9Sstevel@tonic-gate 	return (error);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate static int
9887c478bd9Sstevel@tonic-gate door_getparam_common(door_node_t *dp, int type, size_t *out)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	int error = 0;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
9937c478bd9Sstevel@tonic-gate 	switch (type) {
9947c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DESC_MAX:
9957c478bd9Sstevel@tonic-gate 		*out = (size_t)dp->door_desc_max;
9967c478bd9Sstevel@tonic-gate 		break;
9977c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MIN:
9987c478bd9Sstevel@tonic-gate 		*out = dp->door_data_min;
9997c478bd9Sstevel@tonic-gate 		break;
10007c478bd9Sstevel@tonic-gate 	case DOOR_PARAM_DATA_MAX:
10017c478bd9Sstevel@tonic-gate 		*out = dp->door_data_max;
10027c478bd9Sstevel@tonic-gate 		break;
10037c478bd9Sstevel@tonic-gate 	default:
10047c478bd9Sstevel@tonic-gate 		error = EINVAL;
10057c478bd9Sstevel@tonic-gate 		break;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
10087c478bd9Sstevel@tonic-gate 	return (error);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate int
10127c478bd9Sstevel@tonic-gate door_setparam(int did, int type, size_t val)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate 	door_node_t *dp;
10157c478bd9Sstevel@tonic-gate 	int error = 0;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
10187c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	error = door_setparam_common(dp, 0, type, val);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	releasef(did);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (error)
10257c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	return (0);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate int
10317c478bd9Sstevel@tonic-gate door_getparam(int did, int type, size_t *out)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	door_node_t *dp;
10347c478bd9Sstevel@tonic-gate 	size_t val = 0;
10357c478bd9Sstevel@tonic-gate 	int error = 0;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL)
10387c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	error = door_getparam_common(dp, type, &val);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	releasef(did);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if (error)
10457c478bd9Sstevel@tonic-gate 		return (set_errno(error));
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
10487c478bd9Sstevel@tonic-gate 		if (copyout(&val, out, sizeof (val)))
10497c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10507c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10517c478bd9Sstevel@tonic-gate 	} else {
10527c478bd9Sstevel@tonic-gate 		size32_t val32 = (size32_t)val;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 		if (val != val32)
10557c478bd9Sstevel@tonic-gate 			return (set_errno(EOVERFLOW));
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 		if (copyout(&val32, out, sizeof (val32)))
10587c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
10597c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	return (0);
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate /*
10667c478bd9Sstevel@tonic-gate  * A copyout() which proceeds from high addresses to low addresses.  This way,
10677c478bd9Sstevel@tonic-gate  * stack guard pages are effective.
1068*289175a0Sjwadams  *
1069*289175a0Sjwadams  * Note that we use copyout_nowatch();  this is called while the client is
1070*289175a0Sjwadams  * held.
10717c478bd9Sstevel@tonic-gate  */
10727c478bd9Sstevel@tonic-gate static int
10737c478bd9Sstevel@tonic-gate door_stack_copyout(const void *kaddr, void *uaddr, size_t count)
10747c478bd9Sstevel@tonic-gate {
10757c478bd9Sstevel@tonic-gate 	const char *kbase = (const char *)kaddr;
10767c478bd9Sstevel@tonic-gate 	uintptr_t ubase = (uintptr_t)uaddr;
10777c478bd9Sstevel@tonic-gate 	size_t pgsize = PAGESIZE;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if (count <= pgsize)
1080*289175a0Sjwadams 		return (copyout_nowatch(kaddr, uaddr, count));
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	while (count > 0) {
10837c478bd9Sstevel@tonic-gate 		uintptr_t start, end, offset, amount;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 		end = ubase + count;
10867c478bd9Sstevel@tonic-gate 		start = P2ALIGN(end - 1, pgsize);
10877c478bd9Sstevel@tonic-gate 		if (P2ALIGN(ubase, pgsize) == start)
10887c478bd9Sstevel@tonic-gate 			start = ubase;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 		offset = start - ubase;
10917c478bd9Sstevel@tonic-gate 		amount = end - start;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 		ASSERT(amount > 0 && amount <= count && amount <= pgsize);
10947c478bd9Sstevel@tonic-gate 
1095*289175a0Sjwadams 		if (copyout_nowatch(kbase + offset, (void *)start, amount))
10967c478bd9Sstevel@tonic-gate 			return (1);
10977c478bd9Sstevel@tonic-gate 		count -= amount;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 	return (0);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate /*
11037c478bd9Sstevel@tonic-gate  * Writes the stack layout for door_return() into the door_server_t of the
11047c478bd9Sstevel@tonic-gate  * server thread.
11057c478bd9Sstevel@tonic-gate  */
11067c478bd9Sstevel@tonic-gate static int
11077c478bd9Sstevel@tonic-gate door_layout(kthread_t *tp, size_t data_size, uint_t ndesc, int info_needed)
11087c478bd9Sstevel@tonic-gate {
11097c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(tp->t_door);
11107c478bd9Sstevel@tonic-gate 	door_layout_t *out = &st->d_layout;
11117c478bd9Sstevel@tonic-gate 	uintptr_t base_sp = (uintptr_t)st->d_sp;
11127c478bd9Sstevel@tonic-gate 	size_t ssize = st->d_ssize;
11137c478bd9Sstevel@tonic-gate 	size_t descsz;
11147c478bd9Sstevel@tonic-gate 	uintptr_t descp, datap, infop, resultsp, finalsp;
11157c478bd9Sstevel@tonic-gate 	size_t align = STACK_ALIGN;
11167c478bd9Sstevel@tonic-gate 	size_t results_sz = sizeof (struct door_results);
11177c478bd9Sstevel@tonic-gate 	model_t datamodel = lwp_getdatamodel(ttolwp(tp));
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	ASSERT(!st->d_layout_done);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate #ifndef _STACK_GROWS_DOWNWARD
11227c478bd9Sstevel@tonic-gate #error stack does not grow downward, door_layout() must change
11237c478bd9Sstevel@tonic-gate #endif
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
11267c478bd9Sstevel@tonic-gate 	if (datamodel != DATAMODEL_NATIVE) {
11277c478bd9Sstevel@tonic-gate 		align = STACK_ALIGN32;
11287c478bd9Sstevel@tonic-gate 		results_sz = sizeof (struct door_results32);
11297c478bd9Sstevel@tonic-gate 	}
11307c478bd9Sstevel@tonic-gate #endif
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	descsz = ndesc * sizeof (door_desc_t);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	/*
11357c478bd9Sstevel@tonic-gate 	 * To speed up the overflow checking, we do an initial check
11367c478bd9Sstevel@tonic-gate 	 * that the passed in data size won't cause us to wrap past
11377c478bd9Sstevel@tonic-gate 	 * base_sp.  Since door_max_desc limits descsz, we can
11387c478bd9Sstevel@tonic-gate 	 * safely use it here.  65535 is an arbitrary 'bigger than
11397c478bd9Sstevel@tonic-gate 	 * we need, small enough to not cause trouble' constant;
11407c478bd9Sstevel@tonic-gate 	 * the only constraint is that it must be > than:
11417c478bd9Sstevel@tonic-gate 	 *
11427c478bd9Sstevel@tonic-gate 	 *	5 * STACK_ALIGN +
11437c478bd9Sstevel@tonic-gate 	 *	    sizeof (door_info_t) +
11447c478bd9Sstevel@tonic-gate 	 *	    sizeof (door_results_t) +
11457c478bd9Sstevel@tonic-gate 	 *	    (max adjustment from door_final_sp())
11467c478bd9Sstevel@tonic-gate 	 *
11477c478bd9Sstevel@tonic-gate 	 * After we compute the layout, we can safely do a "did we wrap
11487c478bd9Sstevel@tonic-gate 	 * around" check, followed by a check against the recorded
11497c478bd9Sstevel@tonic-gate 	 * stack size.
11507c478bd9Sstevel@tonic-gate 	 */
11517c478bd9Sstevel@tonic-gate 	if (data_size >= SIZE_MAX - (size_t)65535UL - descsz)
11527c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* overflow */
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	descp = P2ALIGN(base_sp - descsz, align);
11557c478bd9Sstevel@tonic-gate 	datap = P2ALIGN(descp - data_size, align);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	if (info_needed)
11587c478bd9Sstevel@tonic-gate 		infop = P2ALIGN(datap - sizeof (door_info_t), align);
11597c478bd9Sstevel@tonic-gate 	else
11607c478bd9Sstevel@tonic-gate 		infop = datap;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	resultsp = P2ALIGN(infop - results_sz, align);
11637c478bd9Sstevel@tonic-gate 	finalsp = door_final_sp(resultsp, align, datamodel);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	if (finalsp > base_sp)
11667c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* overflow */
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	if (ssize != 0 && (base_sp - finalsp) > ssize)
11697c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* doesn't fit in stack */
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	out->dl_descp = (ndesc != 0)? (caddr_t)descp : 0;
11727c478bd9Sstevel@tonic-gate 	out->dl_datap = (data_size != 0)? (caddr_t)datap : 0;
11737c478bd9Sstevel@tonic-gate 	out->dl_infop = info_needed? (caddr_t)infop : 0;
11747c478bd9Sstevel@tonic-gate 	out->dl_resultsp = (caddr_t)resultsp;
11757c478bd9Sstevel@tonic-gate 	out->dl_sp = (caddr_t)finalsp;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	st->d_layout_done = 1;
11787c478bd9Sstevel@tonic-gate 	return (0);
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate static int
11827c478bd9Sstevel@tonic-gate door_server_dispatch(door_client_t *ct, door_node_t *dp)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(curthread->t_door);
11857c478bd9Sstevel@tonic-gate 	door_layout_t *layout = &st->d_layout;
11867c478bd9Sstevel@tonic-gate 	int error = 0;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	int is_private = (dp->door_flags & DOOR_PRIVATE);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	door_pool_t *pool = (is_private)? &dp->door_servers :
11917c478bd9Sstevel@tonic-gate 	    &curproc->p_server_threads;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	int empty_pool = (pool->dp_threads == NULL);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	caddr_t infop = NULL;
11967c478bd9Sstevel@tonic-gate 	char *datap = NULL;
11977c478bd9Sstevel@tonic-gate 	size_t datasize = 0;
11987c478bd9Sstevel@tonic-gate 	size_t descsize;
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	file_t **fpp = ct->d_fpp;
12017c478bd9Sstevel@tonic-gate 	door_desc_t *start = NULL;
12027c478bd9Sstevel@tonic-gate 	uint_t ndesc = 0;
12037c478bd9Sstevel@tonic-gate 	uint_t ncopied = 0;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	if (ct != NULL) {
12067c478bd9Sstevel@tonic-gate 		datap = ct->d_args.data_ptr;
12077c478bd9Sstevel@tonic-gate 		datasize = ct->d_args.data_size;
12087c478bd9Sstevel@tonic-gate 		ndesc = ct->d_args.desc_num;
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	descsize = ndesc * sizeof (door_desc_t);
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	/*
12147c478bd9Sstevel@tonic-gate 	 * Reset datap to NULL if we aren't passing any data.  Be careful
12157c478bd9Sstevel@tonic-gate 	 * to let unref notifications through, though.
12167c478bd9Sstevel@tonic-gate 	 */
12177c478bd9Sstevel@tonic-gate 	if (datap == DOOR_UNREF_DATA) {
12187c478bd9Sstevel@tonic-gate 		if (ct->d_upcall)
12197c478bd9Sstevel@tonic-gate 			datasize = 0;
12207c478bd9Sstevel@tonic-gate 		else
12217c478bd9Sstevel@tonic-gate 			datap = NULL;
12227c478bd9Sstevel@tonic-gate 	} else if (datasize == 0) {
12237c478bd9Sstevel@tonic-gate 		datap = NULL;
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	/*
12277c478bd9Sstevel@tonic-gate 	 * Get the stack layout, if it hasn't already been done.
12287c478bd9Sstevel@tonic-gate 	 */
12297c478bd9Sstevel@tonic-gate 	if (!st->d_layout_done) {
12307c478bd9Sstevel@tonic-gate 		error = door_layout(curthread, datasize, ndesc,
12317c478bd9Sstevel@tonic-gate 		    (is_private && empty_pool));
12327c478bd9Sstevel@tonic-gate 		if (error != 0)
12337c478bd9Sstevel@tonic-gate 			goto fail;
12347c478bd9Sstevel@tonic-gate 	}
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	/*
12377c478bd9Sstevel@tonic-gate 	 * fill out the stack, starting from the top.  Layout was already
12387c478bd9Sstevel@tonic-gate 	 * filled in by door_args() or door_translate_out().
12397c478bd9Sstevel@tonic-gate 	 */
12407c478bd9Sstevel@tonic-gate 	if (layout->dl_descp != NULL) {
12417c478bd9Sstevel@tonic-gate 		ASSERT(ndesc != 0);
12427c478bd9Sstevel@tonic-gate 		start = kmem_alloc(descsize, KM_SLEEP);
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		while (ndesc > 0) {
12457c478bd9Sstevel@tonic-gate 			if (door_insert(*fpp, &start[ncopied]) == -1) {
12467c478bd9Sstevel@tonic-gate 				error = EMFILE;
12477c478bd9Sstevel@tonic-gate 				goto fail;
12487c478bd9Sstevel@tonic-gate 			}
12497c478bd9Sstevel@tonic-gate 			ndesc--;
12507c478bd9Sstevel@tonic-gate 			ncopied++;
12517c478bd9Sstevel@tonic-gate 			fpp++;
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 		if (door_stack_copyout(start, layout->dl_descp, descsize)) {
12547c478bd9Sstevel@tonic-gate 			error = E2BIG;
12557c478bd9Sstevel@tonic-gate 			goto fail;
12567c478bd9Sstevel@tonic-gate 		}
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 	fpp = NULL;			/* finished processing */
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	if (layout->dl_datap != NULL) {
12617c478bd9Sstevel@tonic-gate 		ASSERT(datasize != 0);
12627c478bd9Sstevel@tonic-gate 		datap = layout->dl_datap;
12637c478bd9Sstevel@tonic-gate 		if (ct->d_upcall || datasize <= door_max_arg) {
12647c478bd9Sstevel@tonic-gate 			if (door_stack_copyout(ct->d_buf, datap, datasize)) {
12657c478bd9Sstevel@tonic-gate 				error = E2BIG;
12667c478bd9Sstevel@tonic-gate 				goto fail;
12677c478bd9Sstevel@tonic-gate 			}
12687c478bd9Sstevel@tonic-gate 		}
12697c478bd9Sstevel@tonic-gate 	}
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	if (is_private && empty_pool) {
12727c478bd9Sstevel@tonic-gate 		door_info_t di;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 		infop = layout->dl_infop;
12757c478bd9Sstevel@tonic-gate 		ASSERT(infop != NULL);
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		di.di_target = curproc->p_pid;
12787c478bd9Sstevel@tonic-gate 		di.di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
12797c478bd9Sstevel@tonic-gate 		di.di_data = (door_ptr_t)(uintptr_t)dp->door_data;
12807c478bd9Sstevel@tonic-gate 		di.di_uniquifier = dp->door_index;
12817c478bd9Sstevel@tonic-gate 		di.di_attributes = (dp->door_flags & DOOR_ATTR_MASK) |
12827c478bd9Sstevel@tonic-gate 		    DOOR_LOCAL;
12837c478bd9Sstevel@tonic-gate 
1284*289175a0Sjwadams 		if (door_stack_copyout(&di, infop, sizeof (di))) {
12857c478bd9Sstevel@tonic-gate 			error = E2BIG;
12867c478bd9Sstevel@tonic-gate 			goto fail;
12877c478bd9Sstevel@tonic-gate 		}
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
12917c478bd9Sstevel@tonic-gate 		struct door_results dr;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 		dr.cookie = dp->door_data;
12947c478bd9Sstevel@tonic-gate 		dr.data_ptr = datap;
12957c478bd9Sstevel@tonic-gate 		dr.data_size = datasize;
12967c478bd9Sstevel@tonic-gate 		dr.desc_ptr = (door_desc_t *)layout->dl_descp;
12977c478bd9Sstevel@tonic-gate 		dr.desc_num = ncopied;
12987c478bd9Sstevel@tonic-gate 		dr.pc = dp->door_pc;
12997c478bd9Sstevel@tonic-gate 		dr.nservers = !empty_pool;
13007c478bd9Sstevel@tonic-gate 		dr.door_info = (door_info_t *)infop;
13017c478bd9Sstevel@tonic-gate 
1302*289175a0Sjwadams 		if (door_stack_copyout(&dr, layout->dl_resultsp, sizeof (dr))) {
13037c478bd9Sstevel@tonic-gate 			error = E2BIG;
13047c478bd9Sstevel@tonic-gate 			goto fail;
13057c478bd9Sstevel@tonic-gate 		}
13067c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13077c478bd9Sstevel@tonic-gate 	} else {
13087c478bd9Sstevel@tonic-gate 		struct door_results32 dr32;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		dr32.cookie = (caddr32_t)(uintptr_t)dp->door_data;
13117c478bd9Sstevel@tonic-gate 		dr32.data_ptr = (caddr32_t)(uintptr_t)datap;
13127c478bd9Sstevel@tonic-gate 		dr32.data_size = (size32_t)datasize;
13137c478bd9Sstevel@tonic-gate 		dr32.desc_ptr = (caddr32_t)(uintptr_t)layout->dl_descp;
13147c478bd9Sstevel@tonic-gate 		dr32.desc_num = ncopied;
13157c478bd9Sstevel@tonic-gate 		dr32.pc = (caddr32_t)(uintptr_t)dp->door_pc;
13167c478bd9Sstevel@tonic-gate 		dr32.nservers = !empty_pool;
13177c478bd9Sstevel@tonic-gate 		dr32.door_info = (caddr32_t)(uintptr_t)infop;
13187c478bd9Sstevel@tonic-gate 
1319*289175a0Sjwadams 		if (door_stack_copyout(&dr32, layout->dl_resultsp,
1320*289175a0Sjwadams 		    sizeof (dr32))) {
13217c478bd9Sstevel@tonic-gate 			error = E2BIG;
13227c478bd9Sstevel@tonic-gate 			goto fail;
13237c478bd9Sstevel@tonic-gate 		}
13247c478bd9Sstevel@tonic-gate #endif
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	error = door_finish_dispatch(layout->dl_sp);
13287c478bd9Sstevel@tonic-gate fail:
13297c478bd9Sstevel@tonic-gate 	if (start != NULL) {
13307c478bd9Sstevel@tonic-gate 		if (error != 0)
13317c478bd9Sstevel@tonic-gate 			door_fd_close(start, ncopied);
13327c478bd9Sstevel@tonic-gate 		kmem_free(start, descsize);
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 	if (fpp != NULL)
13357c478bd9Sstevel@tonic-gate 		door_fp_close(fpp, ndesc);
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	return (error);
13387c478bd9Sstevel@tonic-gate }
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate /*
13417c478bd9Sstevel@tonic-gate  * Return the results (if any) to the caller (if any) and wait for the
13427c478bd9Sstevel@tonic-gate  * next invocation on a door.
13437c478bd9Sstevel@tonic-gate  */
13447c478bd9Sstevel@tonic-gate int
13457c478bd9Sstevel@tonic-gate door_return(caddr_t data_ptr, size_t data_size,
13467c478bd9Sstevel@tonic-gate     door_desc_t *desc_ptr, uint_t desc_num, caddr_t sp, size_t ssize)
13477c478bd9Sstevel@tonic-gate {
13487c478bd9Sstevel@tonic-gate 	kthread_t	*caller;
13497c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
13507c478bd9Sstevel@tonic-gate 	int		error = 0;
13517c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
13527c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* curthread door_data */
13537c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* caller door_data */
1354a574db85Sraf 	int		cancel_pending;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	st = door_my_server(1);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	/*
13597c478bd9Sstevel@tonic-gate 	 * If thread was bound to a door that no longer exists, return
13607c478bd9Sstevel@tonic-gate 	 * an error.  This can happen if a thread is bound to a door
13617c478bd9Sstevel@tonic-gate 	 * before the process calls forkall(); in the child, the door
13627c478bd9Sstevel@tonic-gate 	 * doesn't exist and door_fork() sets the d_invbound flag.
13637c478bd9Sstevel@tonic-gate 	 */
13647c478bd9Sstevel@tonic-gate 	if (st->d_invbound)
13657c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	st->d_sp = sp;			/* Save base of stack. */
13687c478bd9Sstevel@tonic-gate 	st->d_ssize = ssize;		/* and its size */
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	/*
13717c478bd9Sstevel@tonic-gate 	 * before we release our stack to the whims of our next caller,
13727c478bd9Sstevel@tonic-gate 	 * copy in the syscall arguments if we're being traced by /proc.
13737c478bd9Sstevel@tonic-gate 	 */
13747c478bd9Sstevel@tonic-gate 	if (curthread->t_post_sys && PTOU(ttoproc(curthread))->u_systrap)
13757c478bd9Sstevel@tonic-gate 		(void) save_syscall_args();
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	/* Make sure the caller hasn't gone away */
13787c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
13797c478bd9Sstevel@tonic-gate 	if ((caller = st->d_caller) == NULL || caller->t_door == NULL) {
13807c478bd9Sstevel@tonic-gate 		if (desc_num != 0) {
13817c478bd9Sstevel@tonic-gate 			/* close any DOOR_RELEASE descriptors */
13827c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
13837c478bd9Sstevel@tonic-gate 			error = door_release_fds(desc_ptr, desc_num);
13847c478bd9Sstevel@tonic-gate 			if (error)
13857c478bd9Sstevel@tonic-gate 				return (set_errno(error));
13867c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
13877c478bd9Sstevel@tonic-gate 		}
13887c478bd9Sstevel@tonic-gate 		goto out;
13897c478bd9Sstevel@tonic-gate 	}
13907c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	ct->d_args.data_size = data_size;
13937c478bd9Sstevel@tonic-gate 	ct->d_args.desc_num = desc_num;
13947c478bd9Sstevel@tonic-gate 	/*
13957c478bd9Sstevel@tonic-gate 	 * Transfer results, if any, to the client
13967c478bd9Sstevel@tonic-gate 	 */
13977c478bd9Sstevel@tonic-gate 	if (data_size != 0 || desc_num != 0) {
13987c478bd9Sstevel@tonic-gate 		/*
13997c478bd9Sstevel@tonic-gate 		 * Prevent the client from exiting until we have finished
14007c478bd9Sstevel@tonic-gate 		 * moving results.
14017c478bd9Sstevel@tonic-gate 		 */
14027c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
14037c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14047c478bd9Sstevel@tonic-gate 		error = door_results(caller, data_ptr, data_size,
14057c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num);
14067c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14077c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
14087c478bd9Sstevel@tonic-gate 		/*
14097c478bd9Sstevel@tonic-gate 		 * Pass EOVERFLOW errors back to the client
14107c478bd9Sstevel@tonic-gate 		 */
14117c478bd9Sstevel@tonic-gate 		if (error && error != EOVERFLOW) {
14127c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
14137c478bd9Sstevel@tonic-gate 			return (set_errno(error));
14147c478bd9Sstevel@tonic-gate 		}
14157c478bd9Sstevel@tonic-gate 	}
14167c478bd9Sstevel@tonic-gate out:
14177c478bd9Sstevel@tonic-gate 	/* Put ourselves on the available server thread list */
14187c478bd9Sstevel@tonic-gate 	door_release_server(st->d_pool, curthread);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	/*
14217c478bd9Sstevel@tonic-gate 	 * Make sure the caller is still waiting to be resumed
14227c478bd9Sstevel@tonic-gate 	 */
14237c478bd9Sstevel@tonic-gate 	if (caller) {
14247c478bd9Sstevel@tonic-gate 		disp_lock_t *tlp;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 		thread_lock(caller);
14277c478bd9Sstevel@tonic-gate 		ct->d_error = error;		/* Return any errors */
14287c478bd9Sstevel@tonic-gate 		if (caller->t_state == TS_SLEEP &&
14297c478bd9Sstevel@tonic-gate 		    SOBJ_TYPE(caller->t_sobj_ops) == SOBJ_SHUTTLE) {
14307c478bd9Sstevel@tonic-gate 			cpu_t *cp = CPU;
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 			tlp = caller->t_lockp;
14337c478bd9Sstevel@tonic-gate 			/*
14347c478bd9Sstevel@tonic-gate 			 * Setting t_disp_queue prevents erroneous preemptions
14357c478bd9Sstevel@tonic-gate 			 * if this thread is still in execution on another
14367c478bd9Sstevel@tonic-gate 			 * processor
14377c478bd9Sstevel@tonic-gate 			 */
14387c478bd9Sstevel@tonic-gate 			caller->t_disp_queue = cp->cpu_disp;
14397c478bd9Sstevel@tonic-gate 			CL_ACTIVE(caller);
14407c478bd9Sstevel@tonic-gate 			/*
14417c478bd9Sstevel@tonic-gate 			 * We are calling thread_onproc() instead of
14427c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC() because compiler can reorder
14437c478bd9Sstevel@tonic-gate 			 * the two stores of t_state and t_lockp in
14447c478bd9Sstevel@tonic-gate 			 * THREAD_ONPROC().
14457c478bd9Sstevel@tonic-gate 			 */
14467c478bd9Sstevel@tonic-gate 			thread_onproc(caller, cp);
14477c478bd9Sstevel@tonic-gate 			disp_lock_exit_high(tlp);
14487c478bd9Sstevel@tonic-gate 			shuttle_resume(caller, &door_knob);
14497c478bd9Sstevel@tonic-gate 		} else {
14507c478bd9Sstevel@tonic-gate 			/* May have been setrun or in stop state */
14517c478bd9Sstevel@tonic-gate 			thread_unlock(caller);
14527c478bd9Sstevel@tonic-gate 			shuttle_swtch(&door_knob);
14537c478bd9Sstevel@tonic-gate 		}
14547c478bd9Sstevel@tonic-gate 	} else {
14557c478bd9Sstevel@tonic-gate 		shuttle_swtch(&door_knob);
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	/*
14597c478bd9Sstevel@tonic-gate 	 * We've sprung to life. Determine if we are part of a door
14607c478bd9Sstevel@tonic-gate 	 * invocation, or just interrupted
14617c478bd9Sstevel@tonic-gate 	 */
14627c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
14637c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
14647c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
14657c478bd9Sstevel@tonic-gate 		/*
14667c478bd9Sstevel@tonic-gate 		 * Normal door invocation. Return any error condition
14677c478bd9Sstevel@tonic-gate 		 * encountered while trying to pass args to the server
14687c478bd9Sstevel@tonic-gate 		 * thread.
14697c478bd9Sstevel@tonic-gate 		 */
14707c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
14717c478bd9Sstevel@tonic-gate 		/*
14727c478bd9Sstevel@tonic-gate 		 * Prevent the caller from leaving us while we
14737c478bd9Sstevel@tonic-gate 		 * are copying out the arguments from it's buffer.
14747c478bd9Sstevel@tonic-gate 		 */
14757c478bd9Sstevel@tonic-gate 		ASSERT(st->d_caller != NULL);
14767c478bd9Sstevel@tonic-gate 		ct = DOOR_CLIENT(st->d_caller->t_door);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(ct);
14797c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14807c478bd9Sstevel@tonic-gate 		error = door_server_dispatch(ct, dp);
14817c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
14827c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(ct);
14837c478bd9Sstevel@tonic-gate 
1484*289175a0Sjwadams 		/* let the client know we have processed his message */
1485*289175a0Sjwadams 		ct->d_args_done = 1;
1486*289175a0Sjwadams 
14877c478bd9Sstevel@tonic-gate 		if (error) {
14887c478bd9Sstevel@tonic-gate 			caller = st->d_caller;
14897c478bd9Sstevel@tonic-gate 			if (caller)
14907c478bd9Sstevel@tonic-gate 				ct = DOOR_CLIENT(caller->t_door);
14917c478bd9Sstevel@tonic-gate 			else
14927c478bd9Sstevel@tonic-gate 				ct = NULL;
14937c478bd9Sstevel@tonic-gate 			goto out;
14947c478bd9Sstevel@tonic-gate 		}
14957c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
14967c478bd9Sstevel@tonic-gate 		return (0);
14977c478bd9Sstevel@tonic-gate 	} else {
14987c478bd9Sstevel@tonic-gate 		/*
14997c478bd9Sstevel@tonic-gate 		 * We are not involved in a door_invocation.
15007c478bd9Sstevel@tonic-gate 		 * Check for /proc related activity...
15017c478bd9Sstevel@tonic-gate 		 */
15027c478bd9Sstevel@tonic-gate 		st->d_caller = NULL;
1503c4ace179Sdm 		door_server_exit(curproc, curthread);
15047c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
1505a574db85Sraf 		cancel_pending = 0;
1506a574db85Sraf 		if (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
1507a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
1508a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0) {
1509a574db85Sraf 			if (cancel_pending)
1510a574db85Sraf 				schedctl_cancel_eintr();
15117c478bd9Sstevel@tonic-gate 			lwp->lwp_asleep = 0;
15127c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
15137c478bd9Sstevel@tonic-gate 			return (set_errno(EINTR));
15147c478bd9Sstevel@tonic-gate 		}
15157c478bd9Sstevel@tonic-gate 		/* Go back and wait for another request */
15167c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;
15177c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
15187c478bd9Sstevel@tonic-gate 		caller = NULL;
15197c478bd9Sstevel@tonic-gate 		goto out;
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate  * Revoke any future invocations on this door
15257c478bd9Sstevel@tonic-gate  */
15267c478bd9Sstevel@tonic-gate int
15277c478bd9Sstevel@tonic-gate door_revoke(int did)
15287c478bd9Sstevel@tonic-gate {
15297c478bd9Sstevel@tonic-gate 	door_node_t	*d;
15307c478bd9Sstevel@tonic-gate 	int		error;
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	if ((d = door_lookup(did, NULL)) == NULL)
15337c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
15367c478bd9Sstevel@tonic-gate 	if (d->door_target != curproc) {
15377c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
15387c478bd9Sstevel@tonic-gate 		releasef(did);
15397c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
15407c478bd9Sstevel@tonic-gate 	}
15417c478bd9Sstevel@tonic-gate 	d->door_flags |= DOOR_REVOKED;
15427c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_PRIVATE)
15437c478bd9Sstevel@tonic-gate 		cv_broadcast(&d->door_servers.dp_cv);
15447c478bd9Sstevel@tonic-gate 	else
15457c478bd9Sstevel@tonic-gate 		cv_broadcast(&curproc->p_server_threads.dp_cv);
15467c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
15477c478bd9Sstevel@tonic-gate 	releasef(did);
15487c478bd9Sstevel@tonic-gate 	/* Invalidate the descriptor */
15497c478bd9Sstevel@tonic-gate 	if ((error = closeandsetf(did, NULL)) != 0)
15507c478bd9Sstevel@tonic-gate 		return (set_errno(error));
15517c478bd9Sstevel@tonic-gate 	return (0);
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate int
15557c478bd9Sstevel@tonic-gate door_info(int did, struct door_info *d_info)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
15587c478bd9Sstevel@tonic-gate 	door_info_t	di;
15597c478bd9Sstevel@tonic-gate 	door_server_t	*st;
15607c478bd9Sstevel@tonic-gate 	file_t		*fp = NULL;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	if (did == DOOR_QUERY) {
15637c478bd9Sstevel@tonic-gate 		/* Get information on door current thread is bound to */
15647c478bd9Sstevel@tonic-gate 		if ((st = door_my_server(0)) == NULL ||
15657c478bd9Sstevel@tonic-gate 		    (dp = st->d_pool) == NULL)
15667c478bd9Sstevel@tonic-gate 			/* Thread isn't bound to a door */
15677c478bd9Sstevel@tonic-gate 			return (set_errno(EBADF));
15687c478bd9Sstevel@tonic-gate 	} else if ((dp = door_lookup(did, &fp)) == NULL) {
15697c478bd9Sstevel@tonic-gate 		/* Not a door */
15707c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	door_info_common(dp, &di, fp);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	if (did != DOOR_QUERY)
15767c478bd9Sstevel@tonic-gate 		releasef(did);
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	if (copyout(&di, d_info, sizeof (struct door_info)))
15797c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
15807c478bd9Sstevel@tonic-gate 	return (0);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate  * Common code for getting information about a door either via the
15857c478bd9Sstevel@tonic-gate  * door_info system call or the door_ki_info kernel call.
15867c478bd9Sstevel@tonic-gate  */
15877c478bd9Sstevel@tonic-gate void
15887c478bd9Sstevel@tonic-gate door_info_common(door_node_t *dp, struct door_info *dip, file_t *fp)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	int unref_count;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	bzero(dip, sizeof (door_info_t));
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
15957c478bd9Sstevel@tonic-gate 	if (dp->door_target == NULL)
15967c478bd9Sstevel@tonic-gate 		dip->di_target = -1;
15977c478bd9Sstevel@tonic-gate 	else
15987c478bd9Sstevel@tonic-gate 		dip->di_target = dp->door_target->p_pid;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	dip->di_attributes = dp->door_flags & DOOR_ATTR_MASK;
16017c478bd9Sstevel@tonic-gate 	if (dp->door_target == curproc)
16027c478bd9Sstevel@tonic-gate 		dip->di_attributes |= DOOR_LOCAL;
16037c478bd9Sstevel@tonic-gate 	dip->di_proc = (door_ptr_t)(uintptr_t)dp->door_pc;
16047c478bd9Sstevel@tonic-gate 	dip->di_data = (door_ptr_t)(uintptr_t)dp->door_data;
16057c478bd9Sstevel@tonic-gate 	dip->di_uniquifier = dp->door_index;
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * If this door is in the middle of having an unreferenced
16087c478bd9Sstevel@tonic-gate 	 * notification delivered, don't count the VN_HOLD by
16097c478bd9Sstevel@tonic-gate 	 * door_deliver_unref in determining if it is unreferenced.
16107c478bd9Sstevel@tonic-gate 	 * This handles the case where door_info is called from the
16117c478bd9Sstevel@tonic-gate 	 * thread delivering the unref notification.
16127c478bd9Sstevel@tonic-gate 	 */
16137c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_UNREF_ACTIVE)
16147c478bd9Sstevel@tonic-gate 		unref_count = 2;
16157c478bd9Sstevel@tonic-gate 	else
16167c478bd9Sstevel@tonic-gate 		unref_count = 1;
16177c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
16207c478bd9Sstevel@tonic-gate 		/*
16217c478bd9Sstevel@tonic-gate 		 * If this thread is bound to the door, then we can just
16227c478bd9Sstevel@tonic-gate 		 * check the vnode; a ref count of 1 (or 2 if this is
16237c478bd9Sstevel@tonic-gate 		 * handling an unref notification) means that the hold
16247c478bd9Sstevel@tonic-gate 		 * from the door_bind is the only reference to the door
16257c478bd9Sstevel@tonic-gate 		 * (no file descriptor refers to it).
16267c478bd9Sstevel@tonic-gate 		 */
16277c478bd9Sstevel@tonic-gate 		if (DTOV(dp)->v_count == unref_count)
16287c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16297c478bd9Sstevel@tonic-gate 	} else {
16307c478bd9Sstevel@tonic-gate 		/*
16317c478bd9Sstevel@tonic-gate 		 * If we're working from a file descriptor or door handle
16327c478bd9Sstevel@tonic-gate 		 * we need to look at the file structure count.  We don't
16337c478bd9Sstevel@tonic-gate 		 * need to hold the vnode lock since this is just a snapshot.
16347c478bd9Sstevel@tonic-gate 		 */
16357c478bd9Sstevel@tonic-gate 		mutex_enter(&fp->f_tlock);
16367c478bd9Sstevel@tonic-gate 		if (fp->f_count == 1 && DTOV(dp)->v_count == unref_count)
16377c478bd9Sstevel@tonic-gate 			dip->di_attributes |= DOOR_IS_UNREF;
16387c478bd9Sstevel@tonic-gate 		mutex_exit(&fp->f_tlock);
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate /*
16437c478bd9Sstevel@tonic-gate  * Return credentials of the door caller (if any) for this invocation
16447c478bd9Sstevel@tonic-gate  */
16457c478bd9Sstevel@tonic-gate int
16467c478bd9Sstevel@tonic-gate door_ucred(struct ucred_s *uch)
16477c478bd9Sstevel@tonic-gate {
16487c478bd9Sstevel@tonic-gate 	kthread_t	*caller;
16497c478bd9Sstevel@tonic-gate 	door_server_t	*st;
16507c478bd9Sstevel@tonic-gate 	door_client_t	*ct;
16517c478bd9Sstevel@tonic-gate 	struct proc	*p;
16527c478bd9Sstevel@tonic-gate 	struct ucred_s	*res;
16537c478bd9Sstevel@tonic-gate 	int		err;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16567c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL ||
16577c478bd9Sstevel@tonic-gate 	    (caller = st->d_caller) == NULL) {
16587c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
16597c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
16607c478bd9Sstevel@tonic-gate 	}
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	ASSERT(caller->t_door != NULL);
16637c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(caller->t_door);
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/* Prevent caller from exiting while we examine the cred */
16667c478bd9Sstevel@tonic-gate 	DOOR_T_HOLD(ct);
16677c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	p = ttoproc(caller);
16707c478bd9Sstevel@tonic-gate 
1671024b0a25Sseb 	/*
1672024b0a25Sseb 	 * If the credentials are not specified by the client, get the one
1673024b0a25Sseb 	 * associated with the calling process.
1674024b0a25Sseb 	 */
1675024b0a25Sseb 	if (ct->d_cred == NULL) {
1676024b0a25Sseb 		res = pgetucred(p);
1677024b0a25Sseb 	} else {
1678024b0a25Sseb 		res = cred2ucred(ct->d_cred, ct->d_upcall ?
1679024b0a25Sseb 		    p0.p_pid : p->p_pid, NULL, CRED());
1680024b0a25Sseb 	}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
16837c478bd9Sstevel@tonic-gate 	DOOR_T_RELEASE(ct);
16847c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	err = copyout(res, uch, res->uc_size);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	kmem_free(res, res->uc_size);
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	if (err != 0)
16917c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	return (0);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate  * Bind the current lwp to the server thread pool associated with 'did'
16987c478bd9Sstevel@tonic-gate  */
16997c478bd9Sstevel@tonic-gate int
17007c478bd9Sstevel@tonic-gate door_bind(int did)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
17037c478bd9Sstevel@tonic-gate 	door_server_t	*st;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	if ((dp = door_lookup(did, NULL)) == NULL) {
17067c478bd9Sstevel@tonic-gate 		/* Not a door */
17077c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17087c478bd9Sstevel@tonic-gate 	}
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	/*
17117c478bd9Sstevel@tonic-gate 	 * Can't bind to a non-private door, and can't bind to a door
17127c478bd9Sstevel@tonic-gate 	 * served by another process.
17137c478bd9Sstevel@tonic-gate 	 */
17147c478bd9Sstevel@tonic-gate 	if ((dp->door_flags & DOOR_PRIVATE) == 0 ||
17157c478bd9Sstevel@tonic-gate 	    dp->door_target != curproc) {
17167c478bd9Sstevel@tonic-gate 		releasef(did);
17177c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
17187c478bd9Sstevel@tonic-gate 	}
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	st = door_my_server(1);
17217c478bd9Sstevel@tonic-gate 	if (st->d_pool)
17227c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);
17237c478bd9Sstevel@tonic-gate 	st->d_pool = dp;
17247c478bd9Sstevel@tonic-gate 	st->d_invbound = 0;
17257c478bd9Sstevel@tonic-gate 	door_bind_thread(dp);
17267c478bd9Sstevel@tonic-gate 	releasef(did);
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	return (0);
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate /*
17327c478bd9Sstevel@tonic-gate  * Unbind the current lwp from it's server thread pool
17337c478bd9Sstevel@tonic-gate  */
17347c478bd9Sstevel@tonic-gate int
17357c478bd9Sstevel@tonic-gate door_unbind(void)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate 	door_server_t *st;
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	if ((st = door_my_server(0)) == NULL)
17407c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	if (st->d_invbound) {
17437c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool == NULL);
17447c478bd9Sstevel@tonic-gate 		st->d_invbound = 0;
17457c478bd9Sstevel@tonic-gate 		return (0);
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 	if (st->d_pool == NULL)
17487c478bd9Sstevel@tonic-gate 		return (set_errno(EBADF));
17497c478bd9Sstevel@tonic-gate 	door_unbind_thread(st->d_pool);
17507c478bd9Sstevel@tonic-gate 	st->d_pool = NULL;
17517c478bd9Sstevel@tonic-gate 	return (0);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate /*
17557c478bd9Sstevel@tonic-gate  * Create a descriptor for the associated file and fill in the
17567c478bd9Sstevel@tonic-gate  * attributes associated with it.
17577c478bd9Sstevel@tonic-gate  *
17587c478bd9Sstevel@tonic-gate  * Return 0 for success, -1 otherwise;
17597c478bd9Sstevel@tonic-gate  */
17607c478bd9Sstevel@tonic-gate int
17617c478bd9Sstevel@tonic-gate door_insert(struct file *fp, door_desc_t *dp)
17627c478bd9Sstevel@tonic-gate {
17637c478bd9Sstevel@tonic-gate 	struct vnode *vp;
17647c478bd9Sstevel@tonic-gate 	int	fd;
17657c478bd9Sstevel@tonic-gate 	door_attr_t attributes = DOOR_DESCRIPTOR;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
17687c478bd9Sstevel@tonic-gate 	if ((fd = ufalloc(0)) == -1)
17697c478bd9Sstevel@tonic-gate 		return (-1);
17707c478bd9Sstevel@tonic-gate 	setf(fd, fp);
17717c478bd9Sstevel@tonic-gate 	dp->d_data.d_desc.d_descriptor = fd;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/* Fill in the attributes */
1774da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
17757c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
17767c478bd9Sstevel@tonic-gate 	if (vp && vp->v_type == VDOOR) {
17777c478bd9Sstevel@tonic-gate 		if (VTOD(vp)->door_target == curproc)
17787c478bd9Sstevel@tonic-gate 			attributes |= DOOR_LOCAL;
17797c478bd9Sstevel@tonic-gate 		attributes |= VTOD(vp)->door_flags & DOOR_ATTR_MASK;
17807c478bd9Sstevel@tonic-gate 		dp->d_data.d_desc.d_id = VTOD(vp)->door_index;
17817c478bd9Sstevel@tonic-gate 	}
17827c478bd9Sstevel@tonic-gate 	dp->d_attributes = attributes;
17837c478bd9Sstevel@tonic-gate 	return (0);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate /*
17877c478bd9Sstevel@tonic-gate  * Return an available thread for this server.  A NULL return value indicates
17887c478bd9Sstevel@tonic-gate  * that either:
17897c478bd9Sstevel@tonic-gate  *	The door has been revoked, or
17907c478bd9Sstevel@tonic-gate  *	a signal was received.
17917c478bd9Sstevel@tonic-gate  * The two conditions can be differentiated using DOOR_INVALID(dp).
17927c478bd9Sstevel@tonic-gate  */
17937c478bd9Sstevel@tonic-gate static kthread_t *
17947c478bd9Sstevel@tonic-gate door_get_server(door_node_t *dp)
17957c478bd9Sstevel@tonic-gate {
17967c478bd9Sstevel@tonic-gate 	kthread_t **ktp;
17977c478bd9Sstevel@tonic-gate 	kthread_t *server_t;
17987c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
17997c478bd9Sstevel@tonic-gate 	door_server_t *st;
18007c478bd9Sstevel@tonic-gate 	int signalled;
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	disp_lock_t *tlp;
18037c478bd9Sstevel@tonic-gate 	cpu_t *cp;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	if (dp->door_flags & DOOR_PRIVATE)
18087c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
18097c478bd9Sstevel@tonic-gate 	else
18107c478bd9Sstevel@tonic-gate 		pool = &dp->door_target->p_server_threads;
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	for (;;) {
18137c478bd9Sstevel@tonic-gate 		/*
18147c478bd9Sstevel@tonic-gate 		 * We search the thread pool, looking for a server thread
18157c478bd9Sstevel@tonic-gate 		 * ready to take an invocation (i.e. one which is still
18167c478bd9Sstevel@tonic-gate 		 * sleeping on a shuttle object).  If none are available,
18177c478bd9Sstevel@tonic-gate 		 * we sleep on the pool's CV, and will be signaled when a
18187c478bd9Sstevel@tonic-gate 		 * thread is added to the pool.
18197c478bd9Sstevel@tonic-gate 		 *
18207c478bd9Sstevel@tonic-gate 		 * This relies on the fact that once a thread in the thread
18217c478bd9Sstevel@tonic-gate 		 * pool wakes up, it *must* remove and add itself to the pool
18227c478bd9Sstevel@tonic-gate 		 * before it can receive door calls.
18237c478bd9Sstevel@tonic-gate 		 */
18247c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
18257c478bd9Sstevel@tonic-gate 			return (NULL);	/* Target has become invalid */
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 		for (ktp = &pool->dp_threads;
18287c478bd9Sstevel@tonic-gate 		    (server_t = *ktp) != NULL;
18297c478bd9Sstevel@tonic-gate 		    ktp = &st->d_servers) {
18307c478bd9Sstevel@tonic-gate 			st = DOOR_SERVER(server_t->t_door);
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 			thread_lock(server_t);
18337c478bd9Sstevel@tonic-gate 			if (server_t->t_state == TS_SLEEP &&
18347c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(server_t->t_sobj_ops) == SOBJ_SHUTTLE)
18357c478bd9Sstevel@tonic-gate 				break;
18367c478bd9Sstevel@tonic-gate 			thread_unlock(server_t);
18377c478bd9Sstevel@tonic-gate 		}
18387c478bd9Sstevel@tonic-gate 		if (server_t != NULL)
18397c478bd9Sstevel@tonic-gate 			break;		/* we've got a live one! */
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
18427c478bd9Sstevel@tonic-gate 		    &signalled)) {
18437c478bd9Sstevel@tonic-gate 			/*
1844da6c28aaSamw 			 * If we were signaled and the door is still
18457c478bd9Sstevel@tonic-gate 			 * valid, pass the signal on to another waiter.
18467c478bd9Sstevel@tonic-gate 			 */
18477c478bd9Sstevel@tonic-gate 			if (signalled && !DOOR_INVALID(dp))
18487c478bd9Sstevel@tonic-gate 				cv_signal(&pool->dp_cv);
18497c478bd9Sstevel@tonic-gate 			return (NULL);	/* Got a signal */
18507c478bd9Sstevel@tonic-gate 		}
18517c478bd9Sstevel@tonic-gate 	}
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	/*
18547c478bd9Sstevel@tonic-gate 	 * We've got a thread_lock()ed thread which is still on the
18557c478bd9Sstevel@tonic-gate 	 * shuttle.  Take it off the list of available server threads
18567c478bd9Sstevel@tonic-gate 	 * and mark it as ONPROC.  We are committed to resuming this
18577c478bd9Sstevel@tonic-gate 	 * thread now.
18587c478bd9Sstevel@tonic-gate 	 */
18597c478bd9Sstevel@tonic-gate 	tlp = server_t->t_lockp;
18607c478bd9Sstevel@tonic-gate 	cp = CPU;
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	*ktp = st->d_servers;
18637c478bd9Sstevel@tonic-gate 	st->d_servers = NULL;
18647c478bd9Sstevel@tonic-gate 	/*
18657c478bd9Sstevel@tonic-gate 	 * Setting t_disp_queue prevents erroneous preemptions
18667c478bd9Sstevel@tonic-gate 	 * if this thread is still in execution on another processor
18677c478bd9Sstevel@tonic-gate 	 */
18687c478bd9Sstevel@tonic-gate 	server_t->t_disp_queue = cp->cpu_disp;
18697c478bd9Sstevel@tonic-gate 	CL_ACTIVE(server_t);
18707c478bd9Sstevel@tonic-gate 	/*
18717c478bd9Sstevel@tonic-gate 	 * We are calling thread_onproc() instead of
18727c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC() because compiler can reorder
18737c478bd9Sstevel@tonic-gate 	 * the two stores of t_state and t_lockp in
18747c478bd9Sstevel@tonic-gate 	 * THREAD_ONPROC().
18757c478bd9Sstevel@tonic-gate 	 */
18767c478bd9Sstevel@tonic-gate 	thread_onproc(server_t, cp);
18777c478bd9Sstevel@tonic-gate 	disp_lock_exit(tlp);
18787c478bd9Sstevel@tonic-gate 	return (server_t);
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate /*
18827c478bd9Sstevel@tonic-gate  * Put a server thread back in the pool.
18837c478bd9Sstevel@tonic-gate  */
18847c478bd9Sstevel@tonic-gate static void
18857c478bd9Sstevel@tonic-gate door_release_server(door_node_t *dp, kthread_t *t)
18867c478bd9Sstevel@tonic-gate {
18877c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
18887c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
18917c478bd9Sstevel@tonic-gate 	st->d_active = NULL;
18927c478bd9Sstevel@tonic-gate 	st->d_caller = NULL;
18937c478bd9Sstevel@tonic-gate 	st->d_layout_done = 0;
18947c478bd9Sstevel@tonic-gate 	if (dp && (dp->door_flags & DOOR_PRIVATE)) {
18957c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == NULL ||
18967c478bd9Sstevel@tonic-gate 		    dp->door_target == ttoproc(t));
18977c478bd9Sstevel@tonic-gate 		pool = &dp->door_servers;
18987c478bd9Sstevel@tonic-gate 	} else {
18997c478bd9Sstevel@tonic-gate 		pool = &ttoproc(t)->p_server_threads;
19007c478bd9Sstevel@tonic-gate 	}
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	st->d_servers = pool->dp_threads;
19037c478bd9Sstevel@tonic-gate 	pool->dp_threads = t;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	/* If someone is waiting for a server thread, wake him up */
19067c478bd9Sstevel@tonic-gate 	cv_signal(&pool->dp_cv);
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate /*
19107c478bd9Sstevel@tonic-gate  * Remove a server thread from the pool if present.
19117c478bd9Sstevel@tonic-gate  */
1912c4ace179Sdm static void
19137c478bd9Sstevel@tonic-gate door_server_exit(proc_t *p, kthread_t *t)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	door_pool_t *pool;
19167c478bd9Sstevel@tonic-gate 	kthread_t **next;
19177c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(t->t_door);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
19207c478bd9Sstevel@tonic-gate 	if (st->d_pool != NULL) {
19217c478bd9Sstevel@tonic-gate 		ASSERT(st->d_pool->door_flags & DOOR_PRIVATE);
19227c478bd9Sstevel@tonic-gate 		pool = &st->d_pool->door_servers;
19237c478bd9Sstevel@tonic-gate 	} else {
19247c478bd9Sstevel@tonic-gate 		pool = &p->p_server_threads;
19257c478bd9Sstevel@tonic-gate 	}
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	next = &pool->dp_threads;
19287c478bd9Sstevel@tonic-gate 	while (*next != NULL) {
19297c478bd9Sstevel@tonic-gate 		if (*next == t) {
19307c478bd9Sstevel@tonic-gate 			*next = DOOR_SERVER(t->t_door)->d_servers;
1931c4ace179Sdm 			return;
19327c478bd9Sstevel@tonic-gate 		}
19337c478bd9Sstevel@tonic-gate 		next = &(DOOR_SERVER((*next)->t_door)->d_servers);
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate }
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate /*
19387c478bd9Sstevel@tonic-gate  * Lookup the door descriptor. Caller must call releasef when finished
19397c478bd9Sstevel@tonic-gate  * with associated door.
19407c478bd9Sstevel@tonic-gate  */
19417c478bd9Sstevel@tonic-gate static door_node_t *
19427c478bd9Sstevel@tonic-gate door_lookup(int did, file_t **fpp)
19437c478bd9Sstevel@tonic-gate {
19447c478bd9Sstevel@tonic-gate 	vnode_t	*vp;
19457c478bd9Sstevel@tonic-gate 	file_t *fp;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
19487c478bd9Sstevel@tonic-gate 	if ((fp = getf(did)) == NULL)
19497c478bd9Sstevel@tonic-gate 		return (NULL);
19507c478bd9Sstevel@tonic-gate 	/*
19517c478bd9Sstevel@tonic-gate 	 * Use the underlying vnode (we may be namefs mounted)
19527c478bd9Sstevel@tonic-gate 	 */
1953da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
19547c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	if (vp == NULL || vp->v_type != VDOOR) {
19577c478bd9Sstevel@tonic-gate 		releasef(did);
19587c478bd9Sstevel@tonic-gate 		return (NULL);
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	if (fpp)
19627c478bd9Sstevel@tonic-gate 		*fpp = fp;
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	return (VTOD(vp));
19657c478bd9Sstevel@tonic-gate }
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate /*
19687c478bd9Sstevel@tonic-gate  * The current thread is exiting, so clean up any pending
19697c478bd9Sstevel@tonic-gate  * invocation details
19707c478bd9Sstevel@tonic-gate  */
19717c478bd9Sstevel@tonic-gate void
19727c478bd9Sstevel@tonic-gate door_slam(void)
19737c478bd9Sstevel@tonic-gate {
19747c478bd9Sstevel@tonic-gate 	door_node_t *dp;
19757c478bd9Sstevel@tonic-gate 	door_data_t *dt;
19767c478bd9Sstevel@tonic-gate 	door_client_t *ct;
19777c478bd9Sstevel@tonic-gate 	door_server_t *st;
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	/*
19807c478bd9Sstevel@tonic-gate 	 * If we are an active door server, notify our
19817c478bd9Sstevel@tonic-gate 	 * client that we are exiting and revoke our door.
19827c478bd9Sstevel@tonic-gate 	 */
19837c478bd9Sstevel@tonic-gate 	if ((dt = door_my_data(0)) == NULL)
19847c478bd9Sstevel@tonic-gate 		return;
19857c478bd9Sstevel@tonic-gate 	ct = DOOR_CLIENT(dt);
19867c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(dt);
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
19897c478bd9Sstevel@tonic-gate 	for (;;) {
19907c478bd9Sstevel@tonic-gate 		if (DOOR_T_HELD(ct))
19917c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
19927c478bd9Sstevel@tonic-gate 		else if (DOOR_T_HELD(st))
19937c478bd9Sstevel@tonic-gate 			cv_wait(&st->d_cv, &door_knob);
19947c478bd9Sstevel@tonic-gate 		else
19957c478bd9Sstevel@tonic-gate 			break;			/* neither flag is set */
19967c478bd9Sstevel@tonic-gate 	}
19977c478bd9Sstevel@tonic-gate 	curthread->t_door = NULL;
19987c478bd9Sstevel@tonic-gate 	if ((dp = st->d_active) != NULL) {
19997c478bd9Sstevel@tonic-gate 		kthread_t *t = st->d_caller;
20007c478bd9Sstevel@tonic-gate 		proc_t *p = curproc;
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 		/* Revoke our door if the process is exiting */
200397eda132Sraf 		if (dp->door_target == p && (p->p_flag & SEXITING)) {
20047c478bd9Sstevel@tonic-gate 			door_list_delete(dp);
20057c478bd9Sstevel@tonic-gate 			dp->door_target = NULL;
20067c478bd9Sstevel@tonic-gate 			dp->door_flags |= DOOR_REVOKED;
20077c478bd9Sstevel@tonic-gate 			if (dp->door_flags & DOOR_PRIVATE)
20087c478bd9Sstevel@tonic-gate 				cv_broadcast(&dp->door_servers.dp_cv);
20097c478bd9Sstevel@tonic-gate 			else
20107c478bd9Sstevel@tonic-gate 				cv_broadcast(&p->p_server_threads.dp_cv);
20117c478bd9Sstevel@tonic-gate 		}
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 		if (t != NULL) {
20147c478bd9Sstevel@tonic-gate 			/*
20157c478bd9Sstevel@tonic-gate 			 * Let the caller know we are gone
20167c478bd9Sstevel@tonic-gate 			 */
20177c478bd9Sstevel@tonic-gate 			DOOR_CLIENT(t->t_door)->d_error = DOOR_EXIT;
20187c478bd9Sstevel@tonic-gate 			thread_lock(t);
20197c478bd9Sstevel@tonic-gate 			if (t->t_state == TS_SLEEP &&
20207c478bd9Sstevel@tonic-gate 			    SOBJ_TYPE(t->t_sobj_ops) == SOBJ_SHUTTLE)
20217c478bd9Sstevel@tonic-gate 				setrun_locked(t);
20227c478bd9Sstevel@tonic-gate 			thread_unlock(t);
20237c478bd9Sstevel@tonic-gate 		}
20247c478bd9Sstevel@tonic-gate 	}
20257c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20267c478bd9Sstevel@tonic-gate 	if (st->d_pool)
20277c478bd9Sstevel@tonic-gate 		door_unbind_thread(st->d_pool);	/* Implicit door_unbind */
20287c478bd9Sstevel@tonic-gate 	kmem_free(dt, sizeof (door_data_t));
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate /*
20327c478bd9Sstevel@tonic-gate  * Set DOOR_REVOKED for all doors of the current process. This is called
20337c478bd9Sstevel@tonic-gate  * on exit before all lwp's are being terminated so that door calls will
20347c478bd9Sstevel@tonic-gate  * return with an error.
20357c478bd9Sstevel@tonic-gate  */
20367c478bd9Sstevel@tonic-gate void
20377c478bd9Sstevel@tonic-gate door_revoke_all()
20387c478bd9Sstevel@tonic-gate {
20397c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20407c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20437c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20447c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_target == p);
20457c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20467c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20477c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20487c478bd9Sstevel@tonic-gate 	}
20497c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate /*
20547c478bd9Sstevel@tonic-gate  * The process is exiting, and all doors it created need to be revoked.
20557c478bd9Sstevel@tonic-gate  */
20567c478bd9Sstevel@tonic-gate void
20577c478bd9Sstevel@tonic-gate door_exit(void)
20587c478bd9Sstevel@tonic-gate {
20597c478bd9Sstevel@tonic-gate 	door_node_t *dp;
20607c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	ASSERT(p->p_lwpcnt == 1);
20637c478bd9Sstevel@tonic-gate 	/*
20647c478bd9Sstevel@tonic-gate 	 * Walk the list of active doors created by this process and
20657c478bd9Sstevel@tonic-gate 	 * revoke them all.
20667c478bd9Sstevel@tonic-gate 	 */
20677c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
20687c478bd9Sstevel@tonic-gate 	for (dp = p->p_door_list; dp != NULL; dp = dp->door_list) {
20697c478bd9Sstevel@tonic-gate 		dp->door_target = NULL;
20707c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_REVOKED;
20717c478bd9Sstevel@tonic-gate 		if (dp->door_flags & DOOR_PRIVATE)
20727c478bd9Sstevel@tonic-gate 			cv_broadcast(&dp->door_servers.dp_cv);
20737c478bd9Sstevel@tonic-gate 	}
20747c478bd9Sstevel@tonic-gate 	cv_broadcast(&p->p_server_threads.dp_cv);
20757c478bd9Sstevel@tonic-gate 	/* Clear the list */
20767c478bd9Sstevel@tonic-gate 	p->p_door_list = NULL;
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	/* Clean up the unref list */
20797c478bd9Sstevel@tonic-gate 	while ((dp = p->p_unref_list) != NULL) {
20807c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
20817c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
20827c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
20837c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
20847c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
20877c478bd9Sstevel@tonic-gate }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate /*
20917c478bd9Sstevel@tonic-gate  * The process is executing forkall(), and we need to flag threads that
20927c478bd9Sstevel@tonic-gate  * are bound to a door in the child.  This will make the child threads
20937c478bd9Sstevel@tonic-gate  * return an error to door_return unless they call door_unbind first.
20947c478bd9Sstevel@tonic-gate  */
20957c478bd9Sstevel@tonic-gate void
20967c478bd9Sstevel@tonic-gate door_fork(kthread_t *parent, kthread_t *child)
20977c478bd9Sstevel@tonic-gate {
20987c478bd9Sstevel@tonic-gate 	door_data_t *pt = parent->t_door;
20997c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(pt);
21007c478bd9Sstevel@tonic-gate 	door_data_t *dt;
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
21037c478bd9Sstevel@tonic-gate 	if (pt != NULL && (st->d_pool != NULL || st->d_invbound)) {
21047c478bd9Sstevel@tonic-gate 		/* parent thread is bound to a door */
21057c478bd9Sstevel@tonic-gate 		dt = child->t_door =
21067c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sizeof (door_data_t), KM_SLEEP);
21077c478bd9Sstevel@tonic-gate 		DOOR_SERVER(dt)->d_invbound = 1;
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate }
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate /*
21127c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to appropriate door server.
21137c478bd9Sstevel@tonic-gate  */
21147c478bd9Sstevel@tonic-gate static int
21157c478bd9Sstevel@tonic-gate door_unref(void)
21167c478bd9Sstevel@tonic-gate {
21177c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
21187c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
21197c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	/* make sure there's only one unref thread per process */
21227c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
21237c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
21247c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21257c478bd9Sstevel@tonic-gate 		return (set_errno(EALREADY));
21267c478bd9Sstevel@tonic-gate 	}
21277c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
21287c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);			/* create info, if necessary */
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	for (;;) {
21337c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
21367c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
21377c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&p->p_unref_cv, &door_knob)) {
21387c478bd9Sstevel@tonic-gate 				/*
21397c478bd9Sstevel@tonic-gate 				 * Interrupted.
21407c478bd9Sstevel@tonic-gate 				 * Return so we can finish forkall() or exit().
21417c478bd9Sstevel@tonic-gate 				 */
21427c478bd9Sstevel@tonic-gate 				p->p_unref_thread = 0;
21437c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
21447c478bd9Sstevel@tonic-gate 				return (set_errno(EINTR));
21457c478bd9Sstevel@tonic-gate 			}
21467c478bd9Sstevel@tonic-gate 		}
21477c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
21487c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
21497c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
21507c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21517c478bd9Sstevel@tonic-gate 
2152024b0a25Sseb 		(void) door_upcall(DTOV(dp), &unref_args, NULL);
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21557c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
21567c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
21577c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21587c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
21597c478bd9Sstevel@tonic-gate 	}
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate /*
21647c478bd9Sstevel@tonic-gate  * Deliver queued unrefs to kernel door server.
21657c478bd9Sstevel@tonic-gate  */
21667c478bd9Sstevel@tonic-gate /* ARGSUSED */
21677c478bd9Sstevel@tonic-gate static void
21687c478bd9Sstevel@tonic-gate door_unref_kernel(caddr_t arg)
21697c478bd9Sstevel@tonic-gate {
21707c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
21717c478bd9Sstevel@tonic-gate 	static door_arg_t unref_args = { DOOR_UNREF_DATA, 0, 0, 0, 0, 0 };
21727c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
21737c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	/* should only be one of these */
21767c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
21777c478bd9Sstevel@tonic-gate 	if (p->p_unref_thread) {
21787c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21797c478bd9Sstevel@tonic-gate 		return;
21807c478bd9Sstevel@tonic-gate 	}
21817c478bd9Sstevel@tonic-gate 	p->p_unref_thread = 1;
21827c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	(void) door_my_data(1);		/* make sure we have a door_data_t */
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &door_knob, callb_generic_cpr, "door_unref");
21877c478bd9Sstevel@tonic-gate 	for (;;) {
21887c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
21897c478bd9Sstevel@tonic-gate 		/* Grab a queued request */
21907c478bd9Sstevel@tonic-gate 		while ((dp = p->p_unref_list) == NULL) {
21917c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
21927c478bd9Sstevel@tonic-gate 			cv_wait(&p->p_unref_cv, &door_knob);
21937c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &door_knob);
21947c478bd9Sstevel@tonic-gate 		}
21957c478bd9Sstevel@tonic-gate 		p->p_unref_list = dp->door_ulist;
21967c478bd9Sstevel@tonic-gate 		dp->door_ulist = NULL;
21977c478bd9Sstevel@tonic-gate 		dp->door_flags |= DOOR_UNREF_ACTIVE;
21987c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 		(*(dp->door_pc))(dp->door_data, &unref_args, NULL, NULL, NULL);
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
22037c478bd9Sstevel@tonic-gate 		ASSERT(dp->door_flags & DOOR_UNREF_ACTIVE);
22047c478bd9Sstevel@tonic-gate 		dp->door_flags &= ~DOOR_UNREF_ACTIVE;
22057c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
22067c478bd9Sstevel@tonic-gate 		VN_RELE(DTOV(dp));
22077c478bd9Sstevel@tonic-gate 	}
22087c478bd9Sstevel@tonic-gate }
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate /*
22127c478bd9Sstevel@tonic-gate  * Queue an unref invocation for processing for the current process
22137c478bd9Sstevel@tonic-gate  * The door may or may not be revoked at this point.
22147c478bd9Sstevel@tonic-gate  */
22157c478bd9Sstevel@tonic-gate void
22167c478bd9Sstevel@tonic-gate door_deliver_unref(door_node_t *d)
22177c478bd9Sstevel@tonic-gate {
22187c478bd9Sstevel@tonic-gate 	struct proc *server = d->door_target;
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
22217c478bd9Sstevel@tonic-gate 	ASSERT(d->door_active == 0);
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	if (server == NULL)
22247c478bd9Sstevel@tonic-gate 		return;
22257c478bd9Sstevel@tonic-gate 	/*
22267c478bd9Sstevel@tonic-gate 	 * Create a lwp to deliver unref calls if one isn't already running.
22277c478bd9Sstevel@tonic-gate 	 *
22287c478bd9Sstevel@tonic-gate 	 * A separate thread is used to deliver unrefs since the current
22297c478bd9Sstevel@tonic-gate 	 * thread may be holding resources (e.g. locks) in user land that
22307c478bd9Sstevel@tonic-gate 	 * may be needed by the unref processing. This would cause a
22317c478bd9Sstevel@tonic-gate 	 * deadlock.
22327c478bd9Sstevel@tonic-gate 	 */
22337c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
22347c478bd9Sstevel@tonic-gate 		/* multiple unrefs */
22357c478bd9Sstevel@tonic-gate 		d->door_flags &= ~DOOR_DELAY;
22367c478bd9Sstevel@tonic-gate 	} else {
22377c478bd9Sstevel@tonic-gate 		/* Only 1 unref per door */
22387c478bd9Sstevel@tonic-gate 		d->door_flags &= ~(DOOR_UNREF|DOOR_DELAY);
22397c478bd9Sstevel@tonic-gate 	}
22407c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 	/*
22437c478bd9Sstevel@tonic-gate 	 * Need to bump the vnode count before putting the door on the
22447c478bd9Sstevel@tonic-gate 	 * list so it doesn't get prematurely released by door_unref.
22457c478bd9Sstevel@tonic-gate 	 */
22467c478bd9Sstevel@tonic-gate 	VN_HOLD(DTOV(d));
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
22497c478bd9Sstevel@tonic-gate 	/* is this door already on the unref list? */
22507c478bd9Sstevel@tonic-gate 	if (d->door_flags & DOOR_UNREF_MULTI) {
22517c478bd9Sstevel@tonic-gate 		door_node_t *dp;
22527c478bd9Sstevel@tonic-gate 		for (dp = server->p_unref_list; dp != NULL;
22537c478bd9Sstevel@tonic-gate 		    dp = dp->door_ulist) {
22547c478bd9Sstevel@tonic-gate 			if (d == dp) {
22557c478bd9Sstevel@tonic-gate 				/* already there, don't need to add another */
22567c478bd9Sstevel@tonic-gate 				mutex_exit(&door_knob);
22577c478bd9Sstevel@tonic-gate 				VN_RELE(DTOV(d));
22587c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
22597c478bd9Sstevel@tonic-gate 				return;
22607c478bd9Sstevel@tonic-gate 			}
22617c478bd9Sstevel@tonic-gate 		}
22627c478bd9Sstevel@tonic-gate 	}
22637c478bd9Sstevel@tonic-gate 	ASSERT(d->door_ulist == NULL);
22647c478bd9Sstevel@tonic-gate 	d->door_ulist = server->p_unref_list;
22657c478bd9Sstevel@tonic-gate 	server->p_unref_list = d;
22667c478bd9Sstevel@tonic-gate 	cv_broadcast(&server->p_unref_cv);
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate /*
22707c478bd9Sstevel@tonic-gate  * The callers buffer isn't big enough for all of the data/fd's. Allocate
22717c478bd9Sstevel@tonic-gate  * space in the callers address space for the results and copy the data
22727c478bd9Sstevel@tonic-gate  * there.
22737c478bd9Sstevel@tonic-gate  *
22747c478bd9Sstevel@tonic-gate  * For EOVERFLOW, we must clean up the server's door descriptors.
22757c478bd9Sstevel@tonic-gate  */
22767c478bd9Sstevel@tonic-gate static int
22777c478bd9Sstevel@tonic-gate door_overflow(
22787c478bd9Sstevel@tonic-gate 	kthread_t	*caller,
22797c478bd9Sstevel@tonic-gate 	caddr_t		data_ptr,	/* data location */
22807c478bd9Sstevel@tonic-gate 	size_t		data_size,	/* data size */
22817c478bd9Sstevel@tonic-gate 	door_desc_t	*desc_ptr,	/* descriptor location */
22827c478bd9Sstevel@tonic-gate 	uint_t		desc_num)	/* descriptor size */
22837c478bd9Sstevel@tonic-gate {
22847c478bd9Sstevel@tonic-gate 	proc_t *callerp = ttoproc(caller);
22857c478bd9Sstevel@tonic-gate 	struct as *as = callerp->p_as;
22867c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(caller->t_door);
22877c478bd9Sstevel@tonic-gate 	caddr_t	addr;			/* Resulting address in target */
22887c478bd9Sstevel@tonic-gate 	size_t	rlen;			/* Rounded len */
22897c478bd9Sstevel@tonic-gate 	size_t	len;
22907c478bd9Sstevel@tonic-gate 	uint_t	i;
22917c478bd9Sstevel@tonic-gate 	size_t	ds = desc_num * sizeof (door_desc_t);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
22947c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct) || ct->d_kernel);
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	/* Do initial overflow check */
22977c478bd9Sstevel@tonic-gate 	if (!ufcanalloc(callerp, desc_num))
22987c478bd9Sstevel@tonic-gate 		return (EMFILE);
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	/*
23017c478bd9Sstevel@tonic-gate 	 * Allocate space for this stuff in the callers address space
23027c478bd9Sstevel@tonic-gate 	 */
23037c478bd9Sstevel@tonic-gate 	rlen = roundup(data_size + ds, PAGESIZE);
23047c478bd9Sstevel@tonic-gate 	as_rangelock(as);
23057c478bd9Sstevel@tonic-gate 	map_addr_proc(&addr, rlen, 0, 1, as->a_userlimit, ttoproc(caller), 0);
23067c478bd9Sstevel@tonic-gate 	if (addr == NULL ||
23077c478bd9Sstevel@tonic-gate 	    as_map(as, addr, rlen, segvn_create, zfod_argsp) != 0) {
23087c478bd9Sstevel@tonic-gate 		/* No virtual memory available, or anon mapping failed */
23097c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
23107c478bd9Sstevel@tonic-gate 		if (!ct->d_kernel && desc_num > 0) {
23117c478bd9Sstevel@tonic-gate 			int error = door_release_fds(desc_ptr, desc_num);
23127c478bd9Sstevel@tonic-gate 			if (error)
23137c478bd9Sstevel@tonic-gate 				return (error);
23147c478bd9Sstevel@tonic-gate 		}
23157c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
23167c478bd9Sstevel@tonic-gate 	}
23177c478bd9Sstevel@tonic-gate 	as_rangeunlock(as);
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	if (ct->d_kernel)
23207c478bd9Sstevel@tonic-gate 		goto out;
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	if (data_size != 0) {
23237c478bd9Sstevel@tonic-gate 		caddr_t	src = data_ptr;
23247c478bd9Sstevel@tonic-gate 		caddr_t saddr = addr;
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 		/* Copy any data */
23277c478bd9Sstevel@tonic-gate 		len = data_size;
23287c478bd9Sstevel@tonic-gate 		while (len != 0) {
23297c478bd9Sstevel@tonic-gate 			int	amount;
23307c478bd9Sstevel@tonic-gate 			int	error;
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 			amount = len > PAGESIZE ? PAGESIZE : len;
23337c478bd9Sstevel@tonic-gate 			if ((error = door_copy(as, src, saddr, amount)) != 0) {
23347c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23357c478bd9Sstevel@tonic-gate 				return (error);
23367c478bd9Sstevel@tonic-gate 			}
23377c478bd9Sstevel@tonic-gate 			saddr += amount;
23387c478bd9Sstevel@tonic-gate 			src += amount;
23397c478bd9Sstevel@tonic-gate 			len -= amount;
23407c478bd9Sstevel@tonic-gate 		}
23417c478bd9Sstevel@tonic-gate 	}
23427c478bd9Sstevel@tonic-gate 	/* Copy any fd's */
23437c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
23447c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp, *start;
23457c478bd9Sstevel@tonic-gate 		struct file	**fpp;
23467c478bd9Sstevel@tonic-gate 		int		fpp_size;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(ds, KM_SLEEP);
2349*289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp, ds)) {
23507c478bd9Sstevel@tonic-gate 			kmem_free(start, ds);
23517c478bd9Sstevel@tonic-gate 			(void) as_unmap(as, addr, rlen);
23527c478bd9Sstevel@tonic-gate 			return (EFAULT);
23537c478bd9Sstevel@tonic-gate 		}
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
23567c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
23577c478bd9Sstevel@tonic-gate 			/* make more space */
23587c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
23597c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
23607c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
23617c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
23627c478bd9Sstevel@tonic-gate 		}
23637c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
23667c478bd9Sstevel@tonic-gate 			struct file *fp;
23677c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
23707c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
23717c478bd9Sstevel@tonic-gate 				/* close translated references */
23727c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
23737c478bd9Sstevel@tonic-gate 				/* close untranslated references */
23747c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
23757c478bd9Sstevel@tonic-gate 				kmem_free(start, ds);
23767c478bd9Sstevel@tonic-gate 				(void) as_unmap(as, addr, rlen);
23777c478bd9Sstevel@tonic-gate 				return (EINVAL);
23787c478bd9Sstevel@tonic-gate 			}
23797c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
23807c478bd9Sstevel@tonic-gate 			fp->f_count++;
23817c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 			*fpp = fp;
23847c478bd9Sstevel@tonic-gate 			releasef(fd);
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
23877c478bd9Sstevel@tonic-gate 				/* release passed reference */
23887c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
23897c478bd9Sstevel@tonic-gate 			}
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
23927c478bd9Sstevel@tonic-gate 		}
23937c478bd9Sstevel@tonic-gate 		kmem_free(start, ds);
23947c478bd9Sstevel@tonic-gate 	}
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate out:
23977c478bd9Sstevel@tonic-gate 	ct->d_overflow = 1;
23987c478bd9Sstevel@tonic-gate 	ct->d_args.rbuf = addr;
23997c478bd9Sstevel@tonic-gate 	ct->d_args.rsize = rlen;
24007c478bd9Sstevel@tonic-gate 	return (0);
24017c478bd9Sstevel@tonic-gate }
24027c478bd9Sstevel@tonic-gate 
24037c478bd9Sstevel@tonic-gate /*
24047c478bd9Sstevel@tonic-gate  * Transfer arguments from the client to the server.
24057c478bd9Sstevel@tonic-gate  */
24067c478bd9Sstevel@tonic-gate static int
24077c478bd9Sstevel@tonic-gate door_args(kthread_t *server, int is_private)
24087c478bd9Sstevel@tonic-gate {
24097c478bd9Sstevel@tonic-gate 	door_server_t *st = DOOR_SERVER(server->t_door);
24107c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
24117c478bd9Sstevel@tonic-gate 	uint_t	ndid;
24127c478bd9Sstevel@tonic-gate 	size_t	dsize;
24137c478bd9Sstevel@tonic-gate 	int	error;
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(st));
24167c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
24197c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
24207c478bd9Sstevel@tonic-gate 		return (E2BIG);
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 	/*
24237c478bd9Sstevel@tonic-gate 	 * Get the stack layout, and fail now if it won't fit.
24247c478bd9Sstevel@tonic-gate 	 */
24257c478bd9Sstevel@tonic-gate 	error = door_layout(server, ct->d_args.data_size, ndid, is_private);
24267c478bd9Sstevel@tonic-gate 	if (error != 0)
24277c478bd9Sstevel@tonic-gate 		return (error);
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	dsize = ndid * sizeof (door_desc_t);
24307c478bd9Sstevel@tonic-gate 	if (ct->d_args.data_size != 0) {
24317c478bd9Sstevel@tonic-gate 		if (ct->d_args.data_size <= door_max_arg) {
24327c478bd9Sstevel@tonic-gate 			/*
24337c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
24347c478bd9Sstevel@tonic-gate 			 *
24357c478bd9Sstevel@tonic-gate 			 * Allocate a little more than we need for the
24367c478bd9Sstevel@tonic-gate 			 * args, in the hope that the results will fit
24377c478bd9Sstevel@tonic-gate 			 * without having to reallocate a buffer
24387c478bd9Sstevel@tonic-gate 			 */
24397c478bd9Sstevel@tonic-gate 			ASSERT(ct->d_buf == NULL);
24407c478bd9Sstevel@tonic-gate 			ct->d_bufsize = roundup(ct->d_args.data_size,
24417c478bd9Sstevel@tonic-gate 			    DOOR_ROUND);
24427c478bd9Sstevel@tonic-gate 			ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
2443*289175a0Sjwadams 			if (copyin_nowatch(ct->d_args.data_ptr,
24447c478bd9Sstevel@tonic-gate 			    ct->d_buf, ct->d_args.data_size) != 0) {
24457c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
24467c478bd9Sstevel@tonic-gate 				ct->d_buf = NULL;
24477c478bd9Sstevel@tonic-gate 				ct->d_bufsize = 0;
24487c478bd9Sstevel@tonic-gate 				return (EFAULT);
24497c478bd9Sstevel@tonic-gate 			}
24507c478bd9Sstevel@tonic-gate 		} else {
24517c478bd9Sstevel@tonic-gate 			struct as	*as;
24527c478bd9Sstevel@tonic-gate 			caddr_t		src;
24537c478bd9Sstevel@tonic-gate 			caddr_t		dest;
24547c478bd9Sstevel@tonic-gate 			size_t		len = ct->d_args.data_size;
24557c478bd9Sstevel@tonic-gate 			uintptr_t	base;
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 			/*
24587c478bd9Sstevel@tonic-gate 			 * Use a 1 copy method
24597c478bd9Sstevel@tonic-gate 			 */
24607c478bd9Sstevel@tonic-gate 			as = ttoproc(server)->p_as;
24617c478bd9Sstevel@tonic-gate 			src = ct->d_args.data_ptr;
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate 			dest = st->d_layout.dl_datap;
24647c478bd9Sstevel@tonic-gate 			base = (uintptr_t)dest;
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 			/*
24677c478bd9Sstevel@tonic-gate 			 * Copy data directly into server.  We proceed
24687c478bd9Sstevel@tonic-gate 			 * downward from the top of the stack, to mimic
24697c478bd9Sstevel@tonic-gate 			 * normal stack usage. This allows the guard page
24707c478bd9Sstevel@tonic-gate 			 * to stop us before we corrupt anything.
24717c478bd9Sstevel@tonic-gate 			 */
24727c478bd9Sstevel@tonic-gate 			while (len != 0) {
24737c478bd9Sstevel@tonic-gate 				uintptr_t start;
24747c478bd9Sstevel@tonic-gate 				uintptr_t end;
24757c478bd9Sstevel@tonic-gate 				uintptr_t offset;
24767c478bd9Sstevel@tonic-gate 				size_t	amount;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 				/*
24797c478bd9Sstevel@tonic-gate 				 * Locate the next part to copy.
24807c478bd9Sstevel@tonic-gate 				 */
24817c478bd9Sstevel@tonic-gate 				end = base + len;
24827c478bd9Sstevel@tonic-gate 				start = P2ALIGN(end - 1, PAGESIZE);
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 				/*
24857c478bd9Sstevel@tonic-gate 				 * if we are on the final (first) page, fix
24867c478bd9Sstevel@tonic-gate 				 * up the start position.
24877c478bd9Sstevel@tonic-gate 				 */
24887c478bd9Sstevel@tonic-gate 				if (P2ALIGN(base, PAGESIZE) == start)
24897c478bd9Sstevel@tonic-gate 					start = base;
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 				offset = start - base;	/* the copy offset */
24927c478bd9Sstevel@tonic-gate 				amount = end - start;	/* # bytes to copy */
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 				ASSERT(amount > 0 && amount <= len &&
24957c478bd9Sstevel@tonic-gate 				    amount <= PAGESIZE);
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 				error = door_copy(as, src + offset,
24987c478bd9Sstevel@tonic-gate 				    dest + offset, amount);
24997c478bd9Sstevel@tonic-gate 				if (error != 0)
25007c478bd9Sstevel@tonic-gate 					return (error);
25017c478bd9Sstevel@tonic-gate 				len -= amount;
25027c478bd9Sstevel@tonic-gate 			}
25037c478bd9Sstevel@tonic-gate 		}
25047c478bd9Sstevel@tonic-gate 	}
25057c478bd9Sstevel@tonic-gate 	/*
25067c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into files
25077c478bd9Sstevel@tonic-gate 	 */
25087c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
25097c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
25107c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
25117c478bd9Sstevel@tonic-gate 		struct file	**fpp;
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
25147c478bd9Sstevel@tonic-gate 
2515*289175a0Sjwadams 		if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
25167c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
25177c478bd9Sstevel@tonic-gate 			return (EFAULT);
25187c478bd9Sstevel@tonic-gate 		}
25197c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
25207c478bd9Sstevel@tonic-gate 		ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
25217c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
25227c478bd9Sstevel@tonic-gate 		while (ndid--) {
25237c478bd9Sstevel@tonic-gate 			struct file *fp;
25247c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 			/* We only understand file descriptors as passed objs */
25277c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
25287c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
25297c478bd9Sstevel@tonic-gate 				/* close translated references */
25307c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
25317c478bd9Sstevel@tonic-gate 				/* close untranslated references */
25327c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
25337c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
25347c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
25357c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
25367c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
25377c478bd9Sstevel@tonic-gate 				return (EINVAL);
25387c478bd9Sstevel@tonic-gate 			}
25397c478bd9Sstevel@tonic-gate 			/* Hold the fp */
25407c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
25417c478bd9Sstevel@tonic-gate 			fp->f_count++;
25427c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 			*fpp = fp;
25457c478bd9Sstevel@tonic-gate 			releasef(fd);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
25487c478bd9Sstevel@tonic-gate 				/* release passed reference */
25497c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
25507c478bd9Sstevel@tonic-gate 			}
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
25537c478bd9Sstevel@tonic-gate 		}
25547c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
25557c478bd9Sstevel@tonic-gate 	}
25567c478bd9Sstevel@tonic-gate 	return (0);
25577c478bd9Sstevel@tonic-gate }
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate /*
25607c478bd9Sstevel@tonic-gate  * Transfer arguments from a user client to a kernel server.  This copies in
25617c478bd9Sstevel@tonic-gate  * descriptors and translates them into door handles.  It doesn't touch the
25627c478bd9Sstevel@tonic-gate  * other data, letting the kernel server deal with that (to avoid needing
25637c478bd9Sstevel@tonic-gate  * to copy the data twice).
25647c478bd9Sstevel@tonic-gate  */
25657c478bd9Sstevel@tonic-gate static int
25667c478bd9Sstevel@tonic-gate door_translate_in(void)
25677c478bd9Sstevel@tonic-gate {
25687c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
25697c478bd9Sstevel@tonic-gate 	uint_t	ndid;
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
25727c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
25737c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc)
25747c478bd9Sstevel@tonic-gate 		return (E2BIG);
25757c478bd9Sstevel@tonic-gate 	/*
25767c478bd9Sstevel@tonic-gate 	 * Copyin the door args and translate them into door handles.
25777c478bd9Sstevel@tonic-gate 	 */
25787c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
25797c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
25807c478bd9Sstevel@tonic-gate 		door_desc_t	*start;
25817c478bd9Sstevel@tonic-gate 		size_t		dsize = ndid * sizeof (door_desc_t);
25827c478bd9Sstevel@tonic-gate 		struct file	*fp;
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
25857c478bd9Sstevel@tonic-gate 
2586*289175a0Sjwadams 		if (copyin_nowatch(ct->d_args.desc_ptr, didpp, dsize)) {
25877c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
25887c478bd9Sstevel@tonic-gate 			return (EFAULT);
25897c478bd9Sstevel@tonic-gate 		}
25907c478bd9Sstevel@tonic-gate 		while (ndid--) {
25917c478bd9Sstevel@tonic-gate 			vnode_t	*vp;
25927c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 			/*
25957c478bd9Sstevel@tonic-gate 			 * We only understand file descriptors as passed objs
25967c478bd9Sstevel@tonic-gate 			 */
25977c478bd9Sstevel@tonic-gate 			if ((didpp->d_attributes & DOOR_DESCRIPTOR) &&
25987c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) != NULL) {
25997c478bd9Sstevel@tonic-gate 				didpp->d_data.d_handle = FTODH(fp);
26007c478bd9Sstevel@tonic-gate 				/* Hold the door */
26017c478bd9Sstevel@tonic-gate 				door_ki_hold(didpp->d_data.d_handle);
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 				releasef(fd);
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
26067c478bd9Sstevel@tonic-gate 					/* release passed reference */
26077c478bd9Sstevel@tonic-gate 					(void) closeandsetf(fd, NULL);
26087c478bd9Sstevel@tonic-gate 				}
26097c478bd9Sstevel@tonic-gate 
2610da6c28aaSamw 				if (VOP_REALVP(fp->f_vnode, &vp, NULL))
26117c478bd9Sstevel@tonic-gate 					vp = fp->f_vnode;
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 				/* Set attributes */
26147c478bd9Sstevel@tonic-gate 				didpp->d_attributes = DOOR_HANDLE |
26157c478bd9Sstevel@tonic-gate 				    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
26167c478bd9Sstevel@tonic-gate 			} else {
26177c478bd9Sstevel@tonic-gate 				/* close translated references */
26187c478bd9Sstevel@tonic-gate 				door_fd_close(start, didpp - start);
26197c478bd9Sstevel@tonic-gate 				/* close untranslated references */
26207c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 0);
26217c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
26227c478bd9Sstevel@tonic-gate 				return (EINVAL);
26237c478bd9Sstevel@tonic-gate 			}
26247c478bd9Sstevel@tonic-gate 			didpp++;
26257c478bd9Sstevel@tonic-gate 		}
26267c478bd9Sstevel@tonic-gate 		ct->d_args.desc_ptr = start;
26277c478bd9Sstevel@tonic-gate 	}
26287c478bd9Sstevel@tonic-gate 	return (0);
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate /*
26327c478bd9Sstevel@tonic-gate  * Translate door arguments from kernel to user.  This copies the passed
26337c478bd9Sstevel@tonic-gate  * door handles.  It doesn't touch other data.  It is used by door_upcall,
26347c478bd9Sstevel@tonic-gate  * and for data returned by a door_call to a kernel server.
26357c478bd9Sstevel@tonic-gate  */
26367c478bd9Sstevel@tonic-gate static int
26377c478bd9Sstevel@tonic-gate door_translate_out(void)
26387c478bd9Sstevel@tonic-gate {
26397c478bd9Sstevel@tonic-gate 	door_client_t *ct = DOOR_CLIENT(curthread->t_door);
26407c478bd9Sstevel@tonic-gate 	uint_t	ndid;
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
26437c478bd9Sstevel@tonic-gate 	ndid = ct->d_args.desc_num;
26447c478bd9Sstevel@tonic-gate 	if (ndid > door_max_desc) {
26457c478bd9Sstevel@tonic-gate 		door_fd_rele(ct->d_args.desc_ptr, ndid, 1);
26467c478bd9Sstevel@tonic-gate 		return (E2BIG);
26477c478bd9Sstevel@tonic-gate 	}
26487c478bd9Sstevel@tonic-gate 	/*
26497c478bd9Sstevel@tonic-gate 	 * Translate the door args into files
26507c478bd9Sstevel@tonic-gate 	 */
26517c478bd9Sstevel@tonic-gate 	if (ndid != 0) {
26527c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp = ct->d_args.desc_ptr;
26537c478bd9Sstevel@tonic-gate 		struct file	**fpp;
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = ndid * sizeof (struct file *);
26567c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp = kmem_alloc(ct->d_fpp_size, KM_SLEEP);
26577c478bd9Sstevel@tonic-gate 		while (ndid--) {
26587c478bd9Sstevel@tonic-gate 			struct file *fp = NULL;
26597c478bd9Sstevel@tonic-gate 			int fd = -1;
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 			/*
26627c478bd9Sstevel@tonic-gate 			 * We understand file descriptors and door
26637c478bd9Sstevel@tonic-gate 			 * handles as passed objs.
26647c478bd9Sstevel@tonic-gate 			 */
26657c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_DESCRIPTOR) {
26667c478bd9Sstevel@tonic-gate 				fd = didpp->d_data.d_desc.d_descriptor;
26677c478bd9Sstevel@tonic-gate 				fp = getf(fd);
26687c478bd9Sstevel@tonic-gate 			} else if (didpp->d_attributes & DOOR_HANDLE)
26697c478bd9Sstevel@tonic-gate 				fp = DHTOF(didpp->d_data.d_handle);
26707c478bd9Sstevel@tonic-gate 			if (fp != NULL) {
26717c478bd9Sstevel@tonic-gate 				/* Hold the fp */
26727c478bd9Sstevel@tonic-gate 				mutex_enter(&fp->f_tlock);
26737c478bd9Sstevel@tonic-gate 				fp->f_count++;
26747c478bd9Sstevel@tonic-gate 				mutex_exit(&fp->f_tlock);
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 				*fpp = fp;
26777c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_DESCRIPTOR)
26787c478bd9Sstevel@tonic-gate 					releasef(fd);
26797c478bd9Sstevel@tonic-gate 				if (didpp->d_attributes & DOOR_RELEASE) {
26807c478bd9Sstevel@tonic-gate 					/* release passed reference */
26817c478bd9Sstevel@tonic-gate 					if (fd >= 0)
26827c478bd9Sstevel@tonic-gate 						(void) closeandsetf(fd, NULL);
26837c478bd9Sstevel@tonic-gate 					else
26847c478bd9Sstevel@tonic-gate 						(void) closef(fp);
26857c478bd9Sstevel@tonic-gate 				}
26867c478bd9Sstevel@tonic-gate 			} else {
26877c478bd9Sstevel@tonic-gate 				/* close translated references */
26887c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
26897c478bd9Sstevel@tonic-gate 				/* close untranslated references */
26907c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, ndid + 1, 1);
26917c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
26927c478bd9Sstevel@tonic-gate 				ct->d_fpp = NULL;
26937c478bd9Sstevel@tonic-gate 				ct->d_fpp_size = 0;
26947c478bd9Sstevel@tonic-gate 				return (EINVAL);
26957c478bd9Sstevel@tonic-gate 			}
26967c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
26977c478bd9Sstevel@tonic-gate 		}
26987c478bd9Sstevel@tonic-gate 	}
26997c478bd9Sstevel@tonic-gate 	return (0);
27007c478bd9Sstevel@tonic-gate }
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate /*
27037c478bd9Sstevel@tonic-gate  * Move the results from the server to the client
27047c478bd9Sstevel@tonic-gate  */
27057c478bd9Sstevel@tonic-gate static int
27067c478bd9Sstevel@tonic-gate door_results(kthread_t *caller, caddr_t data_ptr, size_t data_size,
27077c478bd9Sstevel@tonic-gate 		door_desc_t *desc_ptr, uint_t desc_num)
27087c478bd9Sstevel@tonic-gate {
27097c478bd9Sstevel@tonic-gate 	door_client_t	*ct = DOOR_CLIENT(caller->t_door);
27107c478bd9Sstevel@tonic-gate 	size_t		dsize;
27117c478bd9Sstevel@tonic-gate 	size_t		rlen;
27127c478bd9Sstevel@tonic-gate 	size_t		result_size;
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 	ASSERT(DOOR_T_HELD(ct));
27157c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
27187c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* No results expected */
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	if (desc_num > door_max_desc)
27217c478bd9Sstevel@tonic-gate 		return (E2BIG);		/* Too many descriptors */
27227c478bd9Sstevel@tonic-gate 
27237c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
27247c478bd9Sstevel@tonic-gate 	/*
27257c478bd9Sstevel@tonic-gate 	 * Check if the results are bigger than the clients buffer
27267c478bd9Sstevel@tonic-gate 	 */
27277c478bd9Sstevel@tonic-gate 	if (dsize)
27287c478bd9Sstevel@tonic-gate 		rlen = roundup(data_size, sizeof (door_desc_t));
27297c478bd9Sstevel@tonic-gate 	else
27307c478bd9Sstevel@tonic-gate 		rlen = data_size;
27317c478bd9Sstevel@tonic-gate 	if ((result_size = rlen + dsize) == 0)
27327c478bd9Sstevel@tonic-gate 		return (0);
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	if (ct->d_upcall) {
27357c478bd9Sstevel@tonic-gate 		/*
27367c478bd9Sstevel@tonic-gate 		 * Handle upcalls
27377c478bd9Sstevel@tonic-gate 		 */
27387c478bd9Sstevel@tonic-gate 		if (ct->d_args.rbuf == NULL || ct->d_args.rsize < result_size) {
27397c478bd9Sstevel@tonic-gate 			/*
27407c478bd9Sstevel@tonic-gate 			 * If there's no return buffer or the buffer is too
27417c478bd9Sstevel@tonic-gate 			 * small, allocate a new one.  The old buffer (if it
27427c478bd9Sstevel@tonic-gate 			 * exists) will be freed by the upcall client.
27437c478bd9Sstevel@tonic-gate 			 */
27447c478bd9Sstevel@tonic-gate 			if (result_size > door_max_upcall_reply)
27457c478bd9Sstevel@tonic-gate 				return (E2BIG);
27467c478bd9Sstevel@tonic-gate 			ct->d_args.rsize = result_size;
27477c478bd9Sstevel@tonic-gate 			ct->d_args.rbuf = kmem_alloc(result_size, KM_SLEEP);
27487c478bd9Sstevel@tonic-gate 		}
27497c478bd9Sstevel@tonic-gate 		ct->d_args.data_ptr = ct->d_args.rbuf;
27507c478bd9Sstevel@tonic-gate 		if (data_size != 0 &&
2751*289175a0Sjwadams 		    copyin_nowatch(data_ptr, ct->d_args.data_ptr,
2752*289175a0Sjwadams 		    data_size) != 0)
27537c478bd9Sstevel@tonic-gate 			return (EFAULT);
27547c478bd9Sstevel@tonic-gate 	} else if (result_size > ct->d_args.rsize) {
27557c478bd9Sstevel@tonic-gate 		return (door_overflow(caller, data_ptr, data_size,
27567c478bd9Sstevel@tonic-gate 		    desc_ptr, desc_num));
27577c478bd9Sstevel@tonic-gate 	} else if (data_size != 0) {
27587c478bd9Sstevel@tonic-gate 		if (data_size <= door_max_arg) {
27597c478bd9Sstevel@tonic-gate 			/*
27607c478bd9Sstevel@tonic-gate 			 * Use a 2 copy method for small amounts of data
27617c478bd9Sstevel@tonic-gate 			 */
27627c478bd9Sstevel@tonic-gate 			if (ct->d_buf == NULL) {
27637c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27647c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27657c478bd9Sstevel@tonic-gate 			} else if (ct->d_bufsize < data_size) {
27667c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_buf, ct->d_bufsize);
27677c478bd9Sstevel@tonic-gate 				ct->d_bufsize = data_size;
27687c478bd9Sstevel@tonic-gate 				ct->d_buf = kmem_alloc(ct->d_bufsize, KM_SLEEP);
27697c478bd9Sstevel@tonic-gate 			}
2770*289175a0Sjwadams 			if (copyin_nowatch(data_ptr, ct->d_buf, data_size) != 0)
27717c478bd9Sstevel@tonic-gate 				return (EFAULT);
27727c478bd9Sstevel@tonic-gate 		} else {
27737c478bd9Sstevel@tonic-gate 			struct as *as = ttoproc(caller)->p_as;
27747c478bd9Sstevel@tonic-gate 			caddr_t	dest = ct->d_args.rbuf;
27757c478bd9Sstevel@tonic-gate 			caddr_t	src = data_ptr;
27767c478bd9Sstevel@tonic-gate 			size_t	len = data_size;
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 			/* Copy data directly into client */
27797c478bd9Sstevel@tonic-gate 			while (len != 0) {
27807c478bd9Sstevel@tonic-gate 				uint_t	amount;
27817c478bd9Sstevel@tonic-gate 				uint_t	max;
27827c478bd9Sstevel@tonic-gate 				uint_t	off;
27837c478bd9Sstevel@tonic-gate 				int	error;
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate 				off = (uintptr_t)dest & PAGEOFFSET;
27867c478bd9Sstevel@tonic-gate 				if (off)
27877c478bd9Sstevel@tonic-gate 					max = PAGESIZE - off;
27887c478bd9Sstevel@tonic-gate 				else
27897c478bd9Sstevel@tonic-gate 					max = PAGESIZE;
27907c478bd9Sstevel@tonic-gate 				amount = len > max ? max : len;
27917c478bd9Sstevel@tonic-gate 				error = door_copy(as, src, dest, amount);
27927c478bd9Sstevel@tonic-gate 				if (error != 0)
27937c478bd9Sstevel@tonic-gate 					return (error);
27947c478bd9Sstevel@tonic-gate 				dest += amount;
27957c478bd9Sstevel@tonic-gate 				src += amount;
27967c478bd9Sstevel@tonic-gate 				len -= amount;
27977c478bd9Sstevel@tonic-gate 			}
27987c478bd9Sstevel@tonic-gate 		}
27997c478bd9Sstevel@tonic-gate 	}
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	/*
28027c478bd9Sstevel@tonic-gate 	 * Copyin the returned door ids and translate them into door_node_t
28037c478bd9Sstevel@tonic-gate 	 */
28047c478bd9Sstevel@tonic-gate 	if (desc_num != 0) {
28057c478bd9Sstevel@tonic-gate 		door_desc_t *start;
28067c478bd9Sstevel@tonic-gate 		door_desc_t *didpp;
28077c478bd9Sstevel@tonic-gate 		struct file **fpp;
28087c478bd9Sstevel@tonic-gate 		size_t	fpp_size;
28097c478bd9Sstevel@tonic-gate 		uint_t	i;
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 		/* First, check if we would overflow client */
28127c478bd9Sstevel@tonic-gate 		if (!ufcanalloc(ttoproc(caller), desc_num))
28137c478bd9Sstevel@tonic-gate 			return (EMFILE);
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 		start = didpp = kmem_alloc(dsize, KM_SLEEP);
2816*289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp, dsize)) {
28177c478bd9Sstevel@tonic-gate 			kmem_free(start, dsize);
28187c478bd9Sstevel@tonic-gate 			return (EFAULT);
28197c478bd9Sstevel@tonic-gate 		}
28207c478bd9Sstevel@tonic-gate 		fpp_size = desc_num * sizeof (struct file *);
28217c478bd9Sstevel@tonic-gate 		if (fpp_size > ct->d_fpp_size) {
28227c478bd9Sstevel@tonic-gate 			/* make more space */
28237c478bd9Sstevel@tonic-gate 			if (ct->d_fpp_size)
28247c478bd9Sstevel@tonic-gate 				kmem_free(ct->d_fpp, ct->d_fpp_size);
28257c478bd9Sstevel@tonic-gate 			ct->d_fpp_size = fpp_size;
28267c478bd9Sstevel@tonic-gate 			ct->d_fpp = kmem_alloc(fpp_size, KM_SLEEP);
28277c478bd9Sstevel@tonic-gate 		}
28287c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 		for (i = 0; i < desc_num; i++) {
28317c478bd9Sstevel@tonic-gate 			struct file *fp;
28327c478bd9Sstevel@tonic-gate 			int fd = didpp->d_data.d_desc.d_descriptor;
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 			/* Only understand file descriptor results */
28357c478bd9Sstevel@tonic-gate 			if (!(didpp->d_attributes & DOOR_DESCRIPTOR) ||
28367c478bd9Sstevel@tonic-gate 			    (fp = getf(fd)) == NULL) {
28377c478bd9Sstevel@tonic-gate 				/* close translated references */
28387c478bd9Sstevel@tonic-gate 				door_fp_close(ct->d_fpp, fpp - ct->d_fpp);
28397c478bd9Sstevel@tonic-gate 				/* close untranslated references */
28407c478bd9Sstevel@tonic-gate 				door_fd_rele(didpp, desc_num - i, 0);
28417c478bd9Sstevel@tonic-gate 				kmem_free(start, dsize);
28427c478bd9Sstevel@tonic-gate 				return (EINVAL);
28437c478bd9Sstevel@tonic-gate 			}
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 			mutex_enter(&fp->f_tlock);
28467c478bd9Sstevel@tonic-gate 			fp->f_count++;
28477c478bd9Sstevel@tonic-gate 			mutex_exit(&fp->f_tlock);
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 			*fpp = fp;
28507c478bd9Sstevel@tonic-gate 			releasef(fd);
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate 			if (didpp->d_attributes & DOOR_RELEASE) {
28537c478bd9Sstevel@tonic-gate 				/* release passed reference */
28547c478bd9Sstevel@tonic-gate 				(void) closeandsetf(fd, NULL);
28557c478bd9Sstevel@tonic-gate 			}
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
28587c478bd9Sstevel@tonic-gate 		}
28597c478bd9Sstevel@tonic-gate 		kmem_free(start, dsize);
28607c478bd9Sstevel@tonic-gate 	}
28617c478bd9Sstevel@tonic-gate 	return (0);
28627c478bd9Sstevel@tonic-gate }
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate /*
28657c478bd9Sstevel@tonic-gate  * Close all the descriptors.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate static void
28687c478bd9Sstevel@tonic-gate door_fd_close(door_desc_t *d, uint_t n)
28697c478bd9Sstevel@tonic-gate {
28707c478bd9Sstevel@tonic-gate 	uint_t	i;
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
28737c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
28747c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_DESCRIPTOR) {
28757c478bd9Sstevel@tonic-gate 			(void) closeandsetf(
28767c478bd9Sstevel@tonic-gate 			    d->d_data.d_desc.d_descriptor, NULL);
28777c478bd9Sstevel@tonic-gate 		} else if (d->d_attributes & DOOR_HANDLE) {
28787c478bd9Sstevel@tonic-gate 			door_ki_rele(d->d_data.d_handle);
28797c478bd9Sstevel@tonic-gate 		}
28807c478bd9Sstevel@tonic-gate 		d++;
28817c478bd9Sstevel@tonic-gate 	}
28827c478bd9Sstevel@tonic-gate }
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate /*
28857c478bd9Sstevel@tonic-gate  * Close descriptors that have the DOOR_RELEASE attribute set.
28867c478bd9Sstevel@tonic-gate  */
28877c478bd9Sstevel@tonic-gate void
28887c478bd9Sstevel@tonic-gate door_fd_rele(door_desc_t *d, uint_t n, int from_kernel)
28897c478bd9Sstevel@tonic-gate {
28907c478bd9Sstevel@tonic-gate 	uint_t	i;
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
28937c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
28947c478bd9Sstevel@tonic-gate 		if (d->d_attributes & DOOR_RELEASE) {
28957c478bd9Sstevel@tonic-gate 			if (d->d_attributes & DOOR_DESCRIPTOR) {
28967c478bd9Sstevel@tonic-gate 				(void) closeandsetf(
28977c478bd9Sstevel@tonic-gate 				    d->d_data.d_desc.d_descriptor, NULL);
28987c478bd9Sstevel@tonic-gate 			} else if (from_kernel &&
28997c478bd9Sstevel@tonic-gate 			    (d->d_attributes & DOOR_HANDLE)) {
29007c478bd9Sstevel@tonic-gate 				door_ki_rele(d->d_data.d_handle);
29017c478bd9Sstevel@tonic-gate 			}
29027c478bd9Sstevel@tonic-gate 		}
29037c478bd9Sstevel@tonic-gate 		d++;
29047c478bd9Sstevel@tonic-gate 	}
29057c478bd9Sstevel@tonic-gate }
29067c478bd9Sstevel@tonic-gate 
29077c478bd9Sstevel@tonic-gate /*
29087c478bd9Sstevel@tonic-gate  * Copy descriptors into the kernel so we can release any marked
29097c478bd9Sstevel@tonic-gate  * DOOR_RELEASE.
29107c478bd9Sstevel@tonic-gate  */
29117c478bd9Sstevel@tonic-gate int
29127c478bd9Sstevel@tonic-gate door_release_fds(door_desc_t *desc_ptr, uint_t ndesc)
29137c478bd9Sstevel@tonic-gate {
29147c478bd9Sstevel@tonic-gate 	size_t dsize;
29157c478bd9Sstevel@tonic-gate 	door_desc_t *didpp;
29167c478bd9Sstevel@tonic-gate 	uint_t desc_num;
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29197c478bd9Sstevel@tonic-gate 	ASSERT(ndesc != 0);
29207c478bd9Sstevel@tonic-gate 
29217c478bd9Sstevel@tonic-gate 	desc_num = MIN(ndesc, door_max_desc);
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 	dsize = desc_num * sizeof (door_desc_t);
29247c478bd9Sstevel@tonic-gate 	didpp = kmem_alloc(dsize, KM_SLEEP);
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	while (ndesc > 0) {
29277c478bd9Sstevel@tonic-gate 		uint_t count = MIN(ndesc, desc_num);
29287c478bd9Sstevel@tonic-gate 
2929*289175a0Sjwadams 		if (copyin_nowatch(desc_ptr, didpp,
2930*289175a0Sjwadams 		    count * sizeof (door_desc_t))) {
29317c478bd9Sstevel@tonic-gate 			kmem_free(didpp, dsize);
29327c478bd9Sstevel@tonic-gate 			return (EFAULT);
29337c478bd9Sstevel@tonic-gate 		}
29347c478bd9Sstevel@tonic-gate 		door_fd_rele(didpp, count, 0);
29357c478bd9Sstevel@tonic-gate 
29367c478bd9Sstevel@tonic-gate 		ndesc -= count;
29377c478bd9Sstevel@tonic-gate 		desc_ptr += count;
29387c478bd9Sstevel@tonic-gate 	}
29397c478bd9Sstevel@tonic-gate 	kmem_free(didpp, dsize);
29407c478bd9Sstevel@tonic-gate 	return (0);
29417c478bd9Sstevel@tonic-gate }
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate /*
29447c478bd9Sstevel@tonic-gate  * Decrement ref count on all the files passed
29457c478bd9Sstevel@tonic-gate  */
29467c478bd9Sstevel@tonic-gate static void
29477c478bd9Sstevel@tonic-gate door_fp_close(struct file **fp, uint_t n)
29487c478bd9Sstevel@tonic-gate {
29497c478bd9Sstevel@tonic-gate 	uint_t	i;
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&door_knob));
29527c478bd9Sstevel@tonic-gate 
29537c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++)
29547c478bd9Sstevel@tonic-gate 		(void) closef(fp[i]);
29557c478bd9Sstevel@tonic-gate }
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate /*
29587c478bd9Sstevel@tonic-gate  * Copy data from 'src' in current address space to 'dest' in 'as' for 'len'
29597c478bd9Sstevel@tonic-gate  * bytes.
29607c478bd9Sstevel@tonic-gate  *
29617c478bd9Sstevel@tonic-gate  * Performs this using 1 mapin and 1 copy operation.
29627c478bd9Sstevel@tonic-gate  *
29637c478bd9Sstevel@tonic-gate  * We really should do more than 1 page at a time to improve
29647c478bd9Sstevel@tonic-gate  * performance, but for now this is treated as an anomalous condition.
29657c478bd9Sstevel@tonic-gate  */
29667c478bd9Sstevel@tonic-gate static int
29677c478bd9Sstevel@tonic-gate door_copy(struct as *as, caddr_t src, caddr_t dest, uint_t len)
29687c478bd9Sstevel@tonic-gate {
29697c478bd9Sstevel@tonic-gate 	caddr_t	kaddr;
29707c478bd9Sstevel@tonic-gate 	caddr_t	rdest;
29717c478bd9Sstevel@tonic-gate 	uint_t	off;
29727c478bd9Sstevel@tonic-gate 	page_t	**pplist;
29737c478bd9Sstevel@tonic-gate 	page_t	*pp = NULL;
29747c478bd9Sstevel@tonic-gate 	int	error = 0;
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 	ASSERT(len <= PAGESIZE);
29777c478bd9Sstevel@tonic-gate 	off = (uintptr_t)dest & PAGEOFFSET;	/* offset within the page */
29787c478bd9Sstevel@tonic-gate 	rdest = (caddr_t)((uintptr_t)dest &
29797c478bd9Sstevel@tonic-gate 	    (uintptr_t)PAGEMASK);	/* Page boundary */
29807c478bd9Sstevel@tonic-gate 	ASSERT(off + len <= PAGESIZE);
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/*
29837c478bd9Sstevel@tonic-gate 	 * Lock down destination page.
29847c478bd9Sstevel@tonic-gate 	 */
29857c478bd9Sstevel@tonic-gate 	if (as_pagelock(as, &pplist, rdest, PAGESIZE, S_WRITE))
29867c478bd9Sstevel@tonic-gate 		return (E2BIG);
29877c478bd9Sstevel@tonic-gate 	/*
29887c478bd9Sstevel@tonic-gate 	 * Check if we have a shadow page list from as_pagelock. If not,
29897c478bd9Sstevel@tonic-gate 	 * we took the slow path and have to find our page struct the hard
29907c478bd9Sstevel@tonic-gate 	 * way.
29917c478bd9Sstevel@tonic-gate 	 */
29927c478bd9Sstevel@tonic-gate 	if (pplist == NULL) {
29937c478bd9Sstevel@tonic-gate 		pfn_t	pfnum;
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate 		/* MMU mapping is already locked down */
29967c478bd9Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
29977c478bd9Sstevel@tonic-gate 		pfnum = hat_getpfnum(as->a_hat, rdest);
29987c478bd9Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 		/*
30017c478bd9Sstevel@tonic-gate 		 * TODO: The pfn step should not be necessary - need
30027c478bd9Sstevel@tonic-gate 		 * a hat_getpp() function.
30037c478bd9Sstevel@tonic-gate 		 */
30047c478bd9Sstevel@tonic-gate 		if (pf_is_memory(pfnum)) {
30057c478bd9Sstevel@tonic-gate 			pp = page_numtopp_nolock(pfnum);
30067c478bd9Sstevel@tonic-gate 			ASSERT(pp == NULL || PAGE_LOCKED(pp));
30077c478bd9Sstevel@tonic-gate 		} else
30087c478bd9Sstevel@tonic-gate 			pp = NULL;
30097c478bd9Sstevel@tonic-gate 		if (pp == NULL) {
30107c478bd9Sstevel@tonic-gate 			as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
30117c478bd9Sstevel@tonic-gate 			return (E2BIG);
30127c478bd9Sstevel@tonic-gate 		}
30137c478bd9Sstevel@tonic-gate 	} else {
30147c478bd9Sstevel@tonic-gate 		pp = *pplist;
30157c478bd9Sstevel@tonic-gate 	}
30167c478bd9Sstevel@tonic-gate 	/*
30177c478bd9Sstevel@tonic-gate 	 * Map destination page into kernel address
30187c478bd9Sstevel@tonic-gate 	 */
30197c478bd9Sstevel@tonic-gate 	kaddr = (caddr_t)ppmapin(pp, PROT_READ | PROT_WRITE, (caddr_t)-1);
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	/*
30227c478bd9Sstevel@tonic-gate 	 * Copy from src to dest
30237c478bd9Sstevel@tonic-gate 	 */
3024*289175a0Sjwadams 	if (copyin_nowatch(src, kaddr + off, len) != 0)
30257c478bd9Sstevel@tonic-gate 		error = EFAULT;
30267c478bd9Sstevel@tonic-gate 	/*
30277c478bd9Sstevel@tonic-gate 	 * Unmap destination page from kernel
30287c478bd9Sstevel@tonic-gate 	 */
30297c478bd9Sstevel@tonic-gate 	ppmapout(kaddr);
30307c478bd9Sstevel@tonic-gate 	/*
30317c478bd9Sstevel@tonic-gate 	 * Unlock destination page
30327c478bd9Sstevel@tonic-gate 	 */
30337c478bd9Sstevel@tonic-gate 	as_pageunlock(as, pplist, rdest, PAGESIZE, S_WRITE);
30347c478bd9Sstevel@tonic-gate 	return (error);
30357c478bd9Sstevel@tonic-gate }
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate /*
30387c478bd9Sstevel@tonic-gate  * General kernel upcall using doors
30397c478bd9Sstevel@tonic-gate  *	Returns 0 on success, errno for failures.
30407c478bd9Sstevel@tonic-gate  *	Caller must have a hold on the door based vnode, and on any
30417c478bd9Sstevel@tonic-gate  *	references passed in desc_ptr.  The references are released
30427c478bd9Sstevel@tonic-gate  *	in the event of an error, and passed without duplication
30437c478bd9Sstevel@tonic-gate  *	otherwise.  Note that param->rbuf must be 64-bit aligned in
30447c478bd9Sstevel@tonic-gate  *	a 64-bit kernel, since it may be used to store door descriptors
3045024b0a25Sseb  *	if they are returned by the server.  The caller is responsible
3046024b0a25Sseb  *	for holding a reference to the cred passed in.
30477c478bd9Sstevel@tonic-gate  */
30487c478bd9Sstevel@tonic-gate int
3049024b0a25Sseb door_upcall(vnode_t *vp, door_arg_t *param, struct cred *cred)
30507c478bd9Sstevel@tonic-gate {
30517c478bd9Sstevel@tonic-gate 	/* Locals */
30527c478bd9Sstevel@tonic-gate 	door_node_t	*dp;
30537c478bd9Sstevel@tonic-gate 	kthread_t	*server_thread;
30547c478bd9Sstevel@tonic-gate 	int		error = 0;
30557c478bd9Sstevel@tonic-gate 	klwp_t		*lwp;
30567c478bd9Sstevel@tonic-gate 	door_client_t	*ct;		/* curthread door_data */
30577c478bd9Sstevel@tonic-gate 	door_server_t	*st;		/* server thread door_data */
30587c478bd9Sstevel@tonic-gate 	int		gotresults = 0;
3059a574db85Sraf 	int		cancel_pending;
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
30627c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30637c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30647c478bd9Sstevel@tonic-gate 		return (EINVAL);
30657c478bd9Sstevel@tonic-gate 	}
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	lwp = ttolwp(curthread);
30687c478bd9Sstevel@tonic-gate 	ct = door_my_client(1);
30697c478bd9Sstevel@tonic-gate 	dp = VTOD(vp);	/* Convert to a door_node_t */
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
30727c478bd9Sstevel@tonic-gate 	if (DOOR_INVALID(dp)) {
30737c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30747c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30757c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30767c478bd9Sstevel@tonic-gate 		error = EBADF;
30777c478bd9Sstevel@tonic-gate 		goto out;
30787c478bd9Sstevel@tonic-gate 	}
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 	if (dp->door_target == &p0) {
30817c478bd9Sstevel@tonic-gate 		/* Can't do an upcall to a kernel server */
30827c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30837c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30847c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30857c478bd9Sstevel@tonic-gate 		error = EINVAL;
30867c478bd9Sstevel@tonic-gate 		goto out;
30877c478bd9Sstevel@tonic-gate 	}
30887c478bd9Sstevel@tonic-gate 
30897c478bd9Sstevel@tonic-gate 	error = door_check_limits(dp, param, 1);
30907c478bd9Sstevel@tonic-gate 	if (error != 0) {
30917c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
30927c478bd9Sstevel@tonic-gate 		if (param->desc_num)
30937c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
30947c478bd9Sstevel@tonic-gate 		goto out;
30957c478bd9Sstevel@tonic-gate 	}
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	/*
30987c478bd9Sstevel@tonic-gate 	 * Get a server thread from the target domain
30997c478bd9Sstevel@tonic-gate 	 */
31007c478bd9Sstevel@tonic-gate 	if ((server_thread = door_get_server(dp)) == NULL) {
31017c478bd9Sstevel@tonic-gate 		if (DOOR_INVALID(dp))
31027c478bd9Sstevel@tonic-gate 			error = EBADF;
31037c478bd9Sstevel@tonic-gate 		else
31047c478bd9Sstevel@tonic-gate 			error = EAGAIN;
31057c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
31067c478bd9Sstevel@tonic-gate 		if (param->desc_num)
31077c478bd9Sstevel@tonic-gate 			door_fd_rele(param->desc_ptr, param->desc_num, 1);
31087c478bd9Sstevel@tonic-gate 		goto out;
31097c478bd9Sstevel@tonic-gate 	}
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	st = DOOR_SERVER(server_thread->t_door);
31127c478bd9Sstevel@tonic-gate 	ct->d_buf = param->data_ptr;
31137c478bd9Sstevel@tonic-gate 	ct->d_bufsize = param->data_size;
31147c478bd9Sstevel@tonic-gate 	ct->d_args = *param;	/* structure assignment */
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
31177c478bd9Sstevel@tonic-gate 		/*
31187c478bd9Sstevel@tonic-gate 		 * Move data from client to server
31197c478bd9Sstevel@tonic-gate 		 */
31207c478bd9Sstevel@tonic-gate 		DOOR_T_HOLD(st);
31217c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);
31227c478bd9Sstevel@tonic-gate 		error = door_translate_out();
31237c478bd9Sstevel@tonic-gate 		mutex_enter(&door_knob);
31247c478bd9Sstevel@tonic-gate 		DOOR_T_RELEASE(st);
31257c478bd9Sstevel@tonic-gate 		if (error) {
31267c478bd9Sstevel@tonic-gate 			/*
31277c478bd9Sstevel@tonic-gate 			 * We're not going to resume this thread after all
31287c478bd9Sstevel@tonic-gate 			 */
31297c478bd9Sstevel@tonic-gate 			door_release_server(dp, server_thread);
31307c478bd9Sstevel@tonic-gate 			shuttle_sleep(server_thread);
31317c478bd9Sstevel@tonic-gate 			mutex_exit(&door_knob);
31327c478bd9Sstevel@tonic-gate 			goto out;
31337c478bd9Sstevel@tonic-gate 		}
31347c478bd9Sstevel@tonic-gate 	}
31357c478bd9Sstevel@tonic-gate 
31367c478bd9Sstevel@tonic-gate 	ct->d_upcall = 1;
3137024b0a25Sseb 	ct->d_cred = cred;
31387c478bd9Sstevel@tonic-gate 	if (param->rsize == 0)
31397c478bd9Sstevel@tonic-gate 		ct->d_noresults = 1;
31407c478bd9Sstevel@tonic-gate 	else
31417c478bd9Sstevel@tonic-gate 		ct->d_noresults = 0;
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	dp->door_active++;
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate 	ct->d_error = DOOR_WAIT;
31467c478bd9Sstevel@tonic-gate 	st->d_caller = curthread;
31477c478bd9Sstevel@tonic-gate 	st->d_active = dp;
31487c478bd9Sstevel@tonic-gate 
31497c478bd9Sstevel@tonic-gate 	shuttle_resume(server_thread, &door_knob);
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 	mutex_enter(&door_knob);
31527c478bd9Sstevel@tonic-gate shuttle_return:
31537c478bd9Sstevel@tonic-gate 	if ((error = ct->d_error) < 0) {	/* DOOR_WAIT or DOOR_EXIT */
31547c478bd9Sstevel@tonic-gate 		/*
31557c478bd9Sstevel@tonic-gate 		 * Premature wakeup. Find out why (stop, forkall, sig, exit ...)
31567c478bd9Sstevel@tonic-gate 		 */
31577c478bd9Sstevel@tonic-gate 		mutex_exit(&door_knob);		/* May block in ISSIG */
3158a574db85Sraf 		cancel_pending = 0;
3159a574db85Sraf 		if (lwp && (ISSIG(curthread, FORREAL) || lwp->lwp_sysabort ||
3160a574db85Sraf 		    MUSTRETURN(curproc, curthread) ||
3161a574db85Sraf 		    (cancel_pending = schedctl_cancel_pending()) != 0)) {
31627c478bd9Sstevel@tonic-gate 			/* Signal, forkall, ... */
3163a574db85Sraf 			if (cancel_pending)
3164a574db85Sraf 				schedctl_cancel_eintr();
31657c478bd9Sstevel@tonic-gate 			lwp->lwp_sysabort = 0;
31667c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
31677c478bd9Sstevel@tonic-gate 			error = EINTR;
31687c478bd9Sstevel@tonic-gate 			/*
31697c478bd9Sstevel@tonic-gate 			 * If the server has finished processing our call,
31707c478bd9Sstevel@tonic-gate 			 * or exited (calling door_slam()), then d_error
31717c478bd9Sstevel@tonic-gate 			 * will have changed.  If the server hasn't finished
31727c478bd9Sstevel@tonic-gate 			 * yet, d_error will still be DOOR_WAIT, and we
31737c478bd9Sstevel@tonic-gate 			 * let it know we are not interested in any
31747c478bd9Sstevel@tonic-gate 			 * results by sending a SIGCANCEL, unless the door
31757c478bd9Sstevel@tonic-gate 			 * is marked with DOOR_NO_CANCEL.
31767c478bd9Sstevel@tonic-gate 			 */
31777c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT &&
31787c478bd9Sstevel@tonic-gate 			    st->d_caller == curthread) {
31797c478bd9Sstevel@tonic-gate 				proc_t	*p = ttoproc(server_thread);
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate 				st->d_active = NULL;
31827c478bd9Sstevel@tonic-gate 				st->d_caller = NULL;
31837c478bd9Sstevel@tonic-gate 				if (!(dp->door_flags & DOOR_NO_CANCEL)) {
31847c478bd9Sstevel@tonic-gate 					DOOR_T_HOLD(st);
31857c478bd9Sstevel@tonic-gate 					mutex_exit(&door_knob);
31867c478bd9Sstevel@tonic-gate 
31877c478bd9Sstevel@tonic-gate 					mutex_enter(&p->p_lock);
31887c478bd9Sstevel@tonic-gate 					sigtoproc(p, server_thread, SIGCANCEL);
31897c478bd9Sstevel@tonic-gate 					mutex_exit(&p->p_lock);
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 					mutex_enter(&door_knob);
31927c478bd9Sstevel@tonic-gate 					DOOR_T_RELEASE(st);
31937c478bd9Sstevel@tonic-gate 				}
31947c478bd9Sstevel@tonic-gate 			}
31957c478bd9Sstevel@tonic-gate 		} else {
31967c478bd9Sstevel@tonic-gate 			/*
31977c478bd9Sstevel@tonic-gate 			 * Return from stop(), server exit...
31987c478bd9Sstevel@tonic-gate 			 *
31997c478bd9Sstevel@tonic-gate 			 * Note that the server could have done a
32007c478bd9Sstevel@tonic-gate 			 * door_return while the client was in stop state
32017c478bd9Sstevel@tonic-gate 			 * (ISSIG), in which case the error condition
32027c478bd9Sstevel@tonic-gate 			 * is updated by the server.
32037c478bd9Sstevel@tonic-gate 			 */
32047c478bd9Sstevel@tonic-gate 			mutex_enter(&door_knob);
32057c478bd9Sstevel@tonic-gate 			if (ct->d_error == DOOR_WAIT) {
32067c478bd9Sstevel@tonic-gate 				/* Still waiting for a reply */
32077c478bd9Sstevel@tonic-gate 				shuttle_swtch(&door_knob);
32087c478bd9Sstevel@tonic-gate 				mutex_enter(&door_knob);
32097c478bd9Sstevel@tonic-gate 				if (lwp)
32107c478bd9Sstevel@tonic-gate 					lwp->lwp_asleep = 0;
32117c478bd9Sstevel@tonic-gate 				goto	shuttle_return;
32127c478bd9Sstevel@tonic-gate 			} else if (ct->d_error == DOOR_EXIT) {
32137c478bd9Sstevel@tonic-gate 				/* Server exit */
32147c478bd9Sstevel@tonic-gate 				error = EINTR;
32157c478bd9Sstevel@tonic-gate 			} else {
32167c478bd9Sstevel@tonic-gate 				/* Server did a door_return during ISSIG */
32177c478bd9Sstevel@tonic-gate 				error = ct->d_error;
32187c478bd9Sstevel@tonic-gate 			}
32197c478bd9Sstevel@tonic-gate 		}
32207c478bd9Sstevel@tonic-gate 		/*
32217c478bd9Sstevel@tonic-gate 		 * Can't exit if the server is currently copying
32227c478bd9Sstevel@tonic-gate 		 * results for me
32237c478bd9Sstevel@tonic-gate 		 */
32247c478bd9Sstevel@tonic-gate 		while (DOOR_T_HELD(ct))
32257c478bd9Sstevel@tonic-gate 			cv_wait(&ct->d_cv, &door_knob);
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate 		/*
32287c478bd9Sstevel@tonic-gate 		 * Find out if results were successfully copied.
32297c478bd9Sstevel@tonic-gate 		 */
32307c478bd9Sstevel@tonic-gate 		if (ct->d_error == 0)
32317c478bd9Sstevel@tonic-gate 			gotresults = 1;
32327c478bd9Sstevel@tonic-gate 	}
32337c478bd9Sstevel@tonic-gate 	if (lwp) {
32347c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 0;		/* /proc */
32357c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 0;		/* /proc */
32367c478bd9Sstevel@tonic-gate 	}
32377c478bd9Sstevel@tonic-gate 	if (--dp->door_active == 0 && (dp->door_flags & DOOR_DELAY))
32387c478bd9Sstevel@tonic-gate 		door_deliver_unref(dp);
32397c478bd9Sstevel@tonic-gate 	mutex_exit(&door_knob);
32407c478bd9Sstevel@tonic-gate 
32417c478bd9Sstevel@tonic-gate 	/*
32427c478bd9Sstevel@tonic-gate 	 * Translate returned doors (if any)
32437c478bd9Sstevel@tonic-gate 	 */
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 	if (ct->d_noresults)
32467c478bd9Sstevel@tonic-gate 		goto out;
32477c478bd9Sstevel@tonic-gate 
32487c478bd9Sstevel@tonic-gate 	if (error) {
32497c478bd9Sstevel@tonic-gate 		/*
32507c478bd9Sstevel@tonic-gate 		 * If server returned results successfully, then we've
32517c478bd9Sstevel@tonic-gate 		 * been interrupted and may need to clean up.
32527c478bd9Sstevel@tonic-gate 		 */
32537c478bd9Sstevel@tonic-gate 		if (gotresults) {
32547c478bd9Sstevel@tonic-gate 			ASSERT(error == EINTR);
32557c478bd9Sstevel@tonic-gate 			door_fp_close(ct->d_fpp, ct->d_args.desc_num);
32567c478bd9Sstevel@tonic-gate 		}
32577c478bd9Sstevel@tonic-gate 		goto out;
32587c478bd9Sstevel@tonic-gate 	}
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	if (ct->d_args.desc_num) {
32617c478bd9Sstevel@tonic-gate 		struct file	**fpp;
32627c478bd9Sstevel@tonic-gate 		door_desc_t	*didpp;
32637c478bd9Sstevel@tonic-gate 		vnode_t		*vp;
32647c478bd9Sstevel@tonic-gate 		uint_t		n = ct->d_args.desc_num;
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate 		didpp = ct->d_args.desc_ptr = (door_desc_t *)(ct->d_args.rbuf +
32677c478bd9Sstevel@tonic-gate 		    roundup(ct->d_args.data_size, sizeof (door_desc_t)));
32687c478bd9Sstevel@tonic-gate 		fpp = ct->d_fpp;
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 		while (n--) {
32717c478bd9Sstevel@tonic-gate 			struct file *fp;
32727c478bd9Sstevel@tonic-gate 
32737c478bd9Sstevel@tonic-gate 			fp = *fpp;
3274da6c28aaSamw 			if (VOP_REALVP(fp->f_vnode, &vp, NULL))
32757c478bd9Sstevel@tonic-gate 				vp = fp->f_vnode;
32767c478bd9Sstevel@tonic-gate 
32777c478bd9Sstevel@tonic-gate 			didpp->d_attributes = DOOR_HANDLE |
32787c478bd9Sstevel@tonic-gate 			    (VTOD(vp)->door_flags & DOOR_ATTR_MASK);
32797c478bd9Sstevel@tonic-gate 			didpp->d_data.d_handle = FTODH(fp);
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 			fpp++; didpp++;
32827c478bd9Sstevel@tonic-gate 		}
32837c478bd9Sstevel@tonic-gate 	}
32847c478bd9Sstevel@tonic-gate 
32857c478bd9Sstevel@tonic-gate 	/* on return data is in rbuf */
32867c478bd9Sstevel@tonic-gate 	*param = ct->d_args;		/* structure assignment */
32877c478bd9Sstevel@tonic-gate 
32887c478bd9Sstevel@tonic-gate out:
32897c478bd9Sstevel@tonic-gate 	if (ct->d_fpp) {
32907c478bd9Sstevel@tonic-gate 		kmem_free(ct->d_fpp, ct->d_fpp_size);
32917c478bd9Sstevel@tonic-gate 		ct->d_fpp = NULL;
32927c478bd9Sstevel@tonic-gate 		ct->d_fpp_size = 0;
32937c478bd9Sstevel@tonic-gate 	}
32947c478bd9Sstevel@tonic-gate 
3295024b0a25Sseb 	ct->d_cred = NULL;
32967c478bd9Sstevel@tonic-gate 	ct->d_upcall = 0;
32977c478bd9Sstevel@tonic-gate 	ct->d_noresults = 0;
32987c478bd9Sstevel@tonic-gate 	ct->d_buf = NULL;
32997c478bd9Sstevel@tonic-gate 	ct->d_bufsize = 0;
33007c478bd9Sstevel@tonic-gate 	return (error);
33017c478bd9Sstevel@tonic-gate }
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate /*
33047c478bd9Sstevel@tonic-gate  * Add a door to the per-process list of active doors for which the
33057c478bd9Sstevel@tonic-gate  * process is a server.
33067c478bd9Sstevel@tonic-gate  */
33077c478bd9Sstevel@tonic-gate static void
33087c478bd9Sstevel@tonic-gate door_list_insert(door_node_t *dp)
33097c478bd9Sstevel@tonic-gate {
33107c478bd9Sstevel@tonic-gate 	proc_t *p = dp->door_target;
33117c478bd9Sstevel@tonic-gate 
33127c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
33137c478bd9Sstevel@tonic-gate 	dp->door_list = p->p_door_list;
33147c478bd9Sstevel@tonic-gate 	p->p_door_list = dp;
33157c478bd9Sstevel@tonic-gate }
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate /*
33187c478bd9Sstevel@tonic-gate  * Remove a door from the per-process list of active doors.
33197c478bd9Sstevel@tonic-gate  */
33207c478bd9Sstevel@tonic-gate void
33217c478bd9Sstevel@tonic-gate door_list_delete(door_node_t *dp)
33227c478bd9Sstevel@tonic-gate {
33237c478bd9Sstevel@tonic-gate 	door_node_t **pp;
33247c478bd9Sstevel@tonic-gate 
33257c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&door_knob));
33267c478bd9Sstevel@tonic-gate 	/*
33277c478bd9Sstevel@tonic-gate 	 * Find the door in the list.  If the door belongs to another process,
33287c478bd9Sstevel@tonic-gate 	 * it's OK to use p_door_list since that process can't exit until all
33297c478bd9Sstevel@tonic-gate 	 * doors have been taken off the list (see door_exit).
33307c478bd9Sstevel@tonic-gate 	 */
33317c478bd9Sstevel@tonic-gate 	pp = &(dp->door_target->p_door_list);
33327c478bd9Sstevel@tonic-gate 	while (*pp != dp)
33337c478bd9Sstevel@tonic-gate 		pp = &((*pp)->door_list);
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 	/* found it, take it off the list */
33367c478bd9Sstevel@tonic-gate 	*pp = dp->door_list;
33377c478bd9Sstevel@tonic-gate }
33387c478bd9Sstevel@tonic-gate 
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate /*
33417c478bd9Sstevel@tonic-gate  * External kernel interfaces for doors.  These functions are available
33427c478bd9Sstevel@tonic-gate  * outside the doorfs module for use in creating and using doors from
33437c478bd9Sstevel@tonic-gate  * within the kernel.
33447c478bd9Sstevel@tonic-gate  */
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate /*
3347024b0a25Sseb  * door_ki_upcall invokes a user-level door server from the kernel, with
3348024b0a25Sseb  * the credentials associated with curthread.
33497c478bd9Sstevel@tonic-gate  */
33507c478bd9Sstevel@tonic-gate int
33517c478bd9Sstevel@tonic-gate door_ki_upcall(door_handle_t dh, door_arg_t *param)
3352024b0a25Sseb {
3353024b0a25Sseb 	return (door_ki_upcall_cred(dh, param, NULL));
3354024b0a25Sseb }
3355024b0a25Sseb 
3356024b0a25Sseb /*
3357024b0a25Sseb  * door_ki_upcall_cred invokes a user-level door server from the kernel with
3358024b0a25Sseb  * the given credentials. If the "cred" argument is NULL, uses the credentials
3359024b0a25Sseb  * associated with current thread.
3360024b0a25Sseb  */
3361024b0a25Sseb int
3362024b0a25Sseb door_ki_upcall_cred(door_handle_t dh, door_arg_t *param, struct cred *cred)
33637c478bd9Sstevel@tonic-gate {
33647c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
33657c478bd9Sstevel@tonic-gate 	vnode_t *realvp;
33667c478bd9Sstevel@tonic-gate 
3367da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
33687c478bd9Sstevel@tonic-gate 		realvp = fp->f_vnode;
3369024b0a25Sseb 	return (door_upcall(realvp, param, cred));
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate /*
33737c478bd9Sstevel@tonic-gate  * Function call to create a "kernel" door server.  A kernel door
33747c478bd9Sstevel@tonic-gate  * server provides a way for a user-level process to invoke a function
33757c478bd9Sstevel@tonic-gate  * in the kernel through a door_call.  From the caller's point of
33767c478bd9Sstevel@tonic-gate  * view, a kernel door server looks the same as a user-level one
33777c478bd9Sstevel@tonic-gate  * (except the server pid is 0).  Unlike normal door calls, the
33787c478bd9Sstevel@tonic-gate  * kernel door function is invoked via a normal function call in the
33797c478bd9Sstevel@tonic-gate  * same thread and context as the caller.
33807c478bd9Sstevel@tonic-gate  */
33817c478bd9Sstevel@tonic-gate int
33827c478bd9Sstevel@tonic-gate door_ki_create(void (*pc_cookie)(), void *data_cookie, uint_t attributes,
33837c478bd9Sstevel@tonic-gate     door_handle_t *dhp)
33847c478bd9Sstevel@tonic-gate {
33857c478bd9Sstevel@tonic-gate 	int err;
33867c478bd9Sstevel@tonic-gate 	file_t *fp;
33877c478bd9Sstevel@tonic-gate 
33887c478bd9Sstevel@tonic-gate 	/* no DOOR_PRIVATE */
33897c478bd9Sstevel@tonic-gate 	if ((attributes & ~DOOR_KI_CREATE_MASK) ||
33907c478bd9Sstevel@tonic-gate 	    (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) ==
33917c478bd9Sstevel@tonic-gate 	    (DOOR_UNREF | DOOR_UNREF_MULTI))
33927c478bd9Sstevel@tonic-gate 		return (EINVAL);
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate 	err = door_create_common(pc_cookie, data_cookie, attributes,
33957c478bd9Sstevel@tonic-gate 	    1, NULL, &fp);
33967c478bd9Sstevel@tonic-gate 	if (err == 0 && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI)) &&
33977c478bd9Sstevel@tonic-gate 	    p0.p_unref_thread == 0) {
33987c478bd9Sstevel@tonic-gate 		/* need to create unref thread for process 0 */
33997c478bd9Sstevel@tonic-gate 		(void) thread_create(NULL, 0, door_unref_kernel, NULL, 0, &p0,
34007c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
34017c478bd9Sstevel@tonic-gate 	}
34027c478bd9Sstevel@tonic-gate 	if (err == 0) {
34037c478bd9Sstevel@tonic-gate 		*dhp = FTODH(fp);
34047c478bd9Sstevel@tonic-gate 	}
34057c478bd9Sstevel@tonic-gate 	return (err);
34067c478bd9Sstevel@tonic-gate }
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate void
34097c478bd9Sstevel@tonic-gate door_ki_hold(door_handle_t dh)
34107c478bd9Sstevel@tonic-gate {
34117c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34127c478bd9Sstevel@tonic-gate 
34137c478bd9Sstevel@tonic-gate 	mutex_enter(&fp->f_tlock);
34147c478bd9Sstevel@tonic-gate 	fp->f_count++;
34157c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
34167c478bd9Sstevel@tonic-gate }
34177c478bd9Sstevel@tonic-gate 
34187c478bd9Sstevel@tonic-gate void
34197c478bd9Sstevel@tonic-gate door_ki_rele(door_handle_t dh)
34207c478bd9Sstevel@tonic-gate {
34217c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate 	(void) closef(fp);
34247c478bd9Sstevel@tonic-gate }
34257c478bd9Sstevel@tonic-gate 
34267c478bd9Sstevel@tonic-gate int
34277c478bd9Sstevel@tonic-gate door_ki_open(char *pathname, door_handle_t *dhp)
34287c478bd9Sstevel@tonic-gate {
34297c478bd9Sstevel@tonic-gate 	file_t *fp;
34307c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34317c478bd9Sstevel@tonic-gate 	int err;
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate 	if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
34347c478bd9Sstevel@tonic-gate 		return (err);
3435da6c28aaSamw 	if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
34367c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
34377c478bd9Sstevel@tonic-gate 		return (err);
34387c478bd9Sstevel@tonic-gate 	}
34397c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
34407c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
34417c478bd9Sstevel@tonic-gate 		return (EINVAL);
34427c478bd9Sstevel@tonic-gate 	}
34437c478bd9Sstevel@tonic-gate 	if ((err = falloc(vp, FREAD | FWRITE, &fp, NULL)) != 0) {
34447c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
34457c478bd9Sstevel@tonic-gate 		return (err);
34467c478bd9Sstevel@tonic-gate 	}
34477c478bd9Sstevel@tonic-gate 	/* falloc returns with f_tlock held on success */
34487c478bd9Sstevel@tonic-gate 	mutex_exit(&fp->f_tlock);
34497c478bd9Sstevel@tonic-gate 	*dhp = FTODH(fp);
34507c478bd9Sstevel@tonic-gate 	return (0);
34517c478bd9Sstevel@tonic-gate }
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate int
34547c478bd9Sstevel@tonic-gate door_ki_info(door_handle_t dh, struct door_info *dip)
34557c478bd9Sstevel@tonic-gate {
34567c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34577c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34587c478bd9Sstevel@tonic-gate 
3459da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
34607c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
34617c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
34627c478bd9Sstevel@tonic-gate 		return (EINVAL);
34637c478bd9Sstevel@tonic-gate 	door_info_common(VTOD(vp), dip, fp);
34647c478bd9Sstevel@tonic-gate 	return (0);
34657c478bd9Sstevel@tonic-gate }
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate door_handle_t
34687c478bd9Sstevel@tonic-gate door_ki_lookup(int did)
34697c478bd9Sstevel@tonic-gate {
34707c478bd9Sstevel@tonic-gate 	file_t *fp;
34717c478bd9Sstevel@tonic-gate 	door_handle_t dh;
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 	/* is the descriptor really a door? */
34747c478bd9Sstevel@tonic-gate 	if (door_lookup(did, &fp) == NULL)
34757c478bd9Sstevel@tonic-gate 		return (NULL);
34767c478bd9Sstevel@tonic-gate 	/* got the door, put a hold on it and release the fd */
34777c478bd9Sstevel@tonic-gate 	dh = FTODH(fp);
34787c478bd9Sstevel@tonic-gate 	door_ki_hold(dh);
34797c478bd9Sstevel@tonic-gate 	releasef(did);
34807c478bd9Sstevel@tonic-gate 	return (dh);
34817c478bd9Sstevel@tonic-gate }
34827c478bd9Sstevel@tonic-gate 
34837c478bd9Sstevel@tonic-gate int
34847c478bd9Sstevel@tonic-gate door_ki_setparam(door_handle_t dh, int type, size_t val)
34857c478bd9Sstevel@tonic-gate {
34867c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
34877c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34887c478bd9Sstevel@tonic-gate 
3489da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
34907c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
34917c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
34927c478bd9Sstevel@tonic-gate 		return (EINVAL);
34937c478bd9Sstevel@tonic-gate 	return (door_setparam_common(VTOD(vp), 1, type, val));
34947c478bd9Sstevel@tonic-gate }
34957c478bd9Sstevel@tonic-gate 
34967c478bd9Sstevel@tonic-gate int
34977c478bd9Sstevel@tonic-gate door_ki_getparam(door_handle_t dh, int type, size_t *out)
34987c478bd9Sstevel@tonic-gate {
34997c478bd9Sstevel@tonic-gate 	file_t *fp = DHTOF(dh);
35007c478bd9Sstevel@tonic-gate 	vnode_t *vp;
35017c478bd9Sstevel@tonic-gate 
3502da6c28aaSamw 	if (VOP_REALVP(fp->f_vnode, &vp, NULL))
35037c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
35047c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR)
35057c478bd9Sstevel@tonic-gate 		return (EINVAL);
35067c478bd9Sstevel@tonic-gate 	return (door_getparam_common(VTOD(vp), type, out));
35077c478bd9Sstevel@tonic-gate }
3508