xref: /titanic_44/usr/src/uts/common/os/aio.c (revision d2749ac6e20fe35dbfa822f9b55c185325a2147e)
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
534709573Sraf  * Common Development and Distribution License (the "License").
634709573Sraf  * 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  */
2134709573Sraf 
227c478bd9Sstevel@tonic-gate /*
23dd1e66b6SVamsi Nagineni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Kernel asynchronous I/O.
297c478bd9Sstevel@tonic-gate  * This is only for raw devices now (as of Nov. 1993).
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/errno.h>
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/file.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
377c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
397c478bd9Sstevel@tonic-gate #include <vm/as.h>
407c478bd9Sstevel@tonic-gate #include <vm/faultcode.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
457c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/aio_impl.h>
487c478bd9Sstevel@tonic-gate #include <sys/debug.h>
497c478bd9Sstevel@tonic-gate #include <sys/param.h>
507c478bd9Sstevel@tonic-gate #include <sys/systm.h>
517c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
527c478bd9Sstevel@tonic-gate #include <sys/fs/pxfs_ki.h>
537c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * external entry point.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate #ifdef _LP64
597c478bd9Sstevel@tonic-gate static int64_t kaioc(long, long, long, long, long, long);
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate static int kaio(ulong_t *, rval_t *);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	AIO_64	0
657c478bd9Sstevel@tonic-gate #define	AIO_32	1
667c478bd9Sstevel@tonic-gate #define	AIO_LARGEFILE	2
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * implementation specific functions (private)
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate #ifdef _LP64
7234709573Sraf static int alio(int, aiocb_t **, int, struct sigevent *);
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate static int aionotify(void);
757c478bd9Sstevel@tonic-gate static int aioinit(void);
767c478bd9Sstevel@tonic-gate static int aiostart(void);
777c478bd9Sstevel@tonic-gate static void alio_cleanup(aio_t *, aiocb_t **, int, int);
787c478bd9Sstevel@tonic-gate static int (*check_vp(struct vnode *, int))(vnode_t *, struct aio_req *,
797c478bd9Sstevel@tonic-gate     cred_t *);
8034b3058fSpraks static void lio_set_error(aio_req_t *, int portused);
817c478bd9Sstevel@tonic-gate static aio_t *aio_aiop_alloc();
827c478bd9Sstevel@tonic-gate static int aio_req_alloc(aio_req_t **, aio_result_t *);
837c478bd9Sstevel@tonic-gate static int aio_lio_alloc(aio_lio_t **);
847c478bd9Sstevel@tonic-gate static aio_req_t *aio_req_done(void *);
857c478bd9Sstevel@tonic-gate static aio_req_t *aio_req_remove(aio_req_t *);
867c478bd9Sstevel@tonic-gate static int aio_req_find(aio_result_t *, aio_req_t **);
877c478bd9Sstevel@tonic-gate static int aio_hash_insert(struct aio_req_t *, aio_t *);
887c478bd9Sstevel@tonic-gate static int aio_req_setup(aio_req_t **, aio_t *, aiocb_t *,
89*d2749ac6SRoger A. Faulkner     aio_result_t *, vnode_t *, int);
907c478bd9Sstevel@tonic-gate static int aio_cleanup_thread(aio_t *);
917c478bd9Sstevel@tonic-gate static aio_lio_t *aio_list_get(aio_result_t *);
927c478bd9Sstevel@tonic-gate static void lio_set_uerror(void *, int);
937c478bd9Sstevel@tonic-gate extern void aio_zerolen(aio_req_t *);
947c478bd9Sstevel@tonic-gate static int aiowait(struct timeval *, int, long	*);
957c478bd9Sstevel@tonic-gate static int aiowaitn(void *, uint_t, uint_t *, timespec_t *);
967c478bd9Sstevel@tonic-gate static int aio_unlock_requests(caddr_t iocblist, int iocb_index,
977c478bd9Sstevel@tonic-gate     aio_req_t *reqlist, aio_t *aiop, model_t model);
987c478bd9Sstevel@tonic-gate static int aio_reqlist_concat(aio_t *aiop, aio_req_t **reqlist, int max);
997c478bd9Sstevel@tonic-gate static int aiosuspend(void *, int, struct  timespec *, int,
1007c478bd9Sstevel@tonic-gate     long	*, int);
1017c478bd9Sstevel@tonic-gate static int aliowait(int, void *, int, void *, int);
1027c478bd9Sstevel@tonic-gate static int aioerror(void *, int);
1037c478bd9Sstevel@tonic-gate static int aio_cancel(int, void *, long	*, int);
1047c478bd9Sstevel@tonic-gate static int arw(int, int, char *, int, offset_t, aio_result_t *, int);
1057c478bd9Sstevel@tonic-gate static int aiorw(int, void *, int, int);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static int alioLF(int, void *, int, void *);
10834709573Sraf static int aio_req_setupLF(aio_req_t **, aio_t *, aiocb64_32_t *,
109*d2749ac6SRoger A. Faulkner     aio_result_t *, vnode_t *, int);
1107c478bd9Sstevel@tonic-gate static int alio32(int, void *, int, void *);
1117c478bd9Sstevel@tonic-gate static int driver_aio_write(vnode_t *vp, struct aio_req *aio, cred_t *cred_p);
1127c478bd9Sstevel@tonic-gate static int driver_aio_read(vnode_t *vp, struct aio_req *aio, cred_t *cred_p);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
1157c478bd9Sstevel@tonic-gate static void aiocb_LFton(aiocb64_32_t *, aiocb_t *);
1167c478bd9Sstevel@tonic-gate void	aiocb_32ton(aiocb32_t *, aiocb_t *);
1177c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * implementation specific functions (external)
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate void aio_req_free(aio_t *, aio_req_t *);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Event Port framework
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate void aio_req_free_port(aio_t *, aio_req_t *);
1297c478bd9Sstevel@tonic-gate static int aio_port_callback(void *, int *, pid_t, int, void *);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
1357c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate #ifdef _LP64
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent = {
1407c478bd9Sstevel@tonic-gate 	6,
1417c478bd9Sstevel@tonic-gate 	SE_NOUNLOAD | SE_64RVAL | SE_ARGC,
1427c478bd9Sstevel@tonic-gate 	(int (*)())kaioc
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1467c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent32 = {
1477c478bd9Sstevel@tonic-gate 	7,
1487c478bd9Sstevel@tonic-gate 	SE_NOUNLOAD | SE_64RVAL,
1497c478bd9Sstevel@tonic-gate 	kaio
1507c478bd9Sstevel@tonic-gate };
1517c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate #else   /* _LP64 */
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate static struct sysent kaio_sysent = {
1567c478bd9Sstevel@tonic-gate 	7,
1577c478bd9Sstevel@tonic-gate 	SE_NOUNLOAD | SE_32RVAL1,
1587c478bd9Sstevel@tonic-gate 	kaio
1597c478bd9Sstevel@tonic-gate };
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate #endif  /* _LP64 */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1687c478bd9Sstevel@tonic-gate 	&mod_syscallops,
1697c478bd9Sstevel@tonic-gate 	"kernel Async I/O",
1707c478bd9Sstevel@tonic-gate 	&kaio_sysent
1717c478bd9Sstevel@tonic-gate };
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
1747c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1757c478bd9Sstevel@tonic-gate 	&mod_syscallops32,
1767c478bd9Sstevel@tonic-gate 	"kernel Async I/O for 32 bit compatibility",
1777c478bd9Sstevel@tonic-gate 	&kaio_sysent32
1787c478bd9Sstevel@tonic-gate };
1797c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1837c478bd9Sstevel@tonic-gate 	MODREV_1,
1847c478bd9Sstevel@tonic-gate 	&modlsys,
1857c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
1867c478bd9Sstevel@tonic-gate 	&modlsys32,
1877c478bd9Sstevel@tonic-gate #endif
1887c478bd9Sstevel@tonic-gate 	NULL
1897c478bd9Sstevel@tonic-gate };
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate int
_init(void)1927c478bd9Sstevel@tonic-gate _init(void)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	int retval;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if ((retval = mod_install(&modlinkage)) != 0)
1977c478bd9Sstevel@tonic-gate 		return (retval);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (0);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate int
_fini(void)2037c478bd9Sstevel@tonic-gate _fini(void)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	int retval;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	retval = mod_remove(&modlinkage);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	return (retval);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2137c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate #ifdef	_LP64
2197c478bd9Sstevel@tonic-gate static int64_t
kaioc(long a0,long a1,long a2,long a3,long a4,long a5)2207c478bd9Sstevel@tonic-gate kaioc(
2217c478bd9Sstevel@tonic-gate 	long	a0,
2227c478bd9Sstevel@tonic-gate 	long	a1,
2237c478bd9Sstevel@tonic-gate 	long	a2,
2247c478bd9Sstevel@tonic-gate 	long	a3,
2257c478bd9Sstevel@tonic-gate 	long	a4,
2267c478bd9Sstevel@tonic-gate 	long	a5)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	int	error;
2297c478bd9Sstevel@tonic-gate 	long	rval = 0;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	switch ((int)a0 & ~AIO_POLL_BIT) {
2327c478bd9Sstevel@tonic-gate 	case AIOREAD:
2337c478bd9Sstevel@tonic-gate 		error = arw((int)a0, (int)a1, (char *)a2, (int)a3,
2347c478bd9Sstevel@tonic-gate 		    (offset_t)a4, (aio_result_t *)a5, FREAD);
2357c478bd9Sstevel@tonic-gate 		break;
2367c478bd9Sstevel@tonic-gate 	case AIOWRITE:
2377c478bd9Sstevel@tonic-gate 		error = arw((int)a0, (int)a1, (char *)a2, (int)a3,
2387c478bd9Sstevel@tonic-gate 		    (offset_t)a4, (aio_result_t *)a5, FWRITE);
2397c478bd9Sstevel@tonic-gate 		break;
2407c478bd9Sstevel@tonic-gate 	case AIOWAIT:
2417c478bd9Sstevel@tonic-gate 		error = aiowait((struct timeval *)a1, (int)a2, &rval);
2427c478bd9Sstevel@tonic-gate 		break;
2437c478bd9Sstevel@tonic-gate 	case AIOWAITN:
2447c478bd9Sstevel@tonic-gate 		error = aiowaitn((void *)a1, (uint_t)a2, (uint_t *)a3,
2457c478bd9Sstevel@tonic-gate 		    (timespec_t *)a4);
2467c478bd9Sstevel@tonic-gate 		break;
2477c478bd9Sstevel@tonic-gate 	case AIONOTIFY:
2487c478bd9Sstevel@tonic-gate 		error = aionotify();
2497c478bd9Sstevel@tonic-gate 		break;
2507c478bd9Sstevel@tonic-gate 	case AIOINIT:
2517c478bd9Sstevel@tonic-gate 		error = aioinit();
2527c478bd9Sstevel@tonic-gate 		break;
2537c478bd9Sstevel@tonic-gate 	case AIOSTART:
2547c478bd9Sstevel@tonic-gate 		error = aiostart();
2557c478bd9Sstevel@tonic-gate 		break;
2567c478bd9Sstevel@tonic-gate 	case AIOLIO:
25734709573Sraf 		error = alio((int)a1, (aiocb_t **)a2, (int)a3,
2587c478bd9Sstevel@tonic-gate 		    (struct sigevent *)a4);
2597c478bd9Sstevel@tonic-gate 		break;
2607c478bd9Sstevel@tonic-gate 	case AIOLIOWAIT:
2617c478bd9Sstevel@tonic-gate 		error = aliowait((int)a1, (void *)a2, (int)a3,
2627c478bd9Sstevel@tonic-gate 		    (struct sigevent *)a4, AIO_64);
2637c478bd9Sstevel@tonic-gate 		break;
2647c478bd9Sstevel@tonic-gate 	case AIOSUSPEND:
2657c478bd9Sstevel@tonic-gate 		error = aiosuspend((void *)a1, (int)a2, (timespec_t *)a3,
2667c478bd9Sstevel@tonic-gate 		    (int)a4, &rval, AIO_64);
2677c478bd9Sstevel@tonic-gate 		break;
2687c478bd9Sstevel@tonic-gate 	case AIOERROR:
2697c478bd9Sstevel@tonic-gate 		error = aioerror((void *)a1, AIO_64);
2707c478bd9Sstevel@tonic-gate 		break;
2717c478bd9Sstevel@tonic-gate 	case AIOAREAD:
2727c478bd9Sstevel@tonic-gate 		error = aiorw((int)a0, (void *)a1, FREAD, AIO_64);
2737c478bd9Sstevel@tonic-gate 		break;
2747c478bd9Sstevel@tonic-gate 	case AIOAWRITE:
2757c478bd9Sstevel@tonic-gate 		error = aiorw((int)a0, (void *)a1, FWRITE, AIO_64);
2767c478bd9Sstevel@tonic-gate 		break;
2777c478bd9Sstevel@tonic-gate 	case AIOCANCEL:
2787c478bd9Sstevel@tonic-gate 		error = aio_cancel((int)a1, (void *)a2, &rval, AIO_64);
2797c478bd9Sstevel@tonic-gate 		break;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/*
2827c478bd9Sstevel@tonic-gate 	 * The large file related stuff is valid only for
2837c478bd9Sstevel@tonic-gate 	 * 32 bit kernel and not for 64 bit kernel
2847c478bd9Sstevel@tonic-gate 	 * On 64 bit kernel we convert large file calls
2857c478bd9Sstevel@tonic-gate 	 * to regular 64bit calls.
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	default:
2897c478bd9Sstevel@tonic-gate 		error = EINVAL;
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	if (error)
2927c478bd9Sstevel@tonic-gate 		return ((int64_t)set_errno(error));
2937c478bd9Sstevel@tonic-gate 	return (rval);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate #endif
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate static int
kaio(ulong_t * uap,rval_t * rvp)2987c478bd9Sstevel@tonic-gate kaio(
2997c478bd9Sstevel@tonic-gate 	ulong_t *uap,
3007c478bd9Sstevel@tonic-gate 	rval_t *rvp)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	long rval = 0;
3037c478bd9Sstevel@tonic-gate 	int	error = 0;
3047c478bd9Sstevel@tonic-gate 	offset_t	off;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		rvp->r_vals = 0;
3087c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN)
3097c478bd9Sstevel@tonic-gate 	off = ((u_offset_t)uap[5] << 32) | (u_offset_t)uap[4];
3107c478bd9Sstevel@tonic-gate #else
3117c478bd9Sstevel@tonic-gate 	off = ((u_offset_t)uap[4] << 32) | (u_offset_t)uap[5];
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	switch (uap[0] & ~AIO_POLL_BIT) {
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * It must be the 32 bit system call on 64 bit kernel
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	case AIOREAD:
3197c478bd9Sstevel@tonic-gate 		return (arw((int)uap[0], (int)uap[1], (char *)uap[2],
3207c478bd9Sstevel@tonic-gate 		    (int)uap[3], off, (aio_result_t *)uap[6], FREAD));
3217c478bd9Sstevel@tonic-gate 	case AIOWRITE:
3227c478bd9Sstevel@tonic-gate 		return (arw((int)uap[0], (int)uap[1], (char *)uap[2],
3237c478bd9Sstevel@tonic-gate 		    (int)uap[3], off, (aio_result_t *)uap[6], FWRITE));
3247c478bd9Sstevel@tonic-gate 	case AIOWAIT:
3257c478bd9Sstevel@tonic-gate 		error = aiowait((struct	timeval *)uap[1], (int)uap[2],
3267c478bd9Sstevel@tonic-gate 		    &rval);
3277c478bd9Sstevel@tonic-gate 		break;
3287c478bd9Sstevel@tonic-gate 	case AIOWAITN:
3297c478bd9Sstevel@tonic-gate 		error = aiowaitn((void *)uap[1], (uint_t)uap[2],
3307c478bd9Sstevel@tonic-gate 		    (uint_t *)uap[3], (timespec_t *)uap[4]);
3317c478bd9Sstevel@tonic-gate 		break;
3327c478bd9Sstevel@tonic-gate 	case AIONOTIFY:
3337c478bd9Sstevel@tonic-gate 		return (aionotify());
3347c478bd9Sstevel@tonic-gate 	case AIOINIT:
3357c478bd9Sstevel@tonic-gate 		return (aioinit());
3367c478bd9Sstevel@tonic-gate 	case AIOSTART:
3377c478bd9Sstevel@tonic-gate 		return (aiostart());
3387c478bd9Sstevel@tonic-gate 	case AIOLIO:
3397c478bd9Sstevel@tonic-gate 		return (alio32((int)uap[1], (void *)uap[2], (int)uap[3],
3407c478bd9Sstevel@tonic-gate 		    (void *)uap[4]));
3417c478bd9Sstevel@tonic-gate 	case AIOLIOWAIT:
3427c478bd9Sstevel@tonic-gate 		return (aliowait((int)uap[1], (void *)uap[2],
3437c478bd9Sstevel@tonic-gate 		    (int)uap[3], (struct sigevent *)uap[4], AIO_32));
3447c478bd9Sstevel@tonic-gate 	case AIOSUSPEND:
3457c478bd9Sstevel@tonic-gate 		error = aiosuspend((void *)uap[1], (int)uap[2],
3467c478bd9Sstevel@tonic-gate 		    (timespec_t *)uap[3], (int)uap[4],
3477c478bd9Sstevel@tonic-gate 		    &rval, AIO_32);
3487c478bd9Sstevel@tonic-gate 		break;
3497c478bd9Sstevel@tonic-gate 	case AIOERROR:
3507c478bd9Sstevel@tonic-gate 		return (aioerror((void *)uap[1], AIO_32));
3517c478bd9Sstevel@tonic-gate 	case AIOAREAD:
3527c478bd9Sstevel@tonic-gate 		return (aiorw((int)uap[0], (void *)uap[1],
3537c478bd9Sstevel@tonic-gate 		    FREAD, AIO_32));
3547c478bd9Sstevel@tonic-gate 	case AIOAWRITE:
3557c478bd9Sstevel@tonic-gate 		return (aiorw((int)uap[0], (void *)uap[1],
3567c478bd9Sstevel@tonic-gate 		    FWRITE, AIO_32));
3577c478bd9Sstevel@tonic-gate 	case AIOCANCEL:
3587c478bd9Sstevel@tonic-gate 		error = (aio_cancel((int)uap[1], (void *)uap[2], &rval,
3597c478bd9Sstevel@tonic-gate 		    AIO_32));
3607c478bd9Sstevel@tonic-gate 		break;
3617c478bd9Sstevel@tonic-gate 	case AIOLIO64:
3627c478bd9Sstevel@tonic-gate 		return (alioLF((int)uap[1], (void *)uap[2],
3637c478bd9Sstevel@tonic-gate 		    (int)uap[3], (void *)uap[4]));
3647c478bd9Sstevel@tonic-gate 	case AIOLIOWAIT64:
3657c478bd9Sstevel@tonic-gate 		return (aliowait(uap[1], (void *)uap[2],
3667c478bd9Sstevel@tonic-gate 		    (int)uap[3], (void *)uap[4], AIO_LARGEFILE));
3677c478bd9Sstevel@tonic-gate 	case AIOSUSPEND64:
3687c478bd9Sstevel@tonic-gate 		error = aiosuspend((void *)uap[1], (int)uap[2],
3697c478bd9Sstevel@tonic-gate 		    (timespec_t *)uap[3], (int)uap[4], &rval,
3707c478bd9Sstevel@tonic-gate 		    AIO_LARGEFILE);
3717c478bd9Sstevel@tonic-gate 		break;
3727c478bd9Sstevel@tonic-gate 	case AIOERROR64:
3737c478bd9Sstevel@tonic-gate 		return (aioerror((void *)uap[1], AIO_LARGEFILE));
3747c478bd9Sstevel@tonic-gate 	case AIOAREAD64:
3757c478bd9Sstevel@tonic-gate 		return (aiorw((int)uap[0], (void *)uap[1], FREAD,
3767c478bd9Sstevel@tonic-gate 		    AIO_LARGEFILE));
3777c478bd9Sstevel@tonic-gate 	case AIOAWRITE64:
3787c478bd9Sstevel@tonic-gate 		return (aiorw((int)uap[0], (void *)uap[1], FWRITE,
3797c478bd9Sstevel@tonic-gate 		    AIO_LARGEFILE));
3807c478bd9Sstevel@tonic-gate 	case AIOCANCEL64:
3817c478bd9Sstevel@tonic-gate 		error = (aio_cancel((int)uap[1], (void *)uap[2],
3827c478bd9Sstevel@tonic-gate 		    &rval, AIO_LARGEFILE));
3837c478bd9Sstevel@tonic-gate 		break;
3847c478bd9Sstevel@tonic-gate 	default:
3857c478bd9Sstevel@tonic-gate 		return (EINVAL);
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	rvp->r_val1 = rval;
3897c478bd9Sstevel@tonic-gate 	return (error);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * wake up LWPs in this process that are sleeping in
3947c478bd9Sstevel@tonic-gate  * aiowait().
3957c478bd9Sstevel@tonic-gate  */
3967c478bd9Sstevel@tonic-gate static int
aionotify(void)3977c478bd9Sstevel@tonic-gate aionotify(void)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	aio_t	*aiop;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
4027c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
4037c478bd9Sstevel@tonic-gate 		return (0);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
4067c478bd9Sstevel@tonic-gate 	aiop->aio_notifycnt++;
4077c478bd9Sstevel@tonic-gate 	cv_broadcast(&aiop->aio_waitcv);
4087c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	return (0);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate static int
timeval2reltime(struct timeval * timout,timestruc_t * rqtime,timestruc_t ** rqtp,int * blocking)4147c478bd9Sstevel@tonic-gate timeval2reltime(struct timeval *timout, timestruc_t *rqtime,
4157c478bd9Sstevel@tonic-gate 	timestruc_t **rqtp, int *blocking)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4187c478bd9Sstevel@tonic-gate 	struct timeval32 wait_time_32;
4197c478bd9Sstevel@tonic-gate #endif
4207c478bd9Sstevel@tonic-gate 	struct timeval wait_time;
4217c478bd9Sstevel@tonic-gate 	model_t	model = get_udatamodel();
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	*rqtp = NULL;
4247c478bd9Sstevel@tonic-gate 	if (timout == NULL) {		/* wait indefinitely */
4257c478bd9Sstevel@tonic-gate 		*blocking = 1;
4267c478bd9Sstevel@tonic-gate 		return (0);
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/*
4307c478bd9Sstevel@tonic-gate 	 * Need to correctly compare with the -1 passed in for a user
4317c478bd9Sstevel@tonic-gate 	 * address pointer, with both 32 bit and 64 bit apps.
4327c478bd9Sstevel@tonic-gate 	 */
4337c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE) {
4347c478bd9Sstevel@tonic-gate 		if ((intptr_t)timout == (intptr_t)-1) {	/* don't wait */
4357c478bd9Sstevel@tonic-gate 			*blocking = 0;
4367c478bd9Sstevel@tonic-gate 			return (0);
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		if (copyin(timout, &wait_time, sizeof (wait_time)))
4407c478bd9Sstevel@tonic-gate 			return (EFAULT);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4437c478bd9Sstevel@tonic-gate 	else {
4447c478bd9Sstevel@tonic-gate 		/*
4457c478bd9Sstevel@tonic-gate 		 * -1 from a 32bit app. It will not get sign extended.
4467c478bd9Sstevel@tonic-gate 		 * don't wait if -1.
4477c478bd9Sstevel@tonic-gate 		 */
4487c478bd9Sstevel@tonic-gate 		if ((intptr_t)timout == (intptr_t)((uint32_t)-1)) {
4497c478bd9Sstevel@tonic-gate 			*blocking = 0;
4507c478bd9Sstevel@tonic-gate 			return (0);
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		if (copyin(timout, &wait_time_32, sizeof (wait_time_32)))
4547c478bd9Sstevel@tonic-gate 			return (EFAULT);
4557c478bd9Sstevel@tonic-gate 		TIMEVAL32_TO_TIMEVAL(&wait_time, &wait_time_32);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (wait_time.tv_sec == 0 && wait_time.tv_usec == 0) {	/* don't wait */
4607c478bd9Sstevel@tonic-gate 		*blocking = 0;
4617c478bd9Sstevel@tonic-gate 		return (0);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	if (wait_time.tv_sec < 0 ||
4657c478bd9Sstevel@tonic-gate 	    wait_time.tv_usec < 0 || wait_time.tv_usec >= MICROSEC)
4667c478bd9Sstevel@tonic-gate 		return (EINVAL);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	rqtime->tv_sec = wait_time.tv_sec;
4697c478bd9Sstevel@tonic-gate 	rqtime->tv_nsec = wait_time.tv_usec * 1000;
4707c478bd9Sstevel@tonic-gate 	*rqtp = rqtime;
4717c478bd9Sstevel@tonic-gate 	*blocking = 1;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	return (0);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate static int
timespec2reltime(timespec_t * timout,timestruc_t * rqtime,timestruc_t ** rqtp,int * blocking)4777c478bd9Sstevel@tonic-gate timespec2reltime(timespec_t *timout, timestruc_t *rqtime,
4787c478bd9Sstevel@tonic-gate 	timestruc_t **rqtp, int *blocking)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4817c478bd9Sstevel@tonic-gate 	timespec32_t wait_time_32;
4827c478bd9Sstevel@tonic-gate #endif
4837c478bd9Sstevel@tonic-gate 	model_t	model = get_udatamodel();
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	*rqtp = NULL;
4867c478bd9Sstevel@tonic-gate 	if (timout == NULL) {
4877c478bd9Sstevel@tonic-gate 		*blocking = 1;
4887c478bd9Sstevel@tonic-gate 		return (0);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE) {
4927c478bd9Sstevel@tonic-gate 		if (copyin(timout, rqtime, sizeof (*rqtime)))
4937c478bd9Sstevel@tonic-gate 			return (EFAULT);
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4967c478bd9Sstevel@tonic-gate 	else {
4977c478bd9Sstevel@tonic-gate 		if (copyin(timout, &wait_time_32, sizeof (wait_time_32)))
4987c478bd9Sstevel@tonic-gate 			return (EFAULT);
4997c478bd9Sstevel@tonic-gate 		TIMESPEC32_TO_TIMESPEC(rqtime, &wait_time_32);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (rqtime->tv_sec == 0 && rqtime->tv_nsec == 0) {
5047c478bd9Sstevel@tonic-gate 		*blocking = 0;
5057c478bd9Sstevel@tonic-gate 		return (0);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	if (rqtime->tv_sec < 0 ||
5097c478bd9Sstevel@tonic-gate 	    rqtime->tv_nsec < 0 || rqtime->tv_nsec >= NANOSEC)
5107c478bd9Sstevel@tonic-gate 		return (EINVAL);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	*rqtp = rqtime;
5137c478bd9Sstevel@tonic-gate 	*blocking = 1;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	return (0);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5197c478bd9Sstevel@tonic-gate static int
aiowait(struct timeval * timout,int dontblockflg,long * rval)5207c478bd9Sstevel@tonic-gate aiowait(
5217c478bd9Sstevel@tonic-gate 	struct timeval	*timout,
5227c478bd9Sstevel@tonic-gate 	int	dontblockflg,
5237c478bd9Sstevel@tonic-gate 	long	*rval)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	int 		error;
5267c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
5277c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
5287c478bd9Sstevel@tonic-gate 	clock_t		status;
5297c478bd9Sstevel@tonic-gate 	int		blocking;
5303348528fSdm120769 	int		timecheck;
5317c478bd9Sstevel@tonic-gate 	timestruc_t	rqtime;
5327c478bd9Sstevel@tonic-gate 	timestruc_t	*rqtp;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
5357c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
5367c478bd9Sstevel@tonic-gate 		return (EINVAL);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/*
5397c478bd9Sstevel@tonic-gate 	 * Establish the absolute future time for the timeout.
5407c478bd9Sstevel@tonic-gate 	 */
5417c478bd9Sstevel@tonic-gate 	error = timeval2reltime(timout, &rqtime, &rqtp, &blocking);
5427c478bd9Sstevel@tonic-gate 	if (error)
5437c478bd9Sstevel@tonic-gate 		return (error);
5447c478bd9Sstevel@tonic-gate 	if (rqtp) {
5457c478bd9Sstevel@tonic-gate 		timestruc_t now;
5463348528fSdm120769 		timecheck = timechanged;
5477c478bd9Sstevel@tonic-gate 		gethrestime(&now);
5487c478bd9Sstevel@tonic-gate 		timespecadd(rqtp, &now);
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
5527c478bd9Sstevel@tonic-gate 	for (;;) {
5537c478bd9Sstevel@tonic-gate 		/* process requests on poll queue */
5547c478bd9Sstevel@tonic-gate 		if (aiop->aio_pollq) {
5557c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
5567c478bd9Sstevel@tonic-gate 			aio_cleanup(0);
5577c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 		if ((reqp = aio_req_remove(NULL)) != NULL) {
5607c478bd9Sstevel@tonic-gate 			*rval = (long)reqp->aio_req_resultp;
5617c478bd9Sstevel@tonic-gate 			break;
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 		/* user-level done queue might not be empty */
5647c478bd9Sstevel@tonic-gate 		if (aiop->aio_notifycnt > 0) {
5657c478bd9Sstevel@tonic-gate 			aiop->aio_notifycnt--;
5667c478bd9Sstevel@tonic-gate 			*rval = 1;
5677c478bd9Sstevel@tonic-gate 			break;
5687c478bd9Sstevel@tonic-gate 		}
5697c478bd9Sstevel@tonic-gate 		/* don't block if no outstanding aio */
5707c478bd9Sstevel@tonic-gate 		if (aiop->aio_outstanding == 0 && dontblockflg) {
5717c478bd9Sstevel@tonic-gate 			error = EINVAL;
5727c478bd9Sstevel@tonic-gate 			break;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 		if (blocking) {
5757c478bd9Sstevel@tonic-gate 			status = cv_waituntil_sig(&aiop->aio_waitcv,
5763348528fSdm120769 			    &aiop->aio_mutex, rqtp, timecheck);
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 			if (status > 0)		/* check done queue again */
5797c478bd9Sstevel@tonic-gate 				continue;
5807c478bd9Sstevel@tonic-gate 			if (status == 0) {	/* interrupted by a signal */
5817c478bd9Sstevel@tonic-gate 				error = EINTR;
5827c478bd9Sstevel@tonic-gate 				*rval = -1;
5837c478bd9Sstevel@tonic-gate 			} else {		/* timer expired */
5847c478bd9Sstevel@tonic-gate 				error = ETIME;
5857c478bd9Sstevel@tonic-gate 			}
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 		break;
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
5907c478bd9Sstevel@tonic-gate 	if (reqp) {
5917c478bd9Sstevel@tonic-gate 		aphysio_unlock(reqp);
5927c478bd9Sstevel@tonic-gate 		aio_copyout_result(reqp);
5937c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
5947c478bd9Sstevel@tonic-gate 		aio_req_free(aiop, reqp);
5957c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	return (error);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate  * aiowaitn can be used to reap completed asynchronous requests submitted with
6027c478bd9Sstevel@tonic-gate  * lio_listio, aio_read or aio_write.
6037c478bd9Sstevel@tonic-gate  * This function only reaps asynchronous raw I/Os.
6047c478bd9Sstevel@tonic-gate  */
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6077c478bd9Sstevel@tonic-gate static int
aiowaitn(void * uiocb,uint_t nent,uint_t * nwait,timespec_t * timout)6087c478bd9Sstevel@tonic-gate aiowaitn(void *uiocb, uint_t nent, uint_t *nwait, timespec_t *timout)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int 		error = 0;
6117c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
6127c478bd9Sstevel@tonic-gate 	aio_req_t	*reqlist = NULL;
6137c478bd9Sstevel@tonic-gate 	caddr_t		iocblist = NULL;	/* array of iocb ptr's */
6147c478bd9Sstevel@tonic-gate 	uint_t		waitcnt, cnt = 0;	/* iocb cnt */
6157c478bd9Sstevel@tonic-gate 	size_t		iocbsz;			/* users iocb size */
6167c478bd9Sstevel@tonic-gate 	size_t		riocbsz;		/* returned iocb size */
6177c478bd9Sstevel@tonic-gate 	int		iocb_index = 0;
6187c478bd9Sstevel@tonic-gate 	model_t		model = get_udatamodel();
6197c478bd9Sstevel@tonic-gate 	int		blocking = 1;
6203348528fSdm120769 	int		timecheck;
6217c478bd9Sstevel@tonic-gate 	timestruc_t	rqtime;
6227c478bd9Sstevel@tonic-gate 	timestruc_t	*rqtp;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
625dd1e66b6SVamsi Nagineni 	if (aiop == NULL || nent == 0 || nent > _AIO_LISTIO_MAX)
626dd1e66b6SVamsi Nagineni 		return (EINVAL);
6277c478bd9Sstevel@tonic-gate 
628dd1e66b6SVamsi Nagineni 	if (aiop->aio_outstanding == 0)
6297c478bd9Sstevel@tonic-gate 		return (EAGAIN);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (copyin(nwait, &waitcnt, sizeof (uint_t)))
6327c478bd9Sstevel@tonic-gate 		return (EFAULT);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	/* set *nwait to zero, if we must return prematurely */
6357c478bd9Sstevel@tonic-gate 	if (copyout(&cnt, nwait, sizeof (uint_t)))
6367c478bd9Sstevel@tonic-gate 		return (EFAULT);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (waitcnt == 0) {
6397c478bd9Sstevel@tonic-gate 		blocking = 0;
6407c478bd9Sstevel@tonic-gate 		rqtp = NULL;
6417c478bd9Sstevel@tonic-gate 		waitcnt = nent;
6427c478bd9Sstevel@tonic-gate 	} else {
6437c478bd9Sstevel@tonic-gate 		error = timespec2reltime(timout, &rqtime, &rqtp, &blocking);
6447c478bd9Sstevel@tonic-gate 		if (error)
6457c478bd9Sstevel@tonic-gate 			return (error);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE)
6497c478bd9Sstevel@tonic-gate 		iocbsz = (sizeof (aiocb_t *) * nent);
6507c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
6517c478bd9Sstevel@tonic-gate 	else
6527c478bd9Sstevel@tonic-gate 		iocbsz = (sizeof (caddr32_t) * nent);
6537c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * Only one aio_waitn call is allowed at a time.
6577c478bd9Sstevel@tonic-gate 	 * The active aio_waitn will collect all requests
6587c478bd9Sstevel@tonic-gate 	 * out of the "done" list and if necessary it will wait
6597c478bd9Sstevel@tonic-gate 	 * for some/all pending requests to fulfill the nwait
6607c478bd9Sstevel@tonic-gate 	 * parameter.
6617c478bd9Sstevel@tonic-gate 	 * A second or further aio_waitn calls will sleep here
6627c478bd9Sstevel@tonic-gate 	 * until the active aio_waitn finishes and leaves the kernel
6637c478bd9Sstevel@tonic-gate 	 * If the second call does not block (poll), then return
6647c478bd9Sstevel@tonic-gate 	 * immediately with the error code : EAGAIN.
6657c478bd9Sstevel@tonic-gate 	 * If the second call should block, then sleep here, but
6667c478bd9Sstevel@tonic-gate 	 * do not touch the timeout. The timeout starts when this
6677c478bd9Sstevel@tonic-gate 	 * aio_waitn-call becomes active.
6687c478bd9Sstevel@tonic-gate 	 */
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	while (aiop->aio_flags & AIO_WAITN) {
6737c478bd9Sstevel@tonic-gate 		if (blocking == 0) {
6747c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
6757c478bd9Sstevel@tonic-gate 			return (EAGAIN);
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		/* block, no timeout */
6797c478bd9Sstevel@tonic-gate 		aiop->aio_flags |= AIO_WAITN_PENDING;
6807c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&aiop->aio_waitncv, &aiop->aio_mutex)) {
6817c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
6827c478bd9Sstevel@tonic-gate 			return (EINTR);
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	/*
6877c478bd9Sstevel@tonic-gate 	 * Establish the absolute future time for the timeout.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	if (rqtp) {
6907c478bd9Sstevel@tonic-gate 		timestruc_t now;
6913348528fSdm120769 		timecheck = timechanged;
6927c478bd9Sstevel@tonic-gate 		gethrestime(&now);
6937c478bd9Sstevel@tonic-gate 		timespecadd(rqtp, &now);
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (iocbsz > aiop->aio_iocbsz && aiop->aio_iocb != NULL) {
6977c478bd9Sstevel@tonic-gate 		kmem_free(aiop->aio_iocb, aiop->aio_iocbsz);
6987c478bd9Sstevel@tonic-gate 		aiop->aio_iocb = NULL;
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (aiop->aio_iocb == NULL) {
7027c478bd9Sstevel@tonic-gate 		iocblist = kmem_zalloc(iocbsz, KM_NOSLEEP);
7037c478bd9Sstevel@tonic-gate 		if (iocblist == NULL) {
7047c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
7057c478bd9Sstevel@tonic-gate 			return (ENOMEM);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		aiop->aio_iocb = (aiocb_t **)iocblist;
7087c478bd9Sstevel@tonic-gate 		aiop->aio_iocbsz = iocbsz;
7097c478bd9Sstevel@tonic-gate 	} else {
7107c478bd9Sstevel@tonic-gate 		iocblist = (char *)aiop->aio_iocb;
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	aiop->aio_waitncnt = waitcnt;
7147c478bd9Sstevel@tonic-gate 	aiop->aio_flags |= AIO_WAITN;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	for (;;) {
7177c478bd9Sstevel@tonic-gate 		/* push requests on poll queue to done queue */
7187c478bd9Sstevel@tonic-gate 		if (aiop->aio_pollq) {
7197c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
7207c478bd9Sstevel@tonic-gate 			aio_cleanup(0);
7217c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		/* check for requests on done queue */
7257c478bd9Sstevel@tonic-gate 		if (aiop->aio_doneq) {
7267c478bd9Sstevel@tonic-gate 			cnt += aio_reqlist_concat(aiop, &reqlist, nent - cnt);
7277c478bd9Sstevel@tonic-gate 			aiop->aio_waitncnt = waitcnt - cnt;
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		/* user-level done queue might not be empty */
7317c478bd9Sstevel@tonic-gate 		if (aiop->aio_notifycnt > 0) {
7327c478bd9Sstevel@tonic-gate 			aiop->aio_notifycnt--;
7337c478bd9Sstevel@tonic-gate 			error = 0;
7347c478bd9Sstevel@tonic-gate 			break;
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		/*
7387c478bd9Sstevel@tonic-gate 		 * if we are here second time as a result of timer
7397c478bd9Sstevel@tonic-gate 		 * expiration, we reset error if there are enough
7407c478bd9Sstevel@tonic-gate 		 * aiocb's to satisfy request.
7417c478bd9Sstevel@tonic-gate 		 * We return also if all requests are already done
7427c478bd9Sstevel@tonic-gate 		 * and we picked up the whole done queue.
7437c478bd9Sstevel@tonic-gate 		 */
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		if ((cnt >= waitcnt) || (cnt > 0 && aiop->aio_pending == 0 &&
7467c478bd9Sstevel@tonic-gate 		    aiop->aio_doneq == NULL)) {
7477c478bd9Sstevel@tonic-gate 			error = 0;
7487c478bd9Sstevel@tonic-gate 			break;
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 		if ((cnt < waitcnt) && blocking) {
7527c478bd9Sstevel@tonic-gate 			int rval = cv_waituntil_sig(&aiop->aio_waitcv,
7533348528fSdm120769 			    &aiop->aio_mutex, rqtp, timecheck);
7547c478bd9Sstevel@tonic-gate 			if (rval > 0)
7557c478bd9Sstevel@tonic-gate 				continue;
7567c478bd9Sstevel@tonic-gate 			if (rval < 0) {
7577c478bd9Sstevel@tonic-gate 				error = ETIME;
7587c478bd9Sstevel@tonic-gate 				blocking = 0;
7597c478bd9Sstevel@tonic-gate 				continue;
7607c478bd9Sstevel@tonic-gate 			}
7617c478bd9Sstevel@tonic-gate 			error = EINTR;
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (cnt > 0) {
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		iocb_index = aio_unlock_requests(iocblist, iocb_index, reqlist,
7717c478bd9Sstevel@tonic-gate 		    aiop, model);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		if (model == DATAMODEL_NATIVE)
7747c478bd9Sstevel@tonic-gate 			riocbsz = (sizeof (aiocb_t *) * cnt);
7757c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
7767c478bd9Sstevel@tonic-gate 		else
7777c478bd9Sstevel@tonic-gate 			riocbsz = (sizeof (caddr32_t) * cnt);
7787c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		if (copyout(iocblist, uiocb, riocbsz) ||
7817c478bd9Sstevel@tonic-gate 		    copyout(&cnt, nwait, sizeof (uint_t)))
7827c478bd9Sstevel@tonic-gate 			error = EFAULT;
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	/* check if there is another thread waiting for execution */
7867c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
7877c478bd9Sstevel@tonic-gate 	aiop->aio_flags &= ~AIO_WAITN;
7887c478bd9Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_WAITN_PENDING) {
7897c478bd9Sstevel@tonic-gate 		aiop->aio_flags &= ~AIO_WAITN_PENDING;
7907c478bd9Sstevel@tonic-gate 		cv_signal(&aiop->aio_waitncv);
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	return (error);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate /*
7987c478bd9Sstevel@tonic-gate  * aio_unlock_requests
7997c478bd9Sstevel@tonic-gate  * copyouts the result of the request as well as the return value.
8007c478bd9Sstevel@tonic-gate  * It builds the list of completed asynchronous requests,
8017c478bd9Sstevel@tonic-gate  * unlocks the allocated memory ranges and
8027c478bd9Sstevel@tonic-gate  * put the aio request structure back into the free list.
8037c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate static int
aio_unlock_requests(caddr_t iocblist,int iocb_index,aio_req_t * reqlist,aio_t * aiop,model_t model)8067c478bd9Sstevel@tonic-gate aio_unlock_requests(
8077c478bd9Sstevel@tonic-gate 	caddr_t	iocblist,
8087c478bd9Sstevel@tonic-gate 	int	iocb_index,
8097c478bd9Sstevel@tonic-gate 	aio_req_t *reqlist,
8107c478bd9Sstevel@tonic-gate 	aio_t	*aiop,
8117c478bd9Sstevel@tonic-gate 	model_t	model)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp, *nreqp;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE) {
8167c478bd9Sstevel@tonic-gate 		for (reqp = reqlist; reqp != NULL;  reqp = nreqp) {
8177c478bd9Sstevel@tonic-gate 			(((caddr_t *)iocblist)[iocb_index++]) =
8187c478bd9Sstevel@tonic-gate 			    reqp->aio_req_iocb.iocb;
8197c478bd9Sstevel@tonic-gate 			nreqp = reqp->aio_req_next;
8207c478bd9Sstevel@tonic-gate 			aphysio_unlock(reqp);
8217c478bd9Sstevel@tonic-gate 			aio_copyout_result(reqp);
8227c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
8237c478bd9Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
8247c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
8287c478bd9Sstevel@tonic-gate 	else {
8297c478bd9Sstevel@tonic-gate 		for (reqp = reqlist; reqp != NULL;  reqp = nreqp) {
8307c478bd9Sstevel@tonic-gate 			((caddr32_t *)iocblist)[iocb_index++] =
8317c478bd9Sstevel@tonic-gate 			    reqp->aio_req_iocb.iocb32;
8327c478bd9Sstevel@tonic-gate 			nreqp = reqp->aio_req_next;
8337c478bd9Sstevel@tonic-gate 			aphysio_unlock(reqp);
8347c478bd9Sstevel@tonic-gate 			aio_copyout_result(reqp);
8357c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
8367c478bd9Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
8377c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
8387c478bd9Sstevel@tonic-gate 		}
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
8417c478bd9Sstevel@tonic-gate 	return (iocb_index);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate /*
8457c478bd9Sstevel@tonic-gate  * aio_reqlist_concat
8467c478bd9Sstevel@tonic-gate  * moves "max" elements from the done queue to the reqlist queue and removes
8477c478bd9Sstevel@tonic-gate  * the AIO_DONEQ flag.
8487c478bd9Sstevel@tonic-gate  * - reqlist queue is a simple linked list
8497c478bd9Sstevel@tonic-gate  * - done queue is a double linked list
8507c478bd9Sstevel@tonic-gate  */
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate static int
aio_reqlist_concat(aio_t * aiop,aio_req_t ** reqlist,int max)8537c478bd9Sstevel@tonic-gate aio_reqlist_concat(aio_t *aiop, aio_req_t **reqlist, int max)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate 	aio_req_t *q2, *q2work, *list;
8567c478bd9Sstevel@tonic-gate 	int count = 0;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	list = *reqlist;
8597c478bd9Sstevel@tonic-gate 	q2 = aiop->aio_doneq;
8607c478bd9Sstevel@tonic-gate 	q2work = q2;
8617c478bd9Sstevel@tonic-gate 	while (max-- > 0) {
8627c478bd9Sstevel@tonic-gate 		q2work->aio_req_flags &= ~AIO_DONEQ;
8637c478bd9Sstevel@tonic-gate 		q2work = q2work->aio_req_next;
8647c478bd9Sstevel@tonic-gate 		count++;
8657c478bd9Sstevel@tonic-gate 		if (q2work == q2)
8667c478bd9Sstevel@tonic-gate 			break;
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (q2work == q2) {
8707c478bd9Sstevel@tonic-gate 		/* all elements revised */
8717c478bd9Sstevel@tonic-gate 		q2->aio_req_prev->aio_req_next = list;
8727c478bd9Sstevel@tonic-gate 		list = q2;
8737c478bd9Sstevel@tonic-gate 		aiop->aio_doneq = NULL;
8747c478bd9Sstevel@tonic-gate 	} else {
8757c478bd9Sstevel@tonic-gate 		/*
8767c478bd9Sstevel@tonic-gate 		 * max < elements in the doneq
8777c478bd9Sstevel@tonic-gate 		 * detach only the required amount of elements
8787c478bd9Sstevel@tonic-gate 		 * out of the doneq
8797c478bd9Sstevel@tonic-gate 		 */
8807c478bd9Sstevel@tonic-gate 		q2work->aio_req_prev->aio_req_next = list;
8817c478bd9Sstevel@tonic-gate 		list = q2;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		aiop->aio_doneq = q2work;
8847c478bd9Sstevel@tonic-gate 		q2work->aio_req_prev = q2->aio_req_prev;
8857c478bd9Sstevel@tonic-gate 		q2->aio_req_prev->aio_req_next = q2work;
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 	*reqlist = list;
8887c478bd9Sstevel@tonic-gate 	return (count);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8927c478bd9Sstevel@tonic-gate static int
aiosuspend(void * aiocb,int nent,struct timespec * timout,int flag,long * rval,int run_mode)8937c478bd9Sstevel@tonic-gate aiosuspend(
8947c478bd9Sstevel@tonic-gate 	void	*aiocb,
8957c478bd9Sstevel@tonic-gate 	int	nent,
8967c478bd9Sstevel@tonic-gate 	struct	timespec	*timout,
8977c478bd9Sstevel@tonic-gate 	int	flag,
8987c478bd9Sstevel@tonic-gate 	long	*rval,
8997c478bd9Sstevel@tonic-gate 	int	run_mode)
9007c478bd9Sstevel@tonic-gate {
9017c478bd9Sstevel@tonic-gate 	int 		error;
9027c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
9037c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp, *found, *next;
9047c478bd9Sstevel@tonic-gate 	caddr_t		cbplist = NULL;
9057c478bd9Sstevel@tonic-gate 	aiocb_t		*cbp, **ucbp;
9067c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
9077c478bd9Sstevel@tonic-gate 	aiocb32_t	*cbp32;
9087c478bd9Sstevel@tonic-gate 	caddr32_t	*ucbp32;
9097c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
9107c478bd9Sstevel@tonic-gate 	aiocb64_32_t	*cbp64;
9117c478bd9Sstevel@tonic-gate 	int		rv;
9127c478bd9Sstevel@tonic-gate 	int		i;
9137c478bd9Sstevel@tonic-gate 	size_t		ssize;
9147c478bd9Sstevel@tonic-gate 	model_t		model = get_udatamodel();
9157c478bd9Sstevel@tonic-gate 	int		blocking;
9163348528fSdm120769 	int		timecheck;
9177c478bd9Sstevel@tonic-gate 	timestruc_t	rqtime;
9187c478bd9Sstevel@tonic-gate 	timestruc_t	*rqtp;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
921dd1e66b6SVamsi Nagineni 	if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX)
9227c478bd9Sstevel@tonic-gate 		return (EINVAL);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	/*
9257c478bd9Sstevel@tonic-gate 	 * Establish the absolute future time for the timeout.
9267c478bd9Sstevel@tonic-gate 	 */
9277c478bd9Sstevel@tonic-gate 	error = timespec2reltime(timout, &rqtime, &rqtp, &blocking);
9287c478bd9Sstevel@tonic-gate 	if (error)
9297c478bd9Sstevel@tonic-gate 		return (error);
9307c478bd9Sstevel@tonic-gate 	if (rqtp) {
9317c478bd9Sstevel@tonic-gate 		timestruc_t now;
9323348528fSdm120769 		timecheck = timechanged;
9337c478bd9Sstevel@tonic-gate 		gethrestime(&now);
9347c478bd9Sstevel@tonic-gate 		timespecadd(rqtp, &now);
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/*
9387c478bd9Sstevel@tonic-gate 	 * If we are not blocking and there's no IO complete
9397c478bd9Sstevel@tonic-gate 	 * skip aiocb copyin.
9407c478bd9Sstevel@tonic-gate 	 */
9417c478bd9Sstevel@tonic-gate 	if (!blocking && (aiop->aio_pollq == NULL) &&
9427c478bd9Sstevel@tonic-gate 	    (aiop->aio_doneq == NULL)) {
9437c478bd9Sstevel@tonic-gate 		return (EAGAIN);
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE)
9477c478bd9Sstevel@tonic-gate 		ssize = (sizeof (aiocb_t *) * nent);
9487c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
9497c478bd9Sstevel@tonic-gate 	else
9507c478bd9Sstevel@tonic-gate 		ssize = (sizeof (caddr32_t) * nent);
9517c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	cbplist = kmem_alloc(ssize, KM_NOSLEEP);
9547c478bd9Sstevel@tonic-gate 	if (cbplist == NULL)
9557c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	if (copyin(aiocb, cbplist, ssize)) {
9587c478bd9Sstevel@tonic-gate 		error = EFAULT;
9597c478bd9Sstevel@tonic-gate 		goto done;
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	found = NULL;
9637c478bd9Sstevel@tonic-gate 	/*
9647c478bd9Sstevel@tonic-gate 	 * we need to get the aio_cleanupq_mutex since we call
9657c478bd9Sstevel@tonic-gate 	 * aio_req_done().
9667c478bd9Sstevel@tonic-gate 	 */
9677c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_cleanupq_mutex);
9687c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
9697c478bd9Sstevel@tonic-gate 	for (;;) {
9707c478bd9Sstevel@tonic-gate 		/* push requests on poll queue to done queue */
9717c478bd9Sstevel@tonic-gate 		if (aiop->aio_pollq) {
9727c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
9737c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_cleanupq_mutex);
9747c478bd9Sstevel@tonic-gate 			aio_cleanup(0);
9757c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_cleanupq_mutex);
9767c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
9777c478bd9Sstevel@tonic-gate 		}
9787c478bd9Sstevel@tonic-gate 		/* check for requests on done queue */
9797c478bd9Sstevel@tonic-gate 		if (aiop->aio_doneq) {
9807c478bd9Sstevel@tonic-gate 			if (model == DATAMODEL_NATIVE)
9817c478bd9Sstevel@tonic-gate 				ucbp = (aiocb_t **)cbplist;
9827c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
9837c478bd9Sstevel@tonic-gate 			else
9847c478bd9Sstevel@tonic-gate 				ucbp32 = (caddr32_t *)cbplist;
9857c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
9867c478bd9Sstevel@tonic-gate 			for (i = 0; i < nent; i++) {
9877c478bd9Sstevel@tonic-gate 				if (model == DATAMODEL_NATIVE) {
9887c478bd9Sstevel@tonic-gate 					if ((cbp = *ucbp++) == NULL)
9897c478bd9Sstevel@tonic-gate 						continue;
9907c478bd9Sstevel@tonic-gate 					if (run_mode != AIO_LARGEFILE)
9917c478bd9Sstevel@tonic-gate 						reqp = aio_req_done(
9927c478bd9Sstevel@tonic-gate 						    &cbp->aio_resultp);
9937c478bd9Sstevel@tonic-gate 					else {
9947c478bd9Sstevel@tonic-gate 						cbp64 = (aiocb64_32_t *)cbp;
9957c478bd9Sstevel@tonic-gate 						reqp = aio_req_done(
9967c478bd9Sstevel@tonic-gate 						    &cbp64->aio_resultp);
9977c478bd9Sstevel@tonic-gate 					}
9987c478bd9Sstevel@tonic-gate 				}
9997c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
10007c478bd9Sstevel@tonic-gate 				else {
10017c478bd9Sstevel@tonic-gate 					if (run_mode == AIO_32) {
10027c478bd9Sstevel@tonic-gate 						if ((cbp32 =
10037c478bd9Sstevel@tonic-gate 						    (aiocb32_t *)(uintptr_t)
10047c478bd9Sstevel@tonic-gate 						    *ucbp32++) == NULL)
10057c478bd9Sstevel@tonic-gate 							continue;
10067c478bd9Sstevel@tonic-gate 						reqp = aio_req_done(
10077c478bd9Sstevel@tonic-gate 						    &cbp32->aio_resultp);
10087c478bd9Sstevel@tonic-gate 					} else if (run_mode == AIO_LARGEFILE) {
10097c478bd9Sstevel@tonic-gate 						if ((cbp64 =
10107c478bd9Sstevel@tonic-gate 						    (aiocb64_32_t *)(uintptr_t)
10117c478bd9Sstevel@tonic-gate 						    *ucbp32++) == NULL)
10127c478bd9Sstevel@tonic-gate 							continue;
10137c478bd9Sstevel@tonic-gate 						reqp = aio_req_done(
10147c478bd9Sstevel@tonic-gate 						    &cbp64->aio_resultp);
10157c478bd9Sstevel@tonic-gate 					}
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 				}
10187c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
10197c478bd9Sstevel@tonic-gate 				if (reqp) {
10207c478bd9Sstevel@tonic-gate 					reqp->aio_req_next = found;
10217c478bd9Sstevel@tonic-gate 					found = reqp;
10227c478bd9Sstevel@tonic-gate 				}
10237c478bd9Sstevel@tonic-gate 				if (aiop->aio_doneq == NULL)
10247c478bd9Sstevel@tonic-gate 					break;
10257c478bd9Sstevel@tonic-gate 			}
10267c478bd9Sstevel@tonic-gate 			if (found)
10277c478bd9Sstevel@tonic-gate 				break;
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 		if (aiop->aio_notifycnt > 0) {
10307c478bd9Sstevel@tonic-gate 			/*
10317c478bd9Sstevel@tonic-gate 			 * nothing on the kernel's queue. the user
10327c478bd9Sstevel@tonic-gate 			 * has notified the kernel that it has items
10337c478bd9Sstevel@tonic-gate 			 * on a user-level queue.
10347c478bd9Sstevel@tonic-gate 			 */
10357c478bd9Sstevel@tonic-gate 			aiop->aio_notifycnt--;
10367c478bd9Sstevel@tonic-gate 			*rval = 1;
10377c478bd9Sstevel@tonic-gate 			error = 0;
10387c478bd9Sstevel@tonic-gate 			break;
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 		/* don't block if nothing is outstanding */
10417c478bd9Sstevel@tonic-gate 		if (aiop->aio_outstanding == 0) {
10427c478bd9Sstevel@tonic-gate 			error = EAGAIN;
10437c478bd9Sstevel@tonic-gate 			break;
10447c478bd9Sstevel@tonic-gate 		}
10457c478bd9Sstevel@tonic-gate 		if (blocking) {
10467c478bd9Sstevel@tonic-gate 			/*
10477c478bd9Sstevel@tonic-gate 			 * drop the aio_cleanupq_mutex as we are
10487c478bd9Sstevel@tonic-gate 			 * going to block.
10497c478bd9Sstevel@tonic-gate 			 */
10507c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_cleanupq_mutex);
10517c478bd9Sstevel@tonic-gate 			rv = cv_waituntil_sig(&aiop->aio_waitcv,
10523348528fSdm120769 			    &aiop->aio_mutex, rqtp, timecheck);
10537c478bd9Sstevel@tonic-gate 			/*
10547c478bd9Sstevel@tonic-gate 			 * we have to drop aio_mutex and
10557c478bd9Sstevel@tonic-gate 			 * grab it in the right order.
10567c478bd9Sstevel@tonic-gate 			 */
10577c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
10587c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_cleanupq_mutex);
10597c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
10607c478bd9Sstevel@tonic-gate 			if (rv > 0)	/* check done queue again */
10617c478bd9Sstevel@tonic-gate 				continue;
10627c478bd9Sstevel@tonic-gate 			if (rv == 0)	/* interrupted by a signal */
10637c478bd9Sstevel@tonic-gate 				error = EINTR;
10647c478bd9Sstevel@tonic-gate 			else		/* timer expired */
10657c478bd9Sstevel@tonic-gate 				error = ETIME;
10667c478bd9Sstevel@tonic-gate 		} else {
10677c478bd9Sstevel@tonic-gate 			error = EAGAIN;
10687c478bd9Sstevel@tonic-gate 		}
10697c478bd9Sstevel@tonic-gate 		break;
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
10727c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_cleanupq_mutex);
10737c478bd9Sstevel@tonic-gate 	for (reqp = found; reqp != NULL; reqp = next) {
10747c478bd9Sstevel@tonic-gate 		next = reqp->aio_req_next;
10757c478bd9Sstevel@tonic-gate 		aphysio_unlock(reqp);
10767c478bd9Sstevel@tonic-gate 		aio_copyout_result(reqp);
10777c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
10787c478bd9Sstevel@tonic-gate 		aio_req_free(aiop, reqp);
10797c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate done:
10827c478bd9Sstevel@tonic-gate 	kmem_free(cbplist, ssize);
10837c478bd9Sstevel@tonic-gate 	return (error);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate /*
10877c478bd9Sstevel@tonic-gate  * initialize aio by allocating an aio_t struct for this
10887c478bd9Sstevel@tonic-gate  * process.
10897c478bd9Sstevel@tonic-gate  */
10907c478bd9Sstevel@tonic-gate static int
aioinit(void)10917c478bd9Sstevel@tonic-gate aioinit(void)
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate 	proc_t *p = curproc;
10947c478bd9Sstevel@tonic-gate 	aio_t *aiop;
10957c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10967c478bd9Sstevel@tonic-gate 	if ((aiop = p->p_aio) == NULL) {
10977c478bd9Sstevel@tonic-gate 		aiop = aio_aiop_alloc();
10987c478bd9Sstevel@tonic-gate 		p->p_aio = aiop;
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11017c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
11027c478bd9Sstevel@tonic-gate 		return (ENOMEM);
11037c478bd9Sstevel@tonic-gate 	return (0);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate /*
11077c478bd9Sstevel@tonic-gate  * start a special thread that will cleanup after aio requests
11087c478bd9Sstevel@tonic-gate  * that are preventing a segment from being unmapped. as_unmap()
11097c478bd9Sstevel@tonic-gate  * blocks until all phsyio to this segment is completed. this
11107c478bd9Sstevel@tonic-gate  * doesn't happen until all the pages in this segment are not
11117c478bd9Sstevel@tonic-gate  * SOFTLOCKed. Some pages will be SOFTLOCKed when there are aio
11127c478bd9Sstevel@tonic-gate  * requests still outstanding. this special thread will make sure
11137c478bd9Sstevel@tonic-gate  * that these SOFTLOCKed pages will eventually be SOFTUNLOCKed.
11147c478bd9Sstevel@tonic-gate  *
11157c478bd9Sstevel@tonic-gate  * this function will return an error if the process has only
11167c478bd9Sstevel@tonic-gate  * one LWP. the assumption is that the caller is a separate LWP
11177c478bd9Sstevel@tonic-gate  * that remains blocked in the kernel for the life of this process.
11187c478bd9Sstevel@tonic-gate  */
11197c478bd9Sstevel@tonic-gate static int
aiostart(void)11207c478bd9Sstevel@tonic-gate aiostart(void)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate 	proc_t *p = curproc;
11237c478bd9Sstevel@tonic-gate 	aio_t *aiop;
11247c478bd9Sstevel@tonic-gate 	int first, error = 0;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if (p->p_lwpcnt == 1)
11277c478bd9Sstevel@tonic-gate 		return (EDEADLK);
11287c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11297c478bd9Sstevel@tonic-gate 	if ((aiop = p->p_aio) == NULL)
11307c478bd9Sstevel@tonic-gate 		error = EINVAL;
11317c478bd9Sstevel@tonic-gate 	else {
11327c478bd9Sstevel@tonic-gate 		first = aiop->aio_ok;
11337c478bd9Sstevel@tonic-gate 		if (aiop->aio_ok == 0)
11347c478bd9Sstevel@tonic-gate 			aiop->aio_ok = 1;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11377c478bd9Sstevel@tonic-gate 	if (error == 0 && first == 0) {
11387c478bd9Sstevel@tonic-gate 		return (aio_cleanup_thread(aiop));
11397c478bd9Sstevel@tonic-gate 		/* should return only to exit */
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 	return (error);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  * Associate an aiocb with a port.
11467c478bd9Sstevel@tonic-gate  * This function is used by aiorw() to associate a transaction with a port.
11477c478bd9Sstevel@tonic-gate  * Allocate an event port structure (port_alloc_event()) and store the
11487c478bd9Sstevel@tonic-gate  * delivered user pointer (portnfy_user) in the portkev_user field of the
11497c478bd9Sstevel@tonic-gate  * port_kevent_t structure..
11507c478bd9Sstevel@tonic-gate  * The aio_req_portkev pointer in the aio_req_t structure was added to identify
11517c478bd9Sstevel@tonic-gate  * the port association.
11527c478bd9Sstevel@tonic-gate  */
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate static int
aio_req_assoc_port_rw(port_notify_t * pntfy,aiocb_t * cbp,aio_req_t * reqp,int event)115534709573Sraf aio_req_assoc_port_rw(port_notify_t *pntfy, aiocb_t *cbp,
115634709573Sraf 	aio_req_t *reqp, int event)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	port_kevent_t	*pkevp = NULL;
11597c478bd9Sstevel@tonic-gate 	int		error;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	error = port_alloc_event(pntfy->portnfy_port, PORT_ALLOC_DEFAULT,
11627c478bd9Sstevel@tonic-gate 	    PORT_SOURCE_AIO, &pkevp);
11637c478bd9Sstevel@tonic-gate 	if (error) {
11647c478bd9Sstevel@tonic-gate 		if ((error == ENOMEM) || (error == EAGAIN))
11657c478bd9Sstevel@tonic-gate 			error = EAGAIN;
11667c478bd9Sstevel@tonic-gate 		else
11677c478bd9Sstevel@tonic-gate 			error = EINVAL;
11687c478bd9Sstevel@tonic-gate 	} else {
11697c478bd9Sstevel@tonic-gate 		port_init_event(pkevp, (uintptr_t)cbp, pntfy->portnfy_user,
11707c478bd9Sstevel@tonic-gate 		    aio_port_callback, reqp);
117134709573Sraf 		pkevp->portkev_events = event;
11727c478bd9Sstevel@tonic-gate 		reqp->aio_req_portkev = pkevp;
11737c478bd9Sstevel@tonic-gate 		reqp->aio_req_port = pntfy->portnfy_port;
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 	return (error);
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate #ifdef _LP64
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate /*
11817c478bd9Sstevel@tonic-gate  * Asynchronous list IO. A chain of aiocb's are copied in
11827c478bd9Sstevel@tonic-gate  * one at a time. If the aiocb is invalid, it is skipped.
11837c478bd9Sstevel@tonic-gate  * For each aiocb, the appropriate driver entry point is
11847c478bd9Sstevel@tonic-gate  * called. Optimize for the common case where the list
11857c478bd9Sstevel@tonic-gate  * of requests is to the same file descriptor.
11867c478bd9Sstevel@tonic-gate  *
11877c478bd9Sstevel@tonic-gate  * One possible optimization is to define a new driver entry
11887c478bd9Sstevel@tonic-gate  * point that supports a list of IO requests. Whether this
11897c478bd9Sstevel@tonic-gate  * improves performance depends somewhat on the driver's
11907c478bd9Sstevel@tonic-gate  * locking strategy. Processing a list could adversely impact
11917c478bd9Sstevel@tonic-gate  * the driver's interrupt latency.
11927c478bd9Sstevel@tonic-gate  */
11937c478bd9Sstevel@tonic-gate static int
alio(int mode_arg,aiocb_t ** aiocb_arg,int nent,struct sigevent * sigev)11947c478bd9Sstevel@tonic-gate alio(
11957c478bd9Sstevel@tonic-gate 	int		mode_arg,
11967c478bd9Sstevel@tonic-gate 	aiocb_t		**aiocb_arg,
11977c478bd9Sstevel@tonic-gate 	int		nent,
11987c478bd9Sstevel@tonic-gate 	struct sigevent	*sigev)
11997c478bd9Sstevel@tonic-gate {
12007c478bd9Sstevel@tonic-gate 	file_t		*fp;
12017c478bd9Sstevel@tonic-gate 	file_t		*prev_fp = NULL;
12027c478bd9Sstevel@tonic-gate 	int		prev_mode = -1;
12037c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
12047c478bd9Sstevel@tonic-gate 	aio_lio_t	*head;
12057c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
12067c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
12077c478bd9Sstevel@tonic-gate 	caddr_t		cbplist;
12087c478bd9Sstevel@tonic-gate 	aiocb_t		cb;
12097c478bd9Sstevel@tonic-gate 	aiocb_t		*aiocb = &cb;
121034709573Sraf 	aiocb_t		*cbp;
121134709573Sraf 	aiocb_t		**ucbp;
12127c478bd9Sstevel@tonic-gate 	struct sigevent sigevk;
12137c478bd9Sstevel@tonic-gate 	sigqueue_t	*sqp;
12147c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
12157c478bd9Sstevel@tonic-gate 	int		mode;
12167c478bd9Sstevel@tonic-gate 	int		error = 0;
12177c478bd9Sstevel@tonic-gate 	int		aio_errors = 0;
12187c478bd9Sstevel@tonic-gate 	int		i;
12197c478bd9Sstevel@tonic-gate 	size_t		ssize;
12207c478bd9Sstevel@tonic-gate 	int		deadhead = 0;
12217c478bd9Sstevel@tonic-gate 	int		aio_notsupported = 0;
122234709573Sraf 	int		lio_head_port;
122334709573Sraf 	int		aio_port;
122434709573Sraf 	int		aio_thread;
12257c478bd9Sstevel@tonic-gate 	port_kevent_t	*pkevtp = NULL;
122634b3058fSpraks 	int		portused = 0;
12277c478bd9Sstevel@tonic-gate 	port_notify_t	pnotify;
122834709573Sraf 	int		event;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
12317c478bd9Sstevel@tonic-gate 	if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX)
12327c478bd9Sstevel@tonic-gate 		return (EINVAL);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	ssize = (sizeof (aiocb_t *) * nent);
12357c478bd9Sstevel@tonic-gate 	cbplist = kmem_alloc(ssize, KM_SLEEP);
12367c478bd9Sstevel@tonic-gate 	ucbp = (aiocb_t **)cbplist;
12377c478bd9Sstevel@tonic-gate 
123834709573Sraf 	if (copyin(aiocb_arg, cbplist, ssize) ||
123934709573Sraf 	    (sigev && copyin(sigev, &sigevk, sizeof (struct sigevent)))) {
12407c478bd9Sstevel@tonic-gate 		kmem_free(cbplist, ssize);
12417c478bd9Sstevel@tonic-gate 		return (EFAULT);
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate 
124434709573Sraf 	/* Event Ports  */
124534709573Sraf 	if (sigev &&
124634709573Sraf 	    (sigevk.sigev_notify == SIGEV_THREAD ||
124734709573Sraf 	    sigevk.sigev_notify == SIGEV_PORT)) {
124834709573Sraf 		if (sigevk.sigev_notify == SIGEV_THREAD) {
124934709573Sraf 			pnotify.portnfy_port = sigevk.sigev_signo;
125034709573Sraf 			pnotify.portnfy_user = sigevk.sigev_value.sival_ptr;
125134709573Sraf 		} else if (copyin(sigevk.sigev_value.sival_ptr,
125234709573Sraf 		    &pnotify, sizeof (pnotify))) {
12537c478bd9Sstevel@tonic-gate 			kmem_free(cbplist, ssize);
12547c478bd9Sstevel@tonic-gate 			return (EFAULT);
12557c478bd9Sstevel@tonic-gate 		}
125634709573Sraf 		error = port_alloc_event(pnotify.portnfy_port,
125734709573Sraf 		    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp);
125834709573Sraf 		if (error) {
125934709573Sraf 			if (error == ENOMEM || error == EAGAIN)
126034709573Sraf 				error = EAGAIN;
126134709573Sraf 			else
126234709573Sraf 				error = EINVAL;
126334709573Sraf 			kmem_free(cbplist, ssize);
126434709573Sraf 			return (error);
126534709573Sraf 		}
126634709573Sraf 		lio_head_port = pnotify.portnfy_port;
126734b3058fSpraks 		portused = 1;
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * a list head should be allocated if notification is
12727c478bd9Sstevel@tonic-gate 	 * enabled for this list.
12737c478bd9Sstevel@tonic-gate 	 */
12747c478bd9Sstevel@tonic-gate 	head = NULL;
12757c478bd9Sstevel@tonic-gate 
127634709573Sraf 	if (mode_arg == LIO_WAIT || sigev) {
12777c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
12787c478bd9Sstevel@tonic-gate 		error = aio_lio_alloc(&head);
12797c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
12807c478bd9Sstevel@tonic-gate 		if (error)
12817c478bd9Sstevel@tonic-gate 			goto done;
12827c478bd9Sstevel@tonic-gate 		deadhead = 1;
12837c478bd9Sstevel@tonic-gate 		head->lio_nent = nent;
12847c478bd9Sstevel@tonic-gate 		head->lio_refcnt = nent;
128534709573Sraf 		head->lio_port = -1;
128634709573Sraf 		head->lio_portkev = NULL;
128734709573Sraf 		if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL &&
128834709573Sraf 		    sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) {
12897c478bd9Sstevel@tonic-gate 			sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP);
12907c478bd9Sstevel@tonic-gate 			if (sqp == NULL) {
12917c478bd9Sstevel@tonic-gate 				error = EAGAIN;
12927c478bd9Sstevel@tonic-gate 				goto done;
12937c478bd9Sstevel@tonic-gate 			}
12947c478bd9Sstevel@tonic-gate 			sqp->sq_func = NULL;
12957c478bd9Sstevel@tonic-gate 			sqp->sq_next = NULL;
12967c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_code = SI_ASYNCIO;
12977c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_pid = curproc->p_pid;
12987c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_ctid = PRCTID(curproc);
12997c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_zoneid = getzoneid();
13007c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_uid = crgetuid(curproc->p_cred);
13017c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_signo = sigevk.sigev_signo;
13027c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_value = sigevk.sigev_value;
13037c478bd9Sstevel@tonic-gate 			head->lio_sigqp = sqp;
13047c478bd9Sstevel@tonic-gate 		} else {
13057c478bd9Sstevel@tonic-gate 			head->lio_sigqp = NULL;
13067c478bd9Sstevel@tonic-gate 		}
130734709573Sraf 		if (pkevtp) {
130834709573Sraf 			/*
130934709573Sraf 			 * Prepare data to send when list of aiocb's
131034709573Sraf 			 * has completed.
131134709573Sraf 			 */
131234709573Sraf 			port_init_event(pkevtp, (uintptr_t)sigev,
131334709573Sraf 			    (void *)(uintptr_t)pnotify.portnfy_user,
131434709573Sraf 			    NULL, head);
131534709573Sraf 			pkevtp->portkev_events = AIOLIO;
131634709573Sraf 			head->lio_portkev = pkevtp;
131734709573Sraf 			head->lio_port = pnotify.portnfy_port;
131834709573Sraf 		}
13197c478bd9Sstevel@tonic-gate 	}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	for (i = 0; i < nent; i++, ucbp++) {
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 		cbp = *ucbp;
13247c478bd9Sstevel@tonic-gate 		/* skip entry if it can't be copied. */
132534709573Sraf 		if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb))) {
13267c478bd9Sstevel@tonic-gate 			if (head) {
13277c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
13287c478bd9Sstevel@tonic-gate 				head->lio_nent--;
13297c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
13307c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
13317c478bd9Sstevel@tonic-gate 			}
13327c478bd9Sstevel@tonic-gate 			continue;
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 		/* skip if opcode for aiocb is LIO_NOP */
13367c478bd9Sstevel@tonic-gate 		mode = aiocb->aio_lio_opcode;
13377c478bd9Sstevel@tonic-gate 		if (mode == LIO_NOP) {
13387c478bd9Sstevel@tonic-gate 			cbp = NULL;
13397c478bd9Sstevel@tonic-gate 			if (head) {
13407c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
13417c478bd9Sstevel@tonic-gate 				head->lio_nent--;
13427c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
13437c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
13447c478bd9Sstevel@tonic-gate 			}
13457c478bd9Sstevel@tonic-gate 			continue;
13467c478bd9Sstevel@tonic-gate 		}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 		/* increment file descriptor's ref count. */
13497c478bd9Sstevel@tonic-gate 		if ((fp = getf(aiocb->aio_fildes)) == NULL) {
13507c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
13517c478bd9Sstevel@tonic-gate 			if (head) {
13527c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
13537c478bd9Sstevel@tonic-gate 				head->lio_nent--;
13547c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
13557c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
13567c478bd9Sstevel@tonic-gate 			}
13577c478bd9Sstevel@tonic-gate 			aio_errors++;
13587c478bd9Sstevel@tonic-gate 			continue;
13597c478bd9Sstevel@tonic-gate 		}
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 		/*
13627c478bd9Sstevel@tonic-gate 		 * check the permission of the partition
13637c478bd9Sstevel@tonic-gate 		 */
13647c478bd9Sstevel@tonic-gate 		if ((fp->f_flag & mode) == 0) {
13657c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
13667c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
13677c478bd9Sstevel@tonic-gate 			if (head) {
13687c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
13697c478bd9Sstevel@tonic-gate 				head->lio_nent--;
13707c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
13717c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
13727c478bd9Sstevel@tonic-gate 			}
13737c478bd9Sstevel@tonic-gate 			aio_errors++;
13747c478bd9Sstevel@tonic-gate 			continue;
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		/*
137834709573Sraf 		 * common case where requests are to the same fd
137934709573Sraf 		 * for the same r/w operation.
13807c478bd9Sstevel@tonic-gate 		 * for UFS, need to set EBADFD
13817c478bd9Sstevel@tonic-gate 		 */
138234709573Sraf 		vp = fp->f_vnode;
138334709573Sraf 		if (fp != prev_fp || mode != prev_mode) {
13847c478bd9Sstevel@tonic-gate 			aio_func = check_vp(vp, mode);
13857c478bd9Sstevel@tonic-gate 			if (aio_func == NULL) {
13867c478bd9Sstevel@tonic-gate 				prev_fp = NULL;
13877c478bd9Sstevel@tonic-gate 				releasef(aiocb->aio_fildes);
13887c478bd9Sstevel@tonic-gate 				lio_set_uerror(&cbp->aio_resultp, EBADFD);
13897c478bd9Sstevel@tonic-gate 				aio_notsupported++;
13907c478bd9Sstevel@tonic-gate 				if (head) {
13917c478bd9Sstevel@tonic-gate 					mutex_enter(&aiop->aio_mutex);
13927c478bd9Sstevel@tonic-gate 					head->lio_nent--;
13937c478bd9Sstevel@tonic-gate 					head->lio_refcnt--;
13947c478bd9Sstevel@tonic-gate 					mutex_exit(&aiop->aio_mutex);
13957c478bd9Sstevel@tonic-gate 				}
13967c478bd9Sstevel@tonic-gate 				continue;
13977c478bd9Sstevel@tonic-gate 			} else {
13987c478bd9Sstevel@tonic-gate 				prev_fp = fp;
13997c478bd9Sstevel@tonic-gate 				prev_mode = mode;
14007c478bd9Sstevel@tonic-gate 			}
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 
140334709573Sraf 		error = aio_req_setup(&reqp, aiop, aiocb,
1404*d2749ac6SRoger A. Faulkner 		    &cbp->aio_resultp, vp, 0);
140534709573Sraf 		if (error) {
14067c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
14077c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, error);
14087c478bd9Sstevel@tonic-gate 			if (head) {
14097c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
14107c478bd9Sstevel@tonic-gate 				head->lio_nent--;
14117c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
14127c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
14137c478bd9Sstevel@tonic-gate 			}
14147c478bd9Sstevel@tonic-gate 			aio_errors++;
14157c478bd9Sstevel@tonic-gate 			continue;
14167c478bd9Sstevel@tonic-gate 		}
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 		reqp->aio_req_lio = head;
14197c478bd9Sstevel@tonic-gate 		deadhead = 0;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 		/*
14227c478bd9Sstevel@tonic-gate 		 * Set the errno field now before sending the request to
14237c478bd9Sstevel@tonic-gate 		 * the driver to avoid a race condition
14247c478bd9Sstevel@tonic-gate 		 */
14257c478bd9Sstevel@tonic-gate 		(void) suword32(&cbp->aio_resultp.aio_errno,
14267c478bd9Sstevel@tonic-gate 		    EINPROGRESS);
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 		reqp->aio_req_iocb.iocb = (caddr_t)cbp;
14297c478bd9Sstevel@tonic-gate 
143034709573Sraf 		event = (mode == LIO_READ)? AIOAREAD : AIOAWRITE;
143134709573Sraf 		aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT);
143234709573Sraf 		aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD);
143334709573Sraf 		if (aio_port | aio_thread) {
143434709573Sraf 			port_kevent_t *lpkevp;
143534709573Sraf 			/*
143634709573Sraf 			 * Prepare data to send with each aiocb completed.
143734709573Sraf 			 */
143834709573Sraf 			if (aio_port) {
143934709573Sraf 				void *paddr =
144034709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
144134709573Sraf 				if (copyin(paddr, &pnotify, sizeof (pnotify)))
144234709573Sraf 					error = EFAULT;
144334709573Sraf 			} else {	/* aio_thread */
144434709573Sraf 				pnotify.portnfy_port =
144534709573Sraf 				    aiocb->aio_sigevent.sigev_signo;
144634709573Sraf 				pnotify.portnfy_user =
144734709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
144834709573Sraf 			}
144934709573Sraf 			if (error)
145034709573Sraf 				/* EMPTY */;
145134709573Sraf 			else if (pkevtp != NULL &&
145234709573Sraf 			    pnotify.portnfy_port == lio_head_port)
145334709573Sraf 				error = port_dup_event(pkevtp, &lpkevp,
145434709573Sraf 				    PORT_ALLOC_DEFAULT);
145534709573Sraf 			else
145634709573Sraf 				error = port_alloc_event(pnotify.portnfy_port,
145734709573Sraf 				    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO,
145834709573Sraf 				    &lpkevp);
145934709573Sraf 			if (error == 0) {
146034709573Sraf 				port_init_event(lpkevp, (uintptr_t)cbp,
146134709573Sraf 				    (void *)(uintptr_t)pnotify.portnfy_user,
146234709573Sraf 				    aio_port_callback, reqp);
146334709573Sraf 				lpkevp->portkev_events = event;
146434709573Sraf 				reqp->aio_req_portkev = lpkevp;
14657c478bd9Sstevel@tonic-gate 				reqp->aio_req_port = pnotify.portnfy_port;
146634709573Sraf 			}
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 		/*
14707c478bd9Sstevel@tonic-gate 		 * send the request to driver.
14717c478bd9Sstevel@tonic-gate 		 */
14727c478bd9Sstevel@tonic-gate 		if (error == 0) {
14737c478bd9Sstevel@tonic-gate 			if (aiocb->aio_nbytes == 0) {
14747c478bd9Sstevel@tonic-gate 				clear_active_fd(aiocb->aio_fildes);
14757c478bd9Sstevel@tonic-gate 				aio_zerolen(reqp);
14767c478bd9Sstevel@tonic-gate 				continue;
14777c478bd9Sstevel@tonic-gate 			}
14787c478bd9Sstevel@tonic-gate 			error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req,
14797c478bd9Sstevel@tonic-gate 			    CRED());
14807c478bd9Sstevel@tonic-gate 		}
148134709573Sraf 
14827c478bd9Sstevel@tonic-gate 		/*
14837c478bd9Sstevel@tonic-gate 		 * the fd's ref count is not decremented until the IO has
14847c478bd9Sstevel@tonic-gate 		 * completed unless there was an error.
14857c478bd9Sstevel@tonic-gate 		 */
14867c478bd9Sstevel@tonic-gate 		if (error) {
14877c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
14887c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, error);
14897c478bd9Sstevel@tonic-gate 			if (head) {
14907c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
14917c478bd9Sstevel@tonic-gate 				head->lio_nent--;
14927c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
14937c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
14947c478bd9Sstevel@tonic-gate 			}
14957c478bd9Sstevel@tonic-gate 			if (error == ENOTSUP)
14967c478bd9Sstevel@tonic-gate 				aio_notsupported++;
14977c478bd9Sstevel@tonic-gate 			else
14987c478bd9Sstevel@tonic-gate 				aio_errors++;
149934b3058fSpraks 			lio_set_error(reqp, portused);
15007c478bd9Sstevel@tonic-gate 		} else {
15017c478bd9Sstevel@tonic-gate 			clear_active_fd(aiocb->aio_fildes);
15027c478bd9Sstevel@tonic-gate 		}
15037c478bd9Sstevel@tonic-gate 	}
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	if (aio_notsupported) {
15067c478bd9Sstevel@tonic-gate 		error = ENOTSUP;
15077c478bd9Sstevel@tonic-gate 	} else if (aio_errors) {
15087c478bd9Sstevel@tonic-gate 		/*
15097c478bd9Sstevel@tonic-gate 		 * return EIO if any request failed
15107c478bd9Sstevel@tonic-gate 		 */
15117c478bd9Sstevel@tonic-gate 		error = EIO;
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	if (mode_arg == LIO_WAIT) {
15157c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
15167c478bd9Sstevel@tonic-gate 		while (head->lio_refcnt > 0) {
15177c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) {
15187c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
15197c478bd9Sstevel@tonic-gate 				error = EINTR;
15207c478bd9Sstevel@tonic-gate 				goto done;
15217c478bd9Sstevel@tonic-gate 			}
15227c478bd9Sstevel@tonic-gate 		}
15237c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
15247c478bd9Sstevel@tonic-gate 		alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_64);
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate done:
15287c478bd9Sstevel@tonic-gate 	kmem_free(cbplist, ssize);
15297c478bd9Sstevel@tonic-gate 	if (deadhead) {
15307c478bd9Sstevel@tonic-gate 		if (head->lio_sigqp)
15317c478bd9Sstevel@tonic-gate 			kmem_free(head->lio_sigqp, sizeof (sigqueue_t));
153234709573Sraf 		if (head->lio_portkev)
153334709573Sraf 			port_free_event(head->lio_portkev);
15347c478bd9Sstevel@tonic-gate 		kmem_free(head, sizeof (aio_lio_t));
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	return (error);
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate #endif /* _LP64 */
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate  * Asynchronous list IO.
15437c478bd9Sstevel@tonic-gate  * If list I/O is called with LIO_WAIT it can still return
15447c478bd9Sstevel@tonic-gate  * before all the I/O's are completed if a signal is caught
15457c478bd9Sstevel@tonic-gate  * or if the list include UFS I/O requests. If this happens,
15467c478bd9Sstevel@tonic-gate  * libaio will call aliowait() to wait for the I/O's to
15477c478bd9Sstevel@tonic-gate  * complete
15487c478bd9Sstevel@tonic-gate  */
15497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15507c478bd9Sstevel@tonic-gate static int
aliowait(int mode,void * aiocb,int nent,void * sigev,int run_mode)15517c478bd9Sstevel@tonic-gate aliowait(
15527c478bd9Sstevel@tonic-gate 	int	mode,
15537c478bd9Sstevel@tonic-gate 	void	*aiocb,
15547c478bd9Sstevel@tonic-gate 	int	nent,
15557c478bd9Sstevel@tonic-gate 	void	*sigev,
15567c478bd9Sstevel@tonic-gate 	int	run_mode)
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate 	aio_lio_t	*head;
15597c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
15607c478bd9Sstevel@tonic-gate 	caddr_t		cbplist;
15617c478bd9Sstevel@tonic-gate 	aiocb_t		*cbp, **ucbp;
15627c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
15637c478bd9Sstevel@tonic-gate 	aiocb32_t	*cbp32;
15647c478bd9Sstevel@tonic-gate 	caddr32_t	*ucbp32;
15657c478bd9Sstevel@tonic-gate 	aiocb64_32_t	*cbp64;
15667c478bd9Sstevel@tonic-gate #endif
15677c478bd9Sstevel@tonic-gate 	int		error = 0;
15687c478bd9Sstevel@tonic-gate 	int		i;
15697c478bd9Sstevel@tonic-gate 	size_t		ssize = 0;
15707c478bd9Sstevel@tonic-gate 	model_t		model = get_udatamodel();
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
15737c478bd9Sstevel@tonic-gate 	if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX)
15747c478bd9Sstevel@tonic-gate 		return (EINVAL);
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE)
15777c478bd9Sstevel@tonic-gate 		ssize = (sizeof (aiocb_t *) * nent);
15787c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
15797c478bd9Sstevel@tonic-gate 	else
15807c478bd9Sstevel@tonic-gate 		ssize = (sizeof (caddr32_t) * nent);
15817c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	if (ssize == 0)
15847c478bd9Sstevel@tonic-gate 		return (EINVAL);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	cbplist = kmem_alloc(ssize, KM_SLEEP);
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE)
15897c478bd9Sstevel@tonic-gate 		ucbp = (aiocb_t **)cbplist;
15907c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
15917c478bd9Sstevel@tonic-gate 	else
15927c478bd9Sstevel@tonic-gate 		ucbp32 = (caddr32_t *)cbplist;
15937c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	if (copyin(aiocb, cbplist, ssize)) {
15967c478bd9Sstevel@tonic-gate 		error = EFAULT;
15977c478bd9Sstevel@tonic-gate 		goto done;
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	/*
16017c478bd9Sstevel@tonic-gate 	 * To find the list head, we go through the
16027c478bd9Sstevel@tonic-gate 	 * list of aiocb structs, find the request
16037c478bd9Sstevel@tonic-gate 	 * its for, then get the list head that reqp
16047c478bd9Sstevel@tonic-gate 	 * points to
16057c478bd9Sstevel@tonic-gate 	 */
16067c478bd9Sstevel@tonic-gate 	head = NULL;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	for (i = 0; i < nent; i++) {
16097c478bd9Sstevel@tonic-gate 		if (model == DATAMODEL_NATIVE) {
16107c478bd9Sstevel@tonic-gate 			/*
16117c478bd9Sstevel@tonic-gate 			 * Since we are only checking for a NULL pointer
16127c478bd9Sstevel@tonic-gate 			 * Following should work on both native data sizes
16137c478bd9Sstevel@tonic-gate 			 * as well as for largefile aiocb.
16147c478bd9Sstevel@tonic-gate 			 */
16157c478bd9Sstevel@tonic-gate 			if ((cbp = *ucbp++) == NULL)
16167c478bd9Sstevel@tonic-gate 				continue;
16177c478bd9Sstevel@tonic-gate 			if (run_mode != AIO_LARGEFILE)
16187c478bd9Sstevel@tonic-gate 				if (head = aio_list_get(&cbp->aio_resultp))
16197c478bd9Sstevel@tonic-gate 					break;
16207c478bd9Sstevel@tonic-gate 			else {
16217c478bd9Sstevel@tonic-gate 				/*
16227c478bd9Sstevel@tonic-gate 				 * This is a case when largefile call is
16237c478bd9Sstevel@tonic-gate 				 * made on 32 bit kernel.
16247c478bd9Sstevel@tonic-gate 				 * Treat each pointer as pointer to
16257c478bd9Sstevel@tonic-gate 				 * aiocb64_32
16267c478bd9Sstevel@tonic-gate 				 */
16277c478bd9Sstevel@tonic-gate 				if (head = aio_list_get((aio_result_t *)
16287c478bd9Sstevel@tonic-gate 				    &(((aiocb64_32_t *)cbp)->aio_resultp)))
16297c478bd9Sstevel@tonic-gate 					break;
16307c478bd9Sstevel@tonic-gate 			}
16317c478bd9Sstevel@tonic-gate 		}
16327c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
16337c478bd9Sstevel@tonic-gate 		else {
16347c478bd9Sstevel@tonic-gate 			if (run_mode == AIO_LARGEFILE) {
16357c478bd9Sstevel@tonic-gate 				if ((cbp64 = (aiocb64_32_t *)
16367c478bd9Sstevel@tonic-gate 				    (uintptr_t)*ucbp32++) == NULL)
16377c478bd9Sstevel@tonic-gate 					continue;
16387c478bd9Sstevel@tonic-gate 				if (head = aio_list_get((aio_result_t *)
16397c478bd9Sstevel@tonic-gate 				    &cbp64->aio_resultp))
16407c478bd9Sstevel@tonic-gate 					break;
16417c478bd9Sstevel@tonic-gate 			} else if (run_mode == AIO_32) {
16427c478bd9Sstevel@tonic-gate 				if ((cbp32 = (aiocb32_t *)
16437c478bd9Sstevel@tonic-gate 				    (uintptr_t)*ucbp32++) == NULL)
16447c478bd9Sstevel@tonic-gate 					continue;
16457c478bd9Sstevel@tonic-gate 				if (head = aio_list_get((aio_result_t *)
16467c478bd9Sstevel@tonic-gate 				    &cbp32->aio_resultp))
16477c478bd9Sstevel@tonic-gate 					break;
16487c478bd9Sstevel@tonic-gate 			}
16497c478bd9Sstevel@tonic-gate 		}
16507c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
16517c478bd9Sstevel@tonic-gate 	}
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	if (head == NULL) {
16547c478bd9Sstevel@tonic-gate 		error = EINVAL;
16557c478bd9Sstevel@tonic-gate 		goto done;
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
16597c478bd9Sstevel@tonic-gate 	while (head->lio_refcnt > 0) {
16607c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) {
16617c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
16627c478bd9Sstevel@tonic-gate 			error = EINTR;
16637c478bd9Sstevel@tonic-gate 			goto done;
16647c478bd9Sstevel@tonic-gate 		}
16657c478bd9Sstevel@tonic-gate 	}
16667c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
16677c478bd9Sstevel@tonic-gate 	alio_cleanup(aiop, (aiocb_t **)cbplist, nent, run_mode);
16687c478bd9Sstevel@tonic-gate done:
16697c478bd9Sstevel@tonic-gate 	kmem_free(cbplist, ssize);
16707c478bd9Sstevel@tonic-gate 	return (error);
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate aio_lio_t *
aio_list_get(aio_result_t * resultp)16747c478bd9Sstevel@tonic-gate aio_list_get(aio_result_t *resultp)
16757c478bd9Sstevel@tonic-gate {
16767c478bd9Sstevel@tonic-gate 	aio_lio_t	*head = NULL;
16777c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
16787c478bd9Sstevel@tonic-gate 	aio_req_t 	**bucket;
16797c478bd9Sstevel@tonic-gate 	aio_req_t 	*reqp;
16807c478bd9Sstevel@tonic-gate 	long		index;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
16837c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
16847c478bd9Sstevel@tonic-gate 		return (NULL);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	if (resultp) {
16877c478bd9Sstevel@tonic-gate 		index = AIO_HASH(resultp);
16887c478bd9Sstevel@tonic-gate 		bucket = &aiop->aio_hash[index];
16897c478bd9Sstevel@tonic-gate 		for (reqp = *bucket; reqp != NULL;
16907c478bd9Sstevel@tonic-gate 		    reqp = reqp->aio_hash_next) {
16917c478bd9Sstevel@tonic-gate 			if (reqp->aio_req_resultp == resultp) {
16927c478bd9Sstevel@tonic-gate 				head = reqp->aio_req_lio;
16937c478bd9Sstevel@tonic-gate 				return (head);
16947c478bd9Sstevel@tonic-gate 			}
16957c478bd9Sstevel@tonic-gate 		}
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate 	return (NULL);
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate static void
lio_set_uerror(void * resultp,int error)17027c478bd9Sstevel@tonic-gate lio_set_uerror(void *resultp, int error)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	/*
17057c478bd9Sstevel@tonic-gate 	 * the resultp field is a pointer to where the
17067c478bd9Sstevel@tonic-gate 	 * error should be written out to the user's
17077c478bd9Sstevel@tonic-gate 	 * aiocb.
17087c478bd9Sstevel@tonic-gate 	 *
17097c478bd9Sstevel@tonic-gate 	 */
17107c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
17117c478bd9Sstevel@tonic-gate 		(void) sulword(&((aio_result_t *)resultp)->aio_return,
17127c478bd9Sstevel@tonic-gate 		    (ssize_t)-1);
17137c478bd9Sstevel@tonic-gate 		(void) suword32(&((aio_result_t *)resultp)->aio_errno, error);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
17167c478bd9Sstevel@tonic-gate 	else {
17177c478bd9Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_return,
17187c478bd9Sstevel@tonic-gate 		    (uint_t)-1);
17197c478bd9Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_errno, error);
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate  * do cleanup completion for all requests in list. memory for
17267c478bd9Sstevel@tonic-gate  * each request is also freed.
17277c478bd9Sstevel@tonic-gate  */
17287c478bd9Sstevel@tonic-gate static void
alio_cleanup(aio_t * aiop,aiocb_t ** cbp,int nent,int run_mode)17297c478bd9Sstevel@tonic-gate alio_cleanup(aio_t *aiop, aiocb_t **cbp, int nent, int run_mode)
17307c478bd9Sstevel@tonic-gate {
17317c478bd9Sstevel@tonic-gate 	int i;
17327c478bd9Sstevel@tonic-gate 	aio_req_t *reqp;
17337c478bd9Sstevel@tonic-gate 	aio_result_t *resultp;
17347c478bd9Sstevel@tonic-gate 	aiocb64_32_t *aiocb_64;
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	for (i = 0; i < nent; i++) {
17377c478bd9Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE) {
17387c478bd9Sstevel@tonic-gate 			if (cbp[i] == NULL)
17397c478bd9Sstevel@tonic-gate 				continue;
17407c478bd9Sstevel@tonic-gate 			if (run_mode == AIO_LARGEFILE) {
17417c478bd9Sstevel@tonic-gate 				aiocb_64 = (aiocb64_32_t *)cbp[i];
174234709573Sraf 				resultp = (aio_result_t *)
174334709573Sraf 				    &aiocb_64->aio_resultp;
17447c478bd9Sstevel@tonic-gate 			} else
17457c478bd9Sstevel@tonic-gate 				resultp = &cbp[i]->aio_resultp;
17467c478bd9Sstevel@tonic-gate 		}
17477c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
17487c478bd9Sstevel@tonic-gate 		else {
17497c478bd9Sstevel@tonic-gate 			aiocb32_t *aiocb_32;
17507c478bd9Sstevel@tonic-gate 			caddr32_t *cbp32;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 			cbp32 = (caddr32_t *)cbp;
17537c478bd9Sstevel@tonic-gate 			if (cbp32[i] == NULL)
17547c478bd9Sstevel@tonic-gate 				continue;
17557c478bd9Sstevel@tonic-gate 			if (run_mode == AIO_32) {
17567c478bd9Sstevel@tonic-gate 				aiocb_32 = (aiocb32_t *)(uintptr_t)cbp32[i];
17577c478bd9Sstevel@tonic-gate 				resultp = (aio_result_t *)&aiocb_32->
17587c478bd9Sstevel@tonic-gate 				    aio_resultp;
17597c478bd9Sstevel@tonic-gate 			} else if (run_mode == AIO_LARGEFILE) {
17607c478bd9Sstevel@tonic-gate 				aiocb_64 = (aiocb64_32_t *)(uintptr_t)cbp32[i];
17617c478bd9Sstevel@tonic-gate 				resultp = (aio_result_t *)&aiocb_64->
17627c478bd9Sstevel@tonic-gate 				    aio_resultp;
17637c478bd9Sstevel@tonic-gate 			}
17647c478bd9Sstevel@tonic-gate 		}
17657c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
17667c478bd9Sstevel@tonic-gate 		/*
17677c478bd9Sstevel@tonic-gate 		 * we need to get the aio_cleanupq_mutex since we call
17687c478bd9Sstevel@tonic-gate 		 * aio_req_done().
17697c478bd9Sstevel@tonic-gate 		 */
17707c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_cleanupq_mutex);
17717c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
17727c478bd9Sstevel@tonic-gate 		reqp = aio_req_done(resultp);
17737c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
17747c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_cleanupq_mutex);
17757c478bd9Sstevel@tonic-gate 		if (reqp != NULL) {
17767c478bd9Sstevel@tonic-gate 			aphysio_unlock(reqp);
17777c478bd9Sstevel@tonic-gate 			aio_copyout_result(reqp);
17787c478bd9Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
17797c478bd9Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
17807c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
17817c478bd9Sstevel@tonic-gate 		}
17827c478bd9Sstevel@tonic-gate 	}
17837c478bd9Sstevel@tonic-gate }
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate /*
178634709573Sraf  * Write out the results for an aio request that is done.
17877c478bd9Sstevel@tonic-gate  */
17887c478bd9Sstevel@tonic-gate static int
aioerror(void * cb,int run_mode)17897c478bd9Sstevel@tonic-gate aioerror(void *cb, int run_mode)
17907c478bd9Sstevel@tonic-gate {
17917c478bd9Sstevel@tonic-gate 	aio_result_t *resultp;
17927c478bd9Sstevel@tonic-gate 	aio_t *aiop;
17937c478bd9Sstevel@tonic-gate 	aio_req_t *reqp;
17947c478bd9Sstevel@tonic-gate 	int retval;
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
17977c478bd9Sstevel@tonic-gate 	if (aiop == NULL || cb == NULL)
17987c478bd9Sstevel@tonic-gate 		return (EINVAL);
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
18017c478bd9Sstevel@tonic-gate 		if (run_mode == AIO_LARGEFILE)
18027c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&((aiocb64_32_t *)cb)->
18037c478bd9Sstevel@tonic-gate 			    aio_resultp;
18047c478bd9Sstevel@tonic-gate 		else
18057c478bd9Sstevel@tonic-gate 			resultp = &((aiocb_t *)cb)->aio_resultp;
18067c478bd9Sstevel@tonic-gate 	}
18077c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
18087c478bd9Sstevel@tonic-gate 	else {
18097c478bd9Sstevel@tonic-gate 		if (run_mode == AIO_LARGEFILE)
18107c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&((aiocb64_32_t *)cb)->
18117c478bd9Sstevel@tonic-gate 			    aio_resultp;
18127c478bd9Sstevel@tonic-gate 		else if (run_mode == AIO_32)
18137c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&((aiocb32_t *)cb)->
18147c478bd9Sstevel@tonic-gate 			    aio_resultp;
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
18177c478bd9Sstevel@tonic-gate 	/*
18187c478bd9Sstevel@tonic-gate 	 * we need to get the aio_cleanupq_mutex since we call
18197c478bd9Sstevel@tonic-gate 	 * aio_req_find().
18207c478bd9Sstevel@tonic-gate 	 */
18217c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_cleanupq_mutex);
18227c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
18237c478bd9Sstevel@tonic-gate 	retval = aio_req_find(resultp, &reqp);
18247c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
18257c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_cleanupq_mutex);
18267c478bd9Sstevel@tonic-gate 	if (retval == 0) {
18277c478bd9Sstevel@tonic-gate 		aphysio_unlock(reqp);
18287c478bd9Sstevel@tonic-gate 		aio_copyout_result(reqp);
18297c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
18307c478bd9Sstevel@tonic-gate 		aio_req_free(aiop, reqp);
18317c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
18327c478bd9Sstevel@tonic-gate 		return (0);
18337c478bd9Sstevel@tonic-gate 	} else if (retval == 1)
18347c478bd9Sstevel@tonic-gate 		return (EINPROGRESS);
18357c478bd9Sstevel@tonic-gate 	else if (retval == 2)
18367c478bd9Sstevel@tonic-gate 		return (EINVAL);
18377c478bd9Sstevel@tonic-gate 	return (0);
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate /*
18417c478bd9Sstevel@tonic-gate  * 	aio_cancel - if no requests outstanding,
18427c478bd9Sstevel@tonic-gate  *			return AIO_ALLDONE
18437c478bd9Sstevel@tonic-gate  *			else
18447c478bd9Sstevel@tonic-gate  *			return AIO_NOTCANCELED
18457c478bd9Sstevel@tonic-gate  */
18467c478bd9Sstevel@tonic-gate static int
aio_cancel(int fildes,void * cb,long * rval,int run_mode)18477c478bd9Sstevel@tonic-gate aio_cancel(
18487c478bd9Sstevel@tonic-gate 	int	fildes,
18497c478bd9Sstevel@tonic-gate 	void 	*cb,
18507c478bd9Sstevel@tonic-gate 	long	*rval,
18517c478bd9Sstevel@tonic-gate 	int	run_mode)
18527c478bd9Sstevel@tonic-gate {
18537c478bd9Sstevel@tonic-gate 	aio_t *aiop;
18547c478bd9Sstevel@tonic-gate 	void *resultp;
18557c478bd9Sstevel@tonic-gate 	int index;
18567c478bd9Sstevel@tonic-gate 	aio_req_t **bucket;
18577c478bd9Sstevel@tonic-gate 	aio_req_t *ent;
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	/*
18617c478bd9Sstevel@tonic-gate 	 * Verify valid file descriptor
18627c478bd9Sstevel@tonic-gate 	 */
18637c478bd9Sstevel@tonic-gate 	if ((getf(fildes)) == NULL) {
18647c478bd9Sstevel@tonic-gate 		return (EBADF);
18657c478bd9Sstevel@tonic-gate 	}
18667c478bd9Sstevel@tonic-gate 	releasef(fildes);
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
18697c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
18707c478bd9Sstevel@tonic-gate 		return (EINVAL);
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	if (aiop->aio_outstanding == 0) {
18737c478bd9Sstevel@tonic-gate 		*rval = AIO_ALLDONE;
18747c478bd9Sstevel@tonic-gate 		return (0);
18757c478bd9Sstevel@tonic-gate 	}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
18787c478bd9Sstevel@tonic-gate 	if (cb != NULL) {
18797c478bd9Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE) {
18807c478bd9Sstevel@tonic-gate 			if (run_mode == AIO_LARGEFILE)
18817c478bd9Sstevel@tonic-gate 				resultp = (aio_result_t *)&((aiocb64_32_t *)cb)
18827c478bd9Sstevel@tonic-gate 				    ->aio_resultp;
18837c478bd9Sstevel@tonic-gate 			else
18847c478bd9Sstevel@tonic-gate 				resultp = &((aiocb_t *)cb)->aio_resultp;
18857c478bd9Sstevel@tonic-gate 		}
18867c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
18877c478bd9Sstevel@tonic-gate 		else {
18887c478bd9Sstevel@tonic-gate 			if (run_mode == AIO_LARGEFILE)
18897c478bd9Sstevel@tonic-gate 				resultp = (aio_result_t *)&((aiocb64_32_t *)cb)
18907c478bd9Sstevel@tonic-gate 				    ->aio_resultp;
18917c478bd9Sstevel@tonic-gate 			else if (run_mode == AIO_32)
18927c478bd9Sstevel@tonic-gate 				resultp = (aio_result_t *)&((aiocb32_t *)cb)
18937c478bd9Sstevel@tonic-gate 				    ->aio_resultp;
18947c478bd9Sstevel@tonic-gate 		}
18957c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
18967c478bd9Sstevel@tonic-gate 		index = AIO_HASH(resultp);
18977c478bd9Sstevel@tonic-gate 		bucket = &aiop->aio_hash[index];
18987c478bd9Sstevel@tonic-gate 		for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) {
18997c478bd9Sstevel@tonic-gate 			if (ent->aio_req_resultp == resultp) {
19007c478bd9Sstevel@tonic-gate 				if ((ent->aio_req_flags & AIO_PENDING) == 0) {
19017c478bd9Sstevel@tonic-gate 					mutex_exit(&aiop->aio_mutex);
19027c478bd9Sstevel@tonic-gate 					*rval = AIO_ALLDONE;
19037c478bd9Sstevel@tonic-gate 					return (0);
19047c478bd9Sstevel@tonic-gate 				}
19057c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
19067c478bd9Sstevel@tonic-gate 				*rval = AIO_NOTCANCELED;
19077c478bd9Sstevel@tonic-gate 				return (0);
19087c478bd9Sstevel@tonic-gate 			}
19097c478bd9Sstevel@tonic-gate 		}
19107c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
19117c478bd9Sstevel@tonic-gate 		*rval = AIO_ALLDONE;
19127c478bd9Sstevel@tonic-gate 		return (0);
19137c478bd9Sstevel@tonic-gate 	}
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	for (index = 0; index < AIO_HASHSZ; index++) {
19167c478bd9Sstevel@tonic-gate 		bucket = &aiop->aio_hash[index];
19177c478bd9Sstevel@tonic-gate 		for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) {
19187c478bd9Sstevel@tonic-gate 			if (ent->aio_req_fd == fildes) {
19197c478bd9Sstevel@tonic-gate 				if ((ent->aio_req_flags & AIO_PENDING) != 0) {
19207c478bd9Sstevel@tonic-gate 					mutex_exit(&aiop->aio_mutex);
19217c478bd9Sstevel@tonic-gate 					*rval = AIO_NOTCANCELED;
19227c478bd9Sstevel@tonic-gate 					return (0);
19237c478bd9Sstevel@tonic-gate 				}
19247c478bd9Sstevel@tonic-gate 			}
19257c478bd9Sstevel@tonic-gate 		}
19267c478bd9Sstevel@tonic-gate 	}
19277c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
19287c478bd9Sstevel@tonic-gate 	*rval = AIO_ALLDONE;
19297c478bd9Sstevel@tonic-gate 	return (0);
19307c478bd9Sstevel@tonic-gate }
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate /*
19337c478bd9Sstevel@tonic-gate  * solaris version of asynchronous read and write
19347c478bd9Sstevel@tonic-gate  */
19357c478bd9Sstevel@tonic-gate static int
arw(int opcode,int fdes,char * bufp,int bufsize,offset_t offset,aio_result_t * resultp,int mode)19367c478bd9Sstevel@tonic-gate arw(
19377c478bd9Sstevel@tonic-gate 	int	opcode,
19387c478bd9Sstevel@tonic-gate 	int	fdes,
19397c478bd9Sstevel@tonic-gate 	char	*bufp,
19407c478bd9Sstevel@tonic-gate 	int	bufsize,
19417c478bd9Sstevel@tonic-gate 	offset_t	offset,
19427c478bd9Sstevel@tonic-gate 	aio_result_t	*resultp,
19437c478bd9Sstevel@tonic-gate 	int		mode)
19447c478bd9Sstevel@tonic-gate {
19457c478bd9Sstevel@tonic-gate 	file_t		*fp;
19467c478bd9Sstevel@tonic-gate 	int		error;
19477c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
19487c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
19497c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
19507c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
19517c478bd9Sstevel@tonic-gate #ifdef _LP64
19527c478bd9Sstevel@tonic-gate 	aiocb_t		aiocb;
19537c478bd9Sstevel@tonic-gate #else
19547c478bd9Sstevel@tonic-gate 	aiocb64_32_t	aiocb64;
19557c478bd9Sstevel@tonic-gate #endif
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
19587c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
19597c478bd9Sstevel@tonic-gate 		return (EINVAL);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	if ((fp = getf(fdes)) == NULL) {
19627c478bd9Sstevel@tonic-gate 		return (EBADF);
19637c478bd9Sstevel@tonic-gate 	}
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	/*
19667c478bd9Sstevel@tonic-gate 	 * check the permission of the partition
19677c478bd9Sstevel@tonic-gate 	 */
19687c478bd9Sstevel@tonic-gate 	if ((fp->f_flag & mode) == 0) {
19697c478bd9Sstevel@tonic-gate 		releasef(fdes);
19707c478bd9Sstevel@tonic-gate 		return (EBADF);
19717c478bd9Sstevel@tonic-gate 	}
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
19747c478bd9Sstevel@tonic-gate 	aio_func = check_vp(vp, mode);
19757c478bd9Sstevel@tonic-gate 	if (aio_func == NULL) {
19767c478bd9Sstevel@tonic-gate 		releasef(fdes);
19777c478bd9Sstevel@tonic-gate 		return (EBADFD);
19787c478bd9Sstevel@tonic-gate 	}
19797c478bd9Sstevel@tonic-gate #ifdef _LP64
19807c478bd9Sstevel@tonic-gate 	aiocb.aio_fildes = fdes;
19817c478bd9Sstevel@tonic-gate 	aiocb.aio_buf = bufp;
19827c478bd9Sstevel@tonic-gate 	aiocb.aio_nbytes = bufsize;
19837c478bd9Sstevel@tonic-gate 	aiocb.aio_offset = offset;
19847c478bd9Sstevel@tonic-gate 	aiocb.aio_sigevent.sigev_notify = 0;
1985*d2749ac6SRoger A. Faulkner 	error = aio_req_setup(&reqp, aiop, &aiocb, resultp, vp, 1);
19867c478bd9Sstevel@tonic-gate #else
19877c478bd9Sstevel@tonic-gate 	aiocb64.aio_fildes = fdes;
19887c478bd9Sstevel@tonic-gate 	aiocb64.aio_buf = (caddr32_t)bufp;
19897c478bd9Sstevel@tonic-gate 	aiocb64.aio_nbytes = bufsize;
19907c478bd9Sstevel@tonic-gate 	aiocb64.aio_offset = offset;
19917c478bd9Sstevel@tonic-gate 	aiocb64.aio_sigevent.sigev_notify = 0;
1992*d2749ac6SRoger A. Faulkner 	error = aio_req_setupLF(&reqp, aiop, &aiocb64, resultp, vp, 1);
19937c478bd9Sstevel@tonic-gate #endif
19947c478bd9Sstevel@tonic-gate 	if (error) {
19957c478bd9Sstevel@tonic-gate 		releasef(fdes);
19967c478bd9Sstevel@tonic-gate 		return (error);
19977c478bd9Sstevel@tonic-gate 	}
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	/*
20007c478bd9Sstevel@tonic-gate 	 * enable polling on this request if the opcode has
20017c478bd9Sstevel@tonic-gate 	 * the AIO poll bit set
20027c478bd9Sstevel@tonic-gate 	 */
20037c478bd9Sstevel@tonic-gate 	if (opcode & AIO_POLL_BIT)
20047c478bd9Sstevel@tonic-gate 		reqp->aio_req_flags |= AIO_POLL;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	if (bufsize == 0) {
20077c478bd9Sstevel@tonic-gate 		clear_active_fd(fdes);
20087c478bd9Sstevel@tonic-gate 		aio_zerolen(reqp);
20097c478bd9Sstevel@tonic-gate 		return (0);
20107c478bd9Sstevel@tonic-gate 	}
20117c478bd9Sstevel@tonic-gate 	/*
20127c478bd9Sstevel@tonic-gate 	 * send the request to driver.
20137c478bd9Sstevel@tonic-gate 	 */
20147c478bd9Sstevel@tonic-gate 	error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, CRED());
20157c478bd9Sstevel@tonic-gate 	/*
20167c478bd9Sstevel@tonic-gate 	 * the fd is stored in the aio_req_t by aio_req_setup(), and
20177c478bd9Sstevel@tonic-gate 	 * is released by the aio_cleanup_thread() when the IO has
20187c478bd9Sstevel@tonic-gate 	 * completed.
20197c478bd9Sstevel@tonic-gate 	 */
20207c478bd9Sstevel@tonic-gate 	if (error) {
20217c478bd9Sstevel@tonic-gate 		releasef(fdes);
20227c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
20237c478bd9Sstevel@tonic-gate 		aio_req_free(aiop, reqp);
20247c478bd9Sstevel@tonic-gate 		aiop->aio_pending--;
20257c478bd9Sstevel@tonic-gate 		if (aiop->aio_flags & AIO_REQ_BLOCK)
20267c478bd9Sstevel@tonic-gate 			cv_signal(&aiop->aio_cleanupcv);
20277c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
20287c478bd9Sstevel@tonic-gate 		return (error);
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 	clear_active_fd(fdes);
20317c478bd9Sstevel@tonic-gate 	return (0);
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate /*
20357c478bd9Sstevel@tonic-gate  * posix version of asynchronous read and write
20367c478bd9Sstevel@tonic-gate  */
20377c478bd9Sstevel@tonic-gate static int
aiorw(int opcode,void * aiocb_arg,int mode,int run_mode)20387c478bd9Sstevel@tonic-gate aiorw(
20397c478bd9Sstevel@tonic-gate 	int		opcode,
20407c478bd9Sstevel@tonic-gate 	void		*aiocb_arg,
20417c478bd9Sstevel@tonic-gate 	int		mode,
20427c478bd9Sstevel@tonic-gate 	int		run_mode)
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
20457c478bd9Sstevel@tonic-gate 	aiocb32_t	aiocb32;
20467c478bd9Sstevel@tonic-gate 	struct	sigevent32 *sigev32;
20477c478bd9Sstevel@tonic-gate 	port_notify32_t	pntfy32;
20487c478bd9Sstevel@tonic-gate #endif
20497c478bd9Sstevel@tonic-gate 	aiocb64_32_t	aiocb64;
20507c478bd9Sstevel@tonic-gate 	aiocb_t		aiocb;
20517c478bd9Sstevel@tonic-gate 	file_t		*fp;
20527c478bd9Sstevel@tonic-gate 	int		error, fd;
20537c478bd9Sstevel@tonic-gate 	size_t		bufsize;
20547c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
20557c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
20567c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
20577c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
20587c478bd9Sstevel@tonic-gate 	aio_result_t	*resultp;
20597c478bd9Sstevel@tonic-gate 	struct	sigevent *sigev;
20607c478bd9Sstevel@tonic-gate 	model_t		model;
20617c478bd9Sstevel@tonic-gate 	int		aio_use_port = 0;
20627c478bd9Sstevel@tonic-gate 	port_notify_t	pntfy;
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
20657c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
20667c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
20677c478bd9Sstevel@tonic-gate 		return (EINVAL);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE) {
20707c478bd9Sstevel@tonic-gate 		if (run_mode != AIO_LARGEFILE) {
20717c478bd9Sstevel@tonic-gate 			if (copyin(aiocb_arg, &aiocb, sizeof (aiocb_t)))
20727c478bd9Sstevel@tonic-gate 				return (EFAULT);
20737c478bd9Sstevel@tonic-gate 			bufsize = aiocb.aio_nbytes;
20747c478bd9Sstevel@tonic-gate 			resultp = &(((aiocb_t *)aiocb_arg)->aio_resultp);
20757c478bd9Sstevel@tonic-gate 			if ((fp = getf(fd = aiocb.aio_fildes)) == NULL) {
20767c478bd9Sstevel@tonic-gate 				return (EBADF);
20777c478bd9Sstevel@tonic-gate 			}
20787c478bd9Sstevel@tonic-gate 			sigev = &aiocb.aio_sigevent;
20797c478bd9Sstevel@tonic-gate 		} else {
20807c478bd9Sstevel@tonic-gate 			/*
20817c478bd9Sstevel@tonic-gate 			 * We come here only when we make largefile
20827c478bd9Sstevel@tonic-gate 			 * call on 32 bit kernel using 32 bit library.
20837c478bd9Sstevel@tonic-gate 			 */
20847c478bd9Sstevel@tonic-gate 			if (copyin(aiocb_arg, &aiocb64, sizeof (aiocb64_32_t)))
20857c478bd9Sstevel@tonic-gate 				return (EFAULT);
20867c478bd9Sstevel@tonic-gate 			bufsize = aiocb64.aio_nbytes;
20877c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&(((aiocb64_32_t *)aiocb_arg)
20887c478bd9Sstevel@tonic-gate 			    ->aio_resultp);
208934709573Sraf 			if ((fp = getf(fd = aiocb64.aio_fildes)) == NULL)
20907c478bd9Sstevel@tonic-gate 				return (EBADF);
20917c478bd9Sstevel@tonic-gate 			sigev = (struct sigevent *)&aiocb64.aio_sigevent;
20927c478bd9Sstevel@tonic-gate 		}
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 		if (sigev->sigev_notify == SIGEV_PORT) {
20957c478bd9Sstevel@tonic-gate 			if (copyin((void *)sigev->sigev_value.sival_ptr,
20967c478bd9Sstevel@tonic-gate 			    &pntfy, sizeof (port_notify_t))) {
20977c478bd9Sstevel@tonic-gate 				releasef(fd);
20987c478bd9Sstevel@tonic-gate 				return (EFAULT);
20997c478bd9Sstevel@tonic-gate 			}
21007c478bd9Sstevel@tonic-gate 			aio_use_port = 1;
210134709573Sraf 		} else if (sigev->sigev_notify == SIGEV_THREAD) {
210234709573Sraf 			pntfy.portnfy_port = aiocb.aio_sigevent.sigev_signo;
210334709573Sraf 			pntfy.portnfy_user =
210434709573Sraf 			    aiocb.aio_sigevent.sigev_value.sival_ptr;
210534709573Sraf 			aio_use_port = 1;
21067c478bd9Sstevel@tonic-gate 		}
21077c478bd9Sstevel@tonic-gate 	}
21087c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
21097c478bd9Sstevel@tonic-gate 	else {
21107c478bd9Sstevel@tonic-gate 		if (run_mode == AIO_32) {
21117c478bd9Sstevel@tonic-gate 			/* 32 bit system call is being made on 64 bit kernel */
21127c478bd9Sstevel@tonic-gate 			if (copyin(aiocb_arg, &aiocb32, sizeof (aiocb32_t)))
21137c478bd9Sstevel@tonic-gate 				return (EFAULT);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 			bufsize = aiocb32.aio_nbytes;
21167c478bd9Sstevel@tonic-gate 			aiocb_32ton(&aiocb32, &aiocb);
21177c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&(((aiocb32_t *)aiocb_arg)->
21187c478bd9Sstevel@tonic-gate 			    aio_resultp);
21197c478bd9Sstevel@tonic-gate 			if ((fp = getf(fd = aiocb32.aio_fildes)) == NULL) {
21207c478bd9Sstevel@tonic-gate 				return (EBADF);
21217c478bd9Sstevel@tonic-gate 			}
21227c478bd9Sstevel@tonic-gate 			sigev32 = &aiocb32.aio_sigevent;
21237c478bd9Sstevel@tonic-gate 		} else if (run_mode == AIO_LARGEFILE) {
21247c478bd9Sstevel@tonic-gate 			/*
21257c478bd9Sstevel@tonic-gate 			 * We come here only when we make largefile
21267c478bd9Sstevel@tonic-gate 			 * call on 64 bit kernel using 32 bit library.
21277c478bd9Sstevel@tonic-gate 			 */
21287c478bd9Sstevel@tonic-gate 			if (copyin(aiocb_arg, &aiocb64, sizeof (aiocb64_32_t)))
21297c478bd9Sstevel@tonic-gate 				return (EFAULT);
21307c478bd9Sstevel@tonic-gate 			bufsize = aiocb64.aio_nbytes;
21317c478bd9Sstevel@tonic-gate 			aiocb_LFton(&aiocb64, &aiocb);
21327c478bd9Sstevel@tonic-gate 			resultp = (aio_result_t *)&(((aiocb64_32_t *)aiocb_arg)
21337c478bd9Sstevel@tonic-gate 			    ->aio_resultp);
21347c478bd9Sstevel@tonic-gate 			if ((fp = getf(fd = aiocb64.aio_fildes)) == NULL)
21357c478bd9Sstevel@tonic-gate 				return (EBADF);
21367c478bd9Sstevel@tonic-gate 			sigev32 = &aiocb64.aio_sigevent;
21377c478bd9Sstevel@tonic-gate 		}
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 		if (sigev32->sigev_notify == SIGEV_PORT) {
21407c478bd9Sstevel@tonic-gate 			if (copyin(
21417c478bd9Sstevel@tonic-gate 			    (void *)(uintptr_t)sigev32->sigev_value.sival_ptr,
21427c478bd9Sstevel@tonic-gate 			    &pntfy32, sizeof (port_notify32_t))) {
21437c478bd9Sstevel@tonic-gate 				releasef(fd);
21447c478bd9Sstevel@tonic-gate 				return (EFAULT);
21457c478bd9Sstevel@tonic-gate 			}
21467c478bd9Sstevel@tonic-gate 			pntfy.portnfy_port = pntfy32.portnfy_port;
214734709573Sraf 			pntfy.portnfy_user = (void *)(uintptr_t)
214834709573Sraf 			    pntfy32.portnfy_user;
214934709573Sraf 			aio_use_port = 1;
215034709573Sraf 		} else if (sigev32->sigev_notify == SIGEV_THREAD) {
215134709573Sraf 			pntfy.portnfy_port = sigev32->sigev_signo;
215234709573Sraf 			pntfy.portnfy_user = (void *)(uintptr_t)
215334709573Sraf 			    sigev32->sigev_value.sival_ptr;
21547c478bd9Sstevel@tonic-gate 			aio_use_port = 1;
21557c478bd9Sstevel@tonic-gate 		}
21567c478bd9Sstevel@tonic-gate 	}
21577c478bd9Sstevel@tonic-gate #endif  /* _SYSCALL32_IMPL */
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	/*
21607c478bd9Sstevel@tonic-gate 	 * check the permission of the partition
21617c478bd9Sstevel@tonic-gate 	 */
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	if ((fp->f_flag & mode) == 0) {
21647c478bd9Sstevel@tonic-gate 		releasef(fd);
21657c478bd9Sstevel@tonic-gate 		return (EBADF);
21667c478bd9Sstevel@tonic-gate 	}
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
21697c478bd9Sstevel@tonic-gate 	aio_func = check_vp(vp, mode);
21707c478bd9Sstevel@tonic-gate 	if (aio_func == NULL) {
21717c478bd9Sstevel@tonic-gate 		releasef(fd);
21727c478bd9Sstevel@tonic-gate 		return (EBADFD);
21737c478bd9Sstevel@tonic-gate 	}
217434709573Sraf 	if (run_mode == AIO_LARGEFILE)
2175*d2749ac6SRoger A. Faulkner 		error = aio_req_setupLF(&reqp, aiop, &aiocb64, resultp, vp, 0);
21767c478bd9Sstevel@tonic-gate 	else
2177*d2749ac6SRoger A. Faulkner 		error = aio_req_setup(&reqp, aiop, &aiocb, resultp, vp, 0);
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	if (error) {
21807c478bd9Sstevel@tonic-gate 		releasef(fd);
21817c478bd9Sstevel@tonic-gate 		return (error);
21827c478bd9Sstevel@tonic-gate 	}
21837c478bd9Sstevel@tonic-gate 	/*
21847c478bd9Sstevel@tonic-gate 	 * enable polling on this request if the opcode has
21857c478bd9Sstevel@tonic-gate 	 * the AIO poll bit set
21867c478bd9Sstevel@tonic-gate 	 */
21877c478bd9Sstevel@tonic-gate 	if (opcode & AIO_POLL_BIT)
21887c478bd9Sstevel@tonic-gate 		reqp->aio_req_flags |= AIO_POLL;
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_NATIVE)
21917c478bd9Sstevel@tonic-gate 		reqp->aio_req_iocb.iocb = aiocb_arg;
21927c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
21937c478bd9Sstevel@tonic-gate 	else
21947c478bd9Sstevel@tonic-gate 		reqp->aio_req_iocb.iocb32 = (caddr32_t)(uintptr_t)aiocb_arg;
21957c478bd9Sstevel@tonic-gate #endif
21967c478bd9Sstevel@tonic-gate 
219734709573Sraf 	if (aio_use_port) {
219834709573Sraf 		int event = (run_mode == AIO_LARGEFILE)?
219934709573Sraf 		    ((mode == FREAD)? AIOAREAD64 : AIOAWRITE64) :
220034709573Sraf 		    ((mode == FREAD)? AIOAREAD : AIOAWRITE);
220134709573Sraf 		error = aio_req_assoc_port_rw(&pntfy, aiocb_arg, reqp, event);
220234709573Sraf 	}
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	/*
22057c478bd9Sstevel@tonic-gate 	 * send the request to driver.
22067c478bd9Sstevel@tonic-gate 	 */
22077c478bd9Sstevel@tonic-gate 	if (error == 0) {
22087c478bd9Sstevel@tonic-gate 		if (bufsize == 0) {
22097c478bd9Sstevel@tonic-gate 			clear_active_fd(fd);
22107c478bd9Sstevel@tonic-gate 			aio_zerolen(reqp);
22117c478bd9Sstevel@tonic-gate 			return (0);
22127c478bd9Sstevel@tonic-gate 		}
22137c478bd9Sstevel@tonic-gate 		error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req, CRED());
22147c478bd9Sstevel@tonic-gate 	}
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	/*
22177c478bd9Sstevel@tonic-gate 	 * the fd is stored in the aio_req_t by aio_req_setup(), and
22187c478bd9Sstevel@tonic-gate 	 * is released by the aio_cleanup_thread() when the IO has
22197c478bd9Sstevel@tonic-gate 	 * completed.
22207c478bd9Sstevel@tonic-gate 	 */
22217c478bd9Sstevel@tonic-gate 	if (error) {
22227c478bd9Sstevel@tonic-gate 		releasef(fd);
22237c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
222434b3058fSpraks 		if (aio_use_port)
222534709573Sraf 			aio_deq(&aiop->aio_portpending, reqp);
22267c478bd9Sstevel@tonic-gate 		aio_req_free(aiop, reqp);
22277c478bd9Sstevel@tonic-gate 		aiop->aio_pending--;
22287c478bd9Sstevel@tonic-gate 		if (aiop->aio_flags & AIO_REQ_BLOCK)
22297c478bd9Sstevel@tonic-gate 			cv_signal(&aiop->aio_cleanupcv);
22307c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
22317c478bd9Sstevel@tonic-gate 		return (error);
22327c478bd9Sstevel@tonic-gate 	}
22337c478bd9Sstevel@tonic-gate 	clear_active_fd(fd);
22347c478bd9Sstevel@tonic-gate 	return (0);
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate /*
22397c478bd9Sstevel@tonic-gate  * set error for a list IO entry that failed.
22407c478bd9Sstevel@tonic-gate  */
22417c478bd9Sstevel@tonic-gate static void
lio_set_error(aio_req_t * reqp,int portused)224234b3058fSpraks lio_set_error(aio_req_t *reqp, int portused)
22437c478bd9Sstevel@tonic-gate {
22447c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	if (aiop == NULL)
22477c478bd9Sstevel@tonic-gate 		return;
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
225034b3058fSpraks 	if (portused)
225134709573Sraf 		aio_deq(&aiop->aio_portpending, reqp);
22527c478bd9Sstevel@tonic-gate 	aiop->aio_pending--;
22537c478bd9Sstevel@tonic-gate 	/* request failed, AIO_PHYSIODONE set to aviod physio cleanup. */
22547c478bd9Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_PHYSIODONE;
22557c478bd9Sstevel@tonic-gate 	/*
22567c478bd9Sstevel@tonic-gate 	 * Need to free the request now as its never
22577c478bd9Sstevel@tonic-gate 	 * going to get on the done queue
22587c478bd9Sstevel@tonic-gate 	 *
22597c478bd9Sstevel@tonic-gate 	 * Note: aio_outstanding is decremented in
22607c478bd9Sstevel@tonic-gate 	 *	 aio_req_free()
22617c478bd9Sstevel@tonic-gate 	 */
22627c478bd9Sstevel@tonic-gate 	aio_req_free(aiop, reqp);
22637c478bd9Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_REQ_BLOCK)
22647c478bd9Sstevel@tonic-gate 		cv_signal(&aiop->aio_cleanupcv);
22657c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate /*
22697c478bd9Sstevel@tonic-gate  * check if a specified request is done, and remove it from
22707c478bd9Sstevel@tonic-gate  * the done queue. otherwise remove anybody from the done queue
22717c478bd9Sstevel@tonic-gate  * if NULL is specified.
22727c478bd9Sstevel@tonic-gate  */
22737c478bd9Sstevel@tonic-gate static aio_req_t *
aio_req_done(void * resultp)22747c478bd9Sstevel@tonic-gate aio_req_done(void *resultp)
22757c478bd9Sstevel@tonic-gate {
22767c478bd9Sstevel@tonic-gate 	aio_req_t **bucket;
22777c478bd9Sstevel@tonic-gate 	aio_req_t *ent;
22787c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
22797c478bd9Sstevel@tonic-gate 	long index;
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex));
22827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 	if (resultp) {
22857c478bd9Sstevel@tonic-gate 		index = AIO_HASH(resultp);
22867c478bd9Sstevel@tonic-gate 		bucket = &aiop->aio_hash[index];
22877c478bd9Sstevel@tonic-gate 		for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) {
22887c478bd9Sstevel@tonic-gate 			if (ent->aio_req_resultp == (aio_result_t *)resultp) {
22897c478bd9Sstevel@tonic-gate 				if (ent->aio_req_flags & AIO_DONEQ) {
22907c478bd9Sstevel@tonic-gate 					return (aio_req_remove(ent));
22917c478bd9Sstevel@tonic-gate 				}
22927c478bd9Sstevel@tonic-gate 				return (NULL);
22937c478bd9Sstevel@tonic-gate 			}
22947c478bd9Sstevel@tonic-gate 		}
22957c478bd9Sstevel@tonic-gate 		/* no match, resultp is invalid */
22967c478bd9Sstevel@tonic-gate 		return (NULL);
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 	return (aio_req_remove(NULL));
22997c478bd9Sstevel@tonic-gate }
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate /*
23027c478bd9Sstevel@tonic-gate  * determine if a user-level resultp pointer is associated with an
23037c478bd9Sstevel@tonic-gate  * active IO request. Zero is returned when the request is done,
23047c478bd9Sstevel@tonic-gate  * and the request is removed from the done queue. Only when the
23057c478bd9Sstevel@tonic-gate  * return value is zero, is the "reqp" pointer valid. One is returned
23067c478bd9Sstevel@tonic-gate  * when the request is inprogress. Two is returned when the request
23077c478bd9Sstevel@tonic-gate  * is invalid.
23087c478bd9Sstevel@tonic-gate  */
23097c478bd9Sstevel@tonic-gate static int
aio_req_find(aio_result_t * resultp,aio_req_t ** reqp)23107c478bd9Sstevel@tonic-gate aio_req_find(aio_result_t *resultp, aio_req_t **reqp)
23117c478bd9Sstevel@tonic-gate {
23127c478bd9Sstevel@tonic-gate 	aio_req_t **bucket;
23137c478bd9Sstevel@tonic-gate 	aio_req_t *ent;
23147c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
23157c478bd9Sstevel@tonic-gate 	long index;
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex));
23187c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 	index = AIO_HASH(resultp);
23217c478bd9Sstevel@tonic-gate 	bucket = &aiop->aio_hash[index];
23227c478bd9Sstevel@tonic-gate 	for (ent = *bucket; ent != NULL; ent = ent->aio_hash_next) {
23237c478bd9Sstevel@tonic-gate 		if (ent->aio_req_resultp == resultp) {
23247c478bd9Sstevel@tonic-gate 			if (ent->aio_req_flags & AIO_DONEQ) {
23257c478bd9Sstevel@tonic-gate 				*reqp = aio_req_remove(ent);
23267c478bd9Sstevel@tonic-gate 				return (0);
23277c478bd9Sstevel@tonic-gate 			}
23287c478bd9Sstevel@tonic-gate 			return (1);
23297c478bd9Sstevel@tonic-gate 		}
23307c478bd9Sstevel@tonic-gate 	}
23317c478bd9Sstevel@tonic-gate 	/* no match, resultp is invalid */
23327c478bd9Sstevel@tonic-gate 	return (2);
23337c478bd9Sstevel@tonic-gate }
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate /*
23367c478bd9Sstevel@tonic-gate  * remove a request from the done queue.
23377c478bd9Sstevel@tonic-gate  */
23387c478bd9Sstevel@tonic-gate static aio_req_t *
aio_req_remove(aio_req_t * reqp)23397c478bd9Sstevel@tonic-gate aio_req_remove(aio_req_t *reqp)
23407c478bd9Sstevel@tonic-gate {
23417c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
23447c478bd9Sstevel@tonic-gate 
234534709573Sraf 	if (reqp != NULL) {
23467c478bd9Sstevel@tonic-gate 		ASSERT(reqp->aio_req_flags & AIO_DONEQ);
23477c478bd9Sstevel@tonic-gate 		if (reqp->aio_req_next == reqp) {
23487c478bd9Sstevel@tonic-gate 			/* only one request on queue */
23497c478bd9Sstevel@tonic-gate 			if (reqp ==  aiop->aio_doneq) {
23507c478bd9Sstevel@tonic-gate 				aiop->aio_doneq = NULL;
23517c478bd9Sstevel@tonic-gate 			} else {
23527c478bd9Sstevel@tonic-gate 				ASSERT(reqp == aiop->aio_cleanupq);
23537c478bd9Sstevel@tonic-gate 				aiop->aio_cleanupq = NULL;
23547c478bd9Sstevel@tonic-gate 			}
23557c478bd9Sstevel@tonic-gate 		} else {
23567c478bd9Sstevel@tonic-gate 			reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
23577c478bd9Sstevel@tonic-gate 			reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
23587c478bd9Sstevel@tonic-gate 			/*
23597c478bd9Sstevel@tonic-gate 			 * The request can be either on the aio_doneq or the
23607c478bd9Sstevel@tonic-gate 			 * aio_cleanupq
23617c478bd9Sstevel@tonic-gate 			 */
23627c478bd9Sstevel@tonic-gate 			if (reqp == aiop->aio_doneq)
23637c478bd9Sstevel@tonic-gate 				aiop->aio_doneq = reqp->aio_req_next;
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 			if (reqp == aiop->aio_cleanupq)
23667c478bd9Sstevel@tonic-gate 				aiop->aio_cleanupq = reqp->aio_req_next;
23677c478bd9Sstevel@tonic-gate 		}
23687c478bd9Sstevel@tonic-gate 		reqp->aio_req_flags &= ~AIO_DONEQ;
236934709573Sraf 		reqp->aio_req_next = NULL;
237034709573Sraf 		reqp->aio_req_prev = NULL;
237134709573Sraf 	} else if ((reqp = aiop->aio_doneq) != NULL) {
237234709573Sraf 		ASSERT(reqp->aio_req_flags & AIO_DONEQ);
237334709573Sraf 		if (reqp == reqp->aio_req_next) {
23747c478bd9Sstevel@tonic-gate 			/* only one request on queue */
23757c478bd9Sstevel@tonic-gate 			aiop->aio_doneq = NULL;
23767c478bd9Sstevel@tonic-gate 		} else {
237734709573Sraf 			reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
237834709573Sraf 			reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
237934709573Sraf 			aiop->aio_doneq = reqp->aio_req_next;
23807c478bd9Sstevel@tonic-gate 		}
238134709573Sraf 		reqp->aio_req_flags &= ~AIO_DONEQ;
238234709573Sraf 		reqp->aio_req_next = NULL;
238334709573Sraf 		reqp->aio_req_prev = NULL;
23847c478bd9Sstevel@tonic-gate 	}
238534709573Sraf 	if (aiop->aio_doneq == NULL && (aiop->aio_flags & AIO_WAITN))
238634709573Sraf 		cv_broadcast(&aiop->aio_waitcv);
238734709573Sraf 	return (reqp);
23887c478bd9Sstevel@tonic-gate }
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate static int
aio_req_setup(aio_req_t ** reqpp,aio_t * aiop,aiocb_t * arg,aio_result_t * resultp,vnode_t * vp,int old_solaris_req)23917c478bd9Sstevel@tonic-gate aio_req_setup(
23927c478bd9Sstevel@tonic-gate 	aio_req_t	**reqpp,
23937c478bd9Sstevel@tonic-gate 	aio_t 		*aiop,
23947c478bd9Sstevel@tonic-gate 	aiocb_t 	*arg,
23957c478bd9Sstevel@tonic-gate 	aio_result_t 	*resultp,
2396*d2749ac6SRoger A. Faulkner 	vnode_t		*vp,
2397*d2749ac6SRoger A. Faulkner 	int		old_solaris_req)
23987c478bd9Sstevel@tonic-gate {
239934709573Sraf 	sigqueue_t	*sqp = NULL;
24007c478bd9Sstevel@tonic-gate 	aio_req_t 	*reqp;
24017c478bd9Sstevel@tonic-gate 	struct uio 	*uio;
24027c478bd9Sstevel@tonic-gate 	struct sigevent *sigev;
24037c478bd9Sstevel@tonic-gate 	int		error;
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	sigev = &arg->aio_sigevent;
240634709573Sraf 	if (sigev->sigev_notify == SIGEV_SIGNAL &&
240734709573Sraf 	    sigev->sigev_signo > 0 && sigev->sigev_signo < NSIG) {
24087c478bd9Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP);
24097c478bd9Sstevel@tonic-gate 		if (sqp == NULL)
24107c478bd9Sstevel@tonic-gate 			return (EAGAIN);
24117c478bd9Sstevel@tonic-gate 		sqp->sq_func = NULL;
24127c478bd9Sstevel@tonic-gate 		sqp->sq_next = NULL;
24137c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_code = SI_ASYNCIO;
24147c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_pid = curproc->p_pid;
24157c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_ctid = PRCTID(curproc);
24167c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_zoneid = getzoneid();
24177c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_uid = crgetuid(curproc->p_cred);
24187c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_signo = sigev->sigev_signo;
24197c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_value = sigev->sigev_value;
242034709573Sraf 	}
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_REQ_BLOCK) {
24257c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
24267c478bd9Sstevel@tonic-gate 		if (sqp)
24277c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
24287c478bd9Sstevel@tonic-gate 		return (EIO);
24297c478bd9Sstevel@tonic-gate 	}
24307c478bd9Sstevel@tonic-gate 	/*
24317c478bd9Sstevel@tonic-gate 	 * get an aio_reqp from the free list or allocate one
24327c478bd9Sstevel@tonic-gate 	 * from dynamic memory.
24337c478bd9Sstevel@tonic-gate 	 */
24347c478bd9Sstevel@tonic-gate 	if (error = aio_req_alloc(&reqp, resultp)) {
24357c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
24367c478bd9Sstevel@tonic-gate 		if (sqp)
24377c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
24387c478bd9Sstevel@tonic-gate 		return (error);
24397c478bd9Sstevel@tonic-gate 	}
24407c478bd9Sstevel@tonic-gate 	aiop->aio_pending++;
24417c478bd9Sstevel@tonic-gate 	aiop->aio_outstanding++;
24427c478bd9Sstevel@tonic-gate 	reqp->aio_req_flags = AIO_PENDING;
2443*d2749ac6SRoger A. Faulkner 	if (old_solaris_req) {
2444*d2749ac6SRoger A. Faulkner 		/* this is an old solaris aio request */
2445*d2749ac6SRoger A. Faulkner 		reqp->aio_req_flags |= AIO_SOLARIS;
2446*d2749ac6SRoger A. Faulkner 		aiop->aio_flags |= AIO_SOLARIS_REQ;
2447*d2749ac6SRoger A. Faulkner 	}
244834709573Sraf 	if (sigev->sigev_notify == SIGEV_THREAD ||
244934709573Sraf 	    sigev->sigev_notify == SIGEV_PORT)
245034709573Sraf 		aio_enq(&aiop->aio_portpending, reqp, 0);
24517c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
24527c478bd9Sstevel@tonic-gate 	/*
24537c478bd9Sstevel@tonic-gate 	 * initialize aio request.
24547c478bd9Sstevel@tonic-gate 	 */
24557c478bd9Sstevel@tonic-gate 	reqp->aio_req_fd = arg->aio_fildes;
24567c478bd9Sstevel@tonic-gate 	reqp->aio_req_sigqp = sqp;
24577c478bd9Sstevel@tonic-gate 	reqp->aio_req_iocb.iocb = NULL;
245834709573Sraf 	reqp->aio_req_lio = NULL;
24597c478bd9Sstevel@tonic-gate 	reqp->aio_req_buf.b_file = vp;
24607c478bd9Sstevel@tonic-gate 	uio = reqp->aio_req.aio_uio;
24617c478bd9Sstevel@tonic-gate 	uio->uio_iovcnt = 1;
24627c478bd9Sstevel@tonic-gate 	uio->uio_iov->iov_base = (caddr_t)arg->aio_buf;
24637c478bd9Sstevel@tonic-gate 	uio->uio_iov->iov_len = arg->aio_nbytes;
24647c478bd9Sstevel@tonic-gate 	uio->uio_loffset = arg->aio_offset;
24657c478bd9Sstevel@tonic-gate 	*reqpp = reqp;
24667c478bd9Sstevel@tonic-gate 	return (0);
24677c478bd9Sstevel@tonic-gate }
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate /*
24707c478bd9Sstevel@tonic-gate  * Allocate p_aio struct.
24717c478bd9Sstevel@tonic-gate  */
24727c478bd9Sstevel@tonic-gate static aio_t *
aio_aiop_alloc(void)24737c478bd9Sstevel@tonic-gate aio_aiop_alloc(void)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate 	aio_t	*aiop;
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&curproc->p_lock));
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	aiop = kmem_zalloc(sizeof (struct aio), KM_NOSLEEP);
24807c478bd9Sstevel@tonic-gate 	if (aiop) {
24817c478bd9Sstevel@tonic-gate 		mutex_init(&aiop->aio_mutex, NULL, MUTEX_DEFAULT, NULL);
24827c478bd9Sstevel@tonic-gate 		mutex_init(&aiop->aio_cleanupq_mutex, NULL, MUTEX_DEFAULT,
24837c478bd9Sstevel@tonic-gate 		    NULL);
24847c478bd9Sstevel@tonic-gate 		mutex_init(&aiop->aio_portq_mutex, NULL, MUTEX_DEFAULT, NULL);
24857c478bd9Sstevel@tonic-gate 	}
24867c478bd9Sstevel@tonic-gate 	return (aiop);
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate /*
24907c478bd9Sstevel@tonic-gate  * Allocate an aio_req struct.
24917c478bd9Sstevel@tonic-gate  */
24927c478bd9Sstevel@tonic-gate static int
aio_req_alloc(aio_req_t ** nreqp,aio_result_t * resultp)24937c478bd9Sstevel@tonic-gate aio_req_alloc(aio_req_t **nreqp, aio_result_t *resultp)
24947c478bd9Sstevel@tonic-gate {
24957c478bd9Sstevel@tonic-gate 	aio_req_t *reqp;
24967c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	if ((reqp = aiop->aio_free) != NULL) {
25017c478bd9Sstevel@tonic-gate 		aiop->aio_free = reqp->aio_req_next;
250234709573Sraf 		bzero(reqp, sizeof (*reqp));
25037c478bd9Sstevel@tonic-gate 	} else {
25047c478bd9Sstevel@tonic-gate 		/*
25057c478bd9Sstevel@tonic-gate 		 * Check whether memory is getting tight.
25067c478bd9Sstevel@tonic-gate 		 * This is a temporary mechanism to avoid memory
25077c478bd9Sstevel@tonic-gate 		 * exhaustion by a single process until we come up
25087c478bd9Sstevel@tonic-gate 		 * with a per process solution such as setrlimit().
25097c478bd9Sstevel@tonic-gate 		 */
25107c478bd9Sstevel@tonic-gate 		if (freemem < desfree)
25117c478bd9Sstevel@tonic-gate 			return (EAGAIN);
25127c478bd9Sstevel@tonic-gate 		reqp = kmem_zalloc(sizeof (struct aio_req_t), KM_NOSLEEP);
25137c478bd9Sstevel@tonic-gate 		if (reqp == NULL)
25147c478bd9Sstevel@tonic-gate 			return (EAGAIN);
25157c478bd9Sstevel@tonic-gate 	}
251634709573Sraf 	reqp->aio_req.aio_uio = &reqp->aio_req_uio;
251734709573Sraf 	reqp->aio_req.aio_uio->uio_iov = &reqp->aio_req_iov;
251834709573Sraf 	reqp->aio_req.aio_private = reqp;
25197c478bd9Sstevel@tonic-gate 	reqp->aio_req_buf.b_offset = -1;
25207c478bd9Sstevel@tonic-gate 	reqp->aio_req_resultp = resultp;
25217c478bd9Sstevel@tonic-gate 	if (aio_hash_insert(reqp, aiop)) {
25227c478bd9Sstevel@tonic-gate 		reqp->aio_req_next = aiop->aio_free;
25237c478bd9Sstevel@tonic-gate 		aiop->aio_free = reqp;
252475e1bcdeSPrakash Sangappa 		return (EBUSY);
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 	*nreqp = reqp;
25277c478bd9Sstevel@tonic-gate 	return (0);
25287c478bd9Sstevel@tonic-gate }
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate /*
25317c478bd9Sstevel@tonic-gate  * Allocate an aio_lio_t struct.
25327c478bd9Sstevel@tonic-gate  */
25337c478bd9Sstevel@tonic-gate static int
aio_lio_alloc(aio_lio_t ** head)25347c478bd9Sstevel@tonic-gate aio_lio_alloc(aio_lio_t **head)
25357c478bd9Sstevel@tonic-gate {
25367c478bd9Sstevel@tonic-gate 	aio_lio_t *liop;
25377c478bd9Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	if ((liop = aiop->aio_lio_free) != NULL) {
25427c478bd9Sstevel@tonic-gate 		aiop->aio_lio_free = liop->lio_next;
25437c478bd9Sstevel@tonic-gate 	} else {
25447c478bd9Sstevel@tonic-gate 		/*
25457c478bd9Sstevel@tonic-gate 		 * Check whether memory is getting tight.
25467c478bd9Sstevel@tonic-gate 		 * This is a temporary mechanism to avoid memory
25477c478bd9Sstevel@tonic-gate 		 * exhaustion by a single process until we come up
25487c478bd9Sstevel@tonic-gate 		 * with a per process solution such as setrlimit().
25497c478bd9Sstevel@tonic-gate 		 */
25507c478bd9Sstevel@tonic-gate 		if (freemem < desfree)
25517c478bd9Sstevel@tonic-gate 			return (EAGAIN);
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 		liop = kmem_zalloc(sizeof (aio_lio_t), KM_NOSLEEP);
25547c478bd9Sstevel@tonic-gate 		if (liop == NULL)
25557c478bd9Sstevel@tonic-gate 			return (EAGAIN);
25567c478bd9Sstevel@tonic-gate 	}
25577c478bd9Sstevel@tonic-gate 	*head = liop;
25587c478bd9Sstevel@tonic-gate 	return (0);
25597c478bd9Sstevel@tonic-gate }
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate /*
25627c478bd9Sstevel@tonic-gate  * this is a special per-process thread that is only activated if
25637c478bd9Sstevel@tonic-gate  * the process is unmapping a segment with outstanding aio. normally,
25647c478bd9Sstevel@tonic-gate  * the process will have completed the aio before unmapping the
25657c478bd9Sstevel@tonic-gate  * segment. If the process does unmap a segment with outstanding aio,
25667c478bd9Sstevel@tonic-gate  * this special thread will guarentee that the locked pages due to
25677c478bd9Sstevel@tonic-gate  * aphysio() are released, thereby permitting the segment to be
2568b0b27ce6Spraks  * unmapped. In addition to this, the cleanup thread is woken up
2569b0b27ce6Spraks  * during DR operations to release the locked pages.
25707c478bd9Sstevel@tonic-gate  */
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate static int
aio_cleanup_thread(aio_t * aiop)25737c478bd9Sstevel@tonic-gate aio_cleanup_thread(aio_t *aiop)
25747c478bd9Sstevel@tonic-gate {
25757c478bd9Sstevel@tonic-gate 	proc_t *p = curproc;
25767c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
25777c478bd9Sstevel@tonic-gate 	int poked = 0;
25787c478bd9Sstevel@tonic-gate 	kcondvar_t *cvp;
25797c478bd9Sstevel@tonic-gate 	int exit_flag = 0;
2580b0b27ce6Spraks 	int rqclnup = 0;
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	sigfillset(&curthread->t_hold);
25837c478bd9Sstevel@tonic-gate 	sigdiffset(&curthread->t_hold, &cantmask);
25847c478bd9Sstevel@tonic-gate 	for (;;) {
25857c478bd9Sstevel@tonic-gate 		/*
25867c478bd9Sstevel@tonic-gate 		 * if a segment is being unmapped, and the current
25877c478bd9Sstevel@tonic-gate 		 * process's done queue is not empty, then every request
25887c478bd9Sstevel@tonic-gate 		 * on the doneq with locked resources should be forced
25897c478bd9Sstevel@tonic-gate 		 * to release their locks. By moving the doneq request
25907c478bd9Sstevel@tonic-gate 		 * to the cleanupq, aio_cleanup() will process the cleanupq,
25917c478bd9Sstevel@tonic-gate 		 * and place requests back onto the doneq. All requests
25927c478bd9Sstevel@tonic-gate 		 * processed by aio_cleanup() will have their physical
25937c478bd9Sstevel@tonic-gate 		 * resources unlocked.
25947c478bd9Sstevel@tonic-gate 		 */
25957c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
25967c478bd9Sstevel@tonic-gate 		if ((aiop->aio_flags & AIO_CLEANUP) == 0) {
25977c478bd9Sstevel@tonic-gate 			aiop->aio_flags |= AIO_CLEANUP;
25987c478bd9Sstevel@tonic-gate 			mutex_enter(&as->a_contents);
2599b0b27ce6Spraks 			if (aiop->aio_rqclnup) {
2600b0b27ce6Spraks 				aiop->aio_rqclnup = 0;
2601b0b27ce6Spraks 				rqclnup = 1;
2602b0b27ce6Spraks 			}
26037c478bd9Sstevel@tonic-gate 			mutex_exit(&as->a_contents);
260416660111SSurya Prakki 			if (aiop->aio_doneq) {
260516660111SSurya Prakki 				aio_req_t *doneqhead = aiop->aio_doneq;
26067c478bd9Sstevel@tonic-gate 				aiop->aio_doneq = NULL;
26077c478bd9Sstevel@tonic-gate 				aio_cleanupq_concat(aiop, doneqhead, AIO_DONEQ);
26087c478bd9Sstevel@tonic-gate 			}
26097c478bd9Sstevel@tonic-gate 		}
26107c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
26117c478bd9Sstevel@tonic-gate 		aio_cleanup(AIO_CLEANUP_THREAD);
26127c478bd9Sstevel@tonic-gate 		/*
26137c478bd9Sstevel@tonic-gate 		 * thread should block on the cleanupcv while
26147c478bd9Sstevel@tonic-gate 		 * AIO_CLEANUP is set.
26157c478bd9Sstevel@tonic-gate 		 */
26167c478bd9Sstevel@tonic-gate 		cvp = &aiop->aio_cleanupcv;
26177c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 		if (aiop->aio_pollq != NULL || aiop->aio_cleanupq != NULL ||
26207c478bd9Sstevel@tonic-gate 		    aiop->aio_notifyq != NULL ||
26217c478bd9Sstevel@tonic-gate 		    aiop->aio_portcleanupq != NULL) {
26227c478bd9Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
26237c478bd9Sstevel@tonic-gate 			continue;
26247c478bd9Sstevel@tonic-gate 		}
26257c478bd9Sstevel@tonic-gate 		mutex_enter(&as->a_contents);
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 		/*
26287c478bd9Sstevel@tonic-gate 		 * AIO_CLEANUP determines when the cleanup thread
2629b0b27ce6Spraks 		 * should be active. This flag is set when
2630b0b27ce6Spraks 		 * the cleanup thread is awakened by as_unmap() or
2631b0b27ce6Spraks 		 * due to DR operations.
26327c478bd9Sstevel@tonic-gate 		 * The flag is cleared when the blocking as_unmap()
26337c478bd9Sstevel@tonic-gate 		 * that originally awakened us is allowed to
26347c478bd9Sstevel@tonic-gate 		 * complete. as_unmap() blocks when trying to
26357c478bd9Sstevel@tonic-gate 		 * unmap a segment that has SOFTLOCKed pages. when
26367c478bd9Sstevel@tonic-gate 		 * the segment's pages are all SOFTUNLOCKed,
2637b0b27ce6Spraks 		 * as->a_flags & AS_UNMAPWAIT should be zero.
2638b0b27ce6Spraks 		 *
2639b0b27ce6Spraks 		 * In case of cleanup request by DR, the flag is cleared
2640b0b27ce6Spraks 		 * once all the pending aio requests have been processed.
2641b0b27ce6Spraks 		 *
2642b0b27ce6Spraks 		 * The flag shouldn't be cleared right away if the
2643b0b27ce6Spraks 		 * cleanup thread was interrupted because the process
2644b0b27ce6Spraks 		 * is doing forkall(). This happens when cv_wait_sig()
2645b0b27ce6Spraks 		 * returns zero, because it was awakened by a pokelwps().
2646b0b27ce6Spraks 		 * If the process is not exiting, it must be doing forkall().
26477c478bd9Sstevel@tonic-gate 		 */
26487c478bd9Sstevel@tonic-gate 		if ((poked == 0) &&
2649b0b27ce6Spraks 		    ((!rqclnup && (AS_ISUNMAPWAIT(as) == 0)) ||
2650b0b27ce6Spraks 		    (aiop->aio_pending == 0))) {
26517c478bd9Sstevel@tonic-gate 			aiop->aio_flags &= ~(AIO_CLEANUP | AIO_CLEANUP_PORT);
26527c478bd9Sstevel@tonic-gate 			cvp = &as->a_cv;
2653b0b27ce6Spraks 			rqclnup = 0;
26547c478bd9Sstevel@tonic-gate 		}
26557c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
26567c478bd9Sstevel@tonic-gate 		if (poked) {
26577c478bd9Sstevel@tonic-gate 			/*
26587c478bd9Sstevel@tonic-gate 			 * If the process is exiting/killed, don't return
26597c478bd9Sstevel@tonic-gate 			 * immediately without waiting for pending I/O's
26607c478bd9Sstevel@tonic-gate 			 * and releasing the page locks.
26617c478bd9Sstevel@tonic-gate 			 */
26627c478bd9Sstevel@tonic-gate 			if (p->p_flag & (SEXITLWPS|SKILLED)) {
26637c478bd9Sstevel@tonic-gate 				/*
26647c478bd9Sstevel@tonic-gate 				 * If exit_flag is set, then it is
26657c478bd9Sstevel@tonic-gate 				 * safe to exit because we have released
26667c478bd9Sstevel@tonic-gate 				 * page locks of completed I/O's.
26677c478bd9Sstevel@tonic-gate 				 */
26687c478bd9Sstevel@tonic-gate 				if (exit_flag)
26697c478bd9Sstevel@tonic-gate 					break;
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 				mutex_exit(&as->a_contents);
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate 				/*
26747c478bd9Sstevel@tonic-gate 				 * Wait for all the pending aio to complete.
26757c478bd9Sstevel@tonic-gate 				 */
26767c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
26777c478bd9Sstevel@tonic-gate 				aiop->aio_flags |= AIO_REQ_BLOCK;
26787c478bd9Sstevel@tonic-gate 				while (aiop->aio_pending != 0)
26797c478bd9Sstevel@tonic-gate 					cv_wait(&aiop->aio_cleanupcv,
26807c478bd9Sstevel@tonic-gate 					    &aiop->aio_mutex);
26817c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
26827c478bd9Sstevel@tonic-gate 				exit_flag = 1;
26837c478bd9Sstevel@tonic-gate 				continue;
26847c478bd9Sstevel@tonic-gate 			} else if (p->p_flag &
26857c478bd9Sstevel@tonic-gate 			    (SHOLDFORK|SHOLDFORK1|SHOLDWATCH)) {
26867c478bd9Sstevel@tonic-gate 				/*
26877c478bd9Sstevel@tonic-gate 				 * hold LWP until it
26887c478bd9Sstevel@tonic-gate 				 * is continued.
26897c478bd9Sstevel@tonic-gate 				 */
26907c478bd9Sstevel@tonic-gate 				mutex_exit(&as->a_contents);
26917c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
26927c478bd9Sstevel@tonic-gate 				stop(PR_SUSPENDED, SUSPEND_NORMAL);
26937c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
26947c478bd9Sstevel@tonic-gate 				poked = 0;
26957c478bd9Sstevel@tonic-gate 				continue;
26967c478bd9Sstevel@tonic-gate 			}
26977c478bd9Sstevel@tonic-gate 		} else {
26987c478bd9Sstevel@tonic-gate 			/*
26997c478bd9Sstevel@tonic-gate 			 * When started this thread will sleep on as->a_cv.
27007c478bd9Sstevel@tonic-gate 			 * as_unmap will awake this thread if the
27017c478bd9Sstevel@tonic-gate 			 * segment has SOFTLOCKed pages (poked = 0).
27027c478bd9Sstevel@tonic-gate 			 * 1. pokelwps() awakes this thread =>
27037c478bd9Sstevel@tonic-gate 			 *    break the loop to check SEXITLWPS, SHOLDFORK, etc
27047c478bd9Sstevel@tonic-gate 			 * 2. as_unmap awakes this thread =>
27057c478bd9Sstevel@tonic-gate 			 *    to break the loop it is necessary that
27067c478bd9Sstevel@tonic-gate 			 *    - AS_UNMAPWAIT is set (as_unmap is waiting for
27077c478bd9Sstevel@tonic-gate 			 *	memory to be unlocked)
27087c478bd9Sstevel@tonic-gate 			 *    - AIO_CLEANUP is not set
27097c478bd9Sstevel@tonic-gate 			 *	(if AIO_CLEANUP is set we have to wait for
27107c478bd9Sstevel@tonic-gate 			 *	pending requests. aio_done will send a signal
27117c478bd9Sstevel@tonic-gate 			 *	for every request which completes to continue
27127c478bd9Sstevel@tonic-gate 			 *	unmapping the corresponding address range)
2713b0b27ce6Spraks 			 * 3. A cleanup request will wake this thread up, ex.
2714b0b27ce6Spraks 			 *    by the DR operations. The aio_rqclnup flag will
2715b0b27ce6Spraks 			 *    be set.
27167c478bd9Sstevel@tonic-gate 			 */
27177c478bd9Sstevel@tonic-gate 			while (poked == 0) {
2718b0b27ce6Spraks 				/*
2719fa7f62f0Ssp92102 				 * The clean up requests that came in
2720fa7f62f0Ssp92102 				 * after we had just cleaned up, couldn't
2721fa7f62f0Ssp92102 				 * be causing the unmap thread to block - as
2722fa7f62f0Ssp92102 				 * unmap event happened first.
2723fa7f62f0Ssp92102 				 * Let aio_done() wake us up if it sees a need.
2724b0b27ce6Spraks 				 */
2725fa7f62f0Ssp92102 				if (aiop->aio_rqclnup &&
2726b0b27ce6Spraks 				    (aiop->aio_flags & AIO_CLEANUP) == 0)
27277c478bd9Sstevel@tonic-gate 					break;
27287c478bd9Sstevel@tonic-gate 				poked = !cv_wait_sig(cvp, &as->a_contents);
27297c478bd9Sstevel@tonic-gate 				if (AS_ISUNMAPWAIT(as) == 0)
27307c478bd9Sstevel@tonic-gate 					cv_signal(cvp);
27317c478bd9Sstevel@tonic-gate 				if (aiop->aio_outstanding != 0)
27327c478bd9Sstevel@tonic-gate 					break;
27337c478bd9Sstevel@tonic-gate 			}
27347c478bd9Sstevel@tonic-gate 		}
27357c478bd9Sstevel@tonic-gate 		mutex_exit(&as->a_contents);
27367c478bd9Sstevel@tonic-gate 	}
27377c478bd9Sstevel@tonic-gate exit:
27387c478bd9Sstevel@tonic-gate 	mutex_exit(&as->a_contents);
27397c478bd9Sstevel@tonic-gate 	ASSERT((curproc->p_flag & (SEXITLWPS|SKILLED)));
27407c478bd9Sstevel@tonic-gate 	aston(curthread);	/* make thread do post_syscall */
27417c478bd9Sstevel@tonic-gate 	return (0);
27427c478bd9Sstevel@tonic-gate }
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate /*
27457c478bd9Sstevel@tonic-gate  * save a reference to a user's outstanding aio in a hash list.
27467c478bd9Sstevel@tonic-gate  */
27477c478bd9Sstevel@tonic-gate static int
aio_hash_insert(aio_req_t * aio_reqp,aio_t * aiop)27487c478bd9Sstevel@tonic-gate aio_hash_insert(
27497c478bd9Sstevel@tonic-gate 	aio_req_t *aio_reqp,
27507c478bd9Sstevel@tonic-gate 	aio_t *aiop)
27517c478bd9Sstevel@tonic-gate {
27527c478bd9Sstevel@tonic-gate 	long index;
27537c478bd9Sstevel@tonic-gate 	aio_result_t *resultp = aio_reqp->aio_req_resultp;
27547c478bd9Sstevel@tonic-gate 	aio_req_t *current;
27557c478bd9Sstevel@tonic-gate 	aio_req_t **nextp;
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate 	index = AIO_HASH(resultp);
27587c478bd9Sstevel@tonic-gate 	nextp = &aiop->aio_hash[index];
27597c478bd9Sstevel@tonic-gate 	while ((current = *nextp) != NULL) {
27607c478bd9Sstevel@tonic-gate 		if (current->aio_req_resultp == resultp)
27617c478bd9Sstevel@tonic-gate 			return (DUPLICATE);
27627c478bd9Sstevel@tonic-gate 		nextp = &current->aio_hash_next;
27637c478bd9Sstevel@tonic-gate 	}
27647c478bd9Sstevel@tonic-gate 	*nextp = aio_reqp;
27657c478bd9Sstevel@tonic-gate 	aio_reqp->aio_hash_next = NULL;
27667c478bd9Sstevel@tonic-gate 	return (0);
27677c478bd9Sstevel@tonic-gate }
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate static int
check_vp(struct vnode * vp,int mode)27707c478bd9Sstevel@tonic-gate (*check_vp(struct vnode *vp, int mode))(vnode_t *, struct aio_req *,
27717c478bd9Sstevel@tonic-gate     cred_t *)
27727c478bd9Sstevel@tonic-gate {
27737c478bd9Sstevel@tonic-gate 	struct snode *sp;
27747c478bd9Sstevel@tonic-gate 	dev_t		dev;
27757c478bd9Sstevel@tonic-gate 	struct cb_ops  	*cb;
27767c478bd9Sstevel@tonic-gate 	major_t		major;
27777c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
27787c478bd9Sstevel@tonic-gate 
27797c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
27807c478bd9Sstevel@tonic-gate 	major = getmajor(dev);
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate 	/*
27837c478bd9Sstevel@tonic-gate 	 * return NULL for requests to files and STREAMs so
27847c478bd9Sstevel@tonic-gate 	 * that libaio takes care of them.
27857c478bd9Sstevel@tonic-gate 	 */
27867c478bd9Sstevel@tonic-gate 	if (vp->v_type == VCHR) {
27877c478bd9Sstevel@tonic-gate 		/* no stream device for kaio */
27887c478bd9Sstevel@tonic-gate 		if (STREAMSTAB(major)) {
27897c478bd9Sstevel@tonic-gate 			return (NULL);
27907c478bd9Sstevel@tonic-gate 		}
27917c478bd9Sstevel@tonic-gate 	} else {
27927c478bd9Sstevel@tonic-gate 		return (NULL);
27937c478bd9Sstevel@tonic-gate 	}
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 	/*
27967c478bd9Sstevel@tonic-gate 	 * Check old drivers which do not have async I/O entry points.
27977c478bd9Sstevel@tonic-gate 	 */
27987c478bd9Sstevel@tonic-gate 	if (devopsp[major]->devo_rev < 3)
27997c478bd9Sstevel@tonic-gate 		return (NULL);
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	cb = devopsp[major]->devo_cb_ops;
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 	if (cb->cb_rev < 1)
28047c478bd9Sstevel@tonic-gate 		return (NULL);
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 	/*
28077c478bd9Sstevel@tonic-gate 	 * Check whether this device is a block device.
28087c478bd9Sstevel@tonic-gate 	 * Kaio is not supported for devices like tty.
28097c478bd9Sstevel@tonic-gate 	 */
28107c478bd9Sstevel@tonic-gate 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
28117c478bd9Sstevel@tonic-gate 		return (NULL);
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	/*
28147c478bd9Sstevel@tonic-gate 	 * Clustering: If vnode is a PXFS vnode, then the device may be remote.
28157c478bd9Sstevel@tonic-gate 	 * We cannot call the driver directly. Instead return the
28167c478bd9Sstevel@tonic-gate 	 * PXFS functions.
28177c478bd9Sstevel@tonic-gate 	 */
28187c478bd9Sstevel@tonic-gate 
28197c478bd9Sstevel@tonic-gate 	if (IS_PXFSVP(vp)) {
28207c478bd9Sstevel@tonic-gate 		if (mode & FREAD)
28217c478bd9Sstevel@tonic-gate 			return (clpxfs_aio_read);
28227c478bd9Sstevel@tonic-gate 		else
28237c478bd9Sstevel@tonic-gate 			return (clpxfs_aio_write);
28247c478bd9Sstevel@tonic-gate 	}
28257c478bd9Sstevel@tonic-gate 	if (mode & FREAD)
28267c478bd9Sstevel@tonic-gate 		aio_func = (cb->cb_aread == nodev) ? NULL : driver_aio_read;
28277c478bd9Sstevel@tonic-gate 	else
28287c478bd9Sstevel@tonic-gate 		aio_func = (cb->cb_awrite == nodev) ? NULL : driver_aio_write;
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	/*
28317c478bd9Sstevel@tonic-gate 	 * Do we need this ?
28327c478bd9Sstevel@tonic-gate 	 * nodev returns ENXIO anyway.
28337c478bd9Sstevel@tonic-gate 	 */
28347c478bd9Sstevel@tonic-gate 	if (aio_func == nodev)
28357c478bd9Sstevel@tonic-gate 		return (NULL);
28367c478bd9Sstevel@tonic-gate 
28377c478bd9Sstevel@tonic-gate 	sp = VTOS(vp);
28387c478bd9Sstevel@tonic-gate 	smark(sp, SACC);
28397c478bd9Sstevel@tonic-gate 	return (aio_func);
28407c478bd9Sstevel@tonic-gate }
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate /*
28437c478bd9Sstevel@tonic-gate  * Clustering: We want check_vp to return a function prototyped
28447c478bd9Sstevel@tonic-gate  * correctly that will be common to both PXFS and regular case.
28457c478bd9Sstevel@tonic-gate  * We define this intermediate function that will do the right
28467c478bd9Sstevel@tonic-gate  * thing for driver cases.
28477c478bd9Sstevel@tonic-gate  */
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate static int
driver_aio_write(vnode_t * vp,struct aio_req * aio,cred_t * cred_p)28507c478bd9Sstevel@tonic-gate driver_aio_write(vnode_t *vp, struct aio_req *aio, cred_t *cred_p)
28517c478bd9Sstevel@tonic-gate {
28527c478bd9Sstevel@tonic-gate 	dev_t dev;
28537c478bd9Sstevel@tonic-gate 	struct cb_ops  	*cb;
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VCHR);
28567c478bd9Sstevel@tonic-gate 	ASSERT(!IS_PXFSVP(vp));
28577c478bd9Sstevel@tonic-gate 	dev = VTOS(vp)->s_dev;
28587c478bd9Sstevel@tonic-gate 	ASSERT(STREAMSTAB(getmajor(dev)) == NULL);
28597c478bd9Sstevel@tonic-gate 
28607c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate 	ASSERT(cb->cb_awrite != nodev);
28637c478bd9Sstevel@tonic-gate 	return ((*cb->cb_awrite)(dev, aio, cred_p));
28647c478bd9Sstevel@tonic-gate }
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate /*
28677c478bd9Sstevel@tonic-gate  * Clustering: We want check_vp to return a function prototyped
28687c478bd9Sstevel@tonic-gate  * correctly that will be common to both PXFS and regular case.
28697c478bd9Sstevel@tonic-gate  * We define this intermediate function that will do the right
28707c478bd9Sstevel@tonic-gate  * thing for driver cases.
28717c478bd9Sstevel@tonic-gate  */
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate static int
driver_aio_read(vnode_t * vp,struct aio_req * aio,cred_t * cred_p)28747c478bd9Sstevel@tonic-gate driver_aio_read(vnode_t *vp, struct aio_req *aio, cred_t *cred_p)
28757c478bd9Sstevel@tonic-gate {
28767c478bd9Sstevel@tonic-gate 	dev_t dev;
28777c478bd9Sstevel@tonic-gate 	struct cb_ops  	*cb;
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_type == VCHR);
28807c478bd9Sstevel@tonic-gate 	ASSERT(!IS_PXFSVP(vp));
28817c478bd9Sstevel@tonic-gate 	dev = VTOS(vp)->s_dev;
28827c478bd9Sstevel@tonic-gate 	ASSERT(!STREAMSTAB(getmajor(dev)));
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate 	ASSERT(cb->cb_aread != nodev);
28877c478bd9Sstevel@tonic-gate 	return ((*cb->cb_aread)(dev, aio, cred_p));
28887c478bd9Sstevel@tonic-gate }
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate /*
28917c478bd9Sstevel@tonic-gate  * This routine is called when a largefile call is made by a 32bit
28927c478bd9Sstevel@tonic-gate  * process on a ILP32 or LP64 kernel. All 64bit processes are large
28937c478bd9Sstevel@tonic-gate  * file by definition and will call alio() instead.
28947c478bd9Sstevel@tonic-gate  */
28957c478bd9Sstevel@tonic-gate static int
alioLF(int mode_arg,void * aiocb_arg,int nent,void * sigev)28967c478bd9Sstevel@tonic-gate alioLF(
28977c478bd9Sstevel@tonic-gate 	int		mode_arg,
28987c478bd9Sstevel@tonic-gate 	void		*aiocb_arg,
28997c478bd9Sstevel@tonic-gate 	int		nent,
29007c478bd9Sstevel@tonic-gate 	void		*sigev)
29017c478bd9Sstevel@tonic-gate {
29027c478bd9Sstevel@tonic-gate 	file_t		*fp;
29037c478bd9Sstevel@tonic-gate 	file_t		*prev_fp = NULL;
29047c478bd9Sstevel@tonic-gate 	int		prev_mode = -1;
29057c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
29067c478bd9Sstevel@tonic-gate 	aio_lio_t	*head;
29077c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
29087c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
29097c478bd9Sstevel@tonic-gate 	caddr_t		cbplist;
29107c478bd9Sstevel@tonic-gate 	aiocb64_32_t	cb64;
29117c478bd9Sstevel@tonic-gate 	aiocb64_32_t	*aiocb = &cb64;
291234709573Sraf 	aiocb64_32_t	*cbp;
291334709573Sraf 	caddr32_t	*ucbp;
29147c478bd9Sstevel@tonic-gate #ifdef _LP64
29157c478bd9Sstevel@tonic-gate 	aiocb_t		aiocb_n;
29167c478bd9Sstevel@tonic-gate #endif
29177c478bd9Sstevel@tonic-gate 	struct sigevent32	sigevk;
29187c478bd9Sstevel@tonic-gate 	sigqueue_t	*sqp;
29197c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
29207c478bd9Sstevel@tonic-gate 	int		mode;
292134709573Sraf 	int		error = 0;
292234709573Sraf 	int		aio_errors = 0;
29237c478bd9Sstevel@tonic-gate 	int		i;
29247c478bd9Sstevel@tonic-gate 	size_t		ssize;
29257c478bd9Sstevel@tonic-gate 	int		deadhead = 0;
29267c478bd9Sstevel@tonic-gate 	int		aio_notsupported = 0;
292734709573Sraf 	int		lio_head_port;
292834709573Sraf 	int		aio_port;
292934709573Sraf 	int		aio_thread;
29307c478bd9Sstevel@tonic-gate 	port_kevent_t	*pkevtp = NULL;
293134b3058fSpraks 	int		portused = 0;
29327c478bd9Sstevel@tonic-gate 	port_notify32_t	pnotify;
293334709573Sraf 	int		event;
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
29367c478bd9Sstevel@tonic-gate 	if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX)
29377c478bd9Sstevel@tonic-gate 		return (EINVAL);
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 	ASSERT(get_udatamodel() == DATAMODEL_ILP32);
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate 	ssize = (sizeof (caddr32_t) * nent);
29427c478bd9Sstevel@tonic-gate 	cbplist = kmem_alloc(ssize, KM_SLEEP);
29437c478bd9Sstevel@tonic-gate 	ucbp = (caddr32_t *)cbplist;
29447c478bd9Sstevel@tonic-gate 
294534709573Sraf 	if (copyin(aiocb_arg, cbplist, ssize) ||
294634709573Sraf 	    (sigev && copyin(sigev, &sigevk, sizeof (sigevk)))) {
29477c478bd9Sstevel@tonic-gate 		kmem_free(cbplist, ssize);
29487c478bd9Sstevel@tonic-gate 		return (EFAULT);
29497c478bd9Sstevel@tonic-gate 	}
29507c478bd9Sstevel@tonic-gate 
295134709573Sraf 	/* Event Ports  */
295234709573Sraf 	if (sigev &&
295334709573Sraf 	    (sigevk.sigev_notify == SIGEV_THREAD ||
295434709573Sraf 	    sigevk.sigev_notify == SIGEV_PORT)) {
295534709573Sraf 		if (sigevk.sigev_notify == SIGEV_THREAD) {
295634709573Sraf 			pnotify.portnfy_port = sigevk.sigev_signo;
295734709573Sraf 			pnotify.portnfy_user = sigevk.sigev_value.sival_ptr;
295834709573Sraf 		} else if (copyin(
295934709573Sraf 		    (void *)(uintptr_t)sigevk.sigev_value.sival_ptr,
296034709573Sraf 		    &pnotify, sizeof (pnotify))) {
29617c478bd9Sstevel@tonic-gate 			kmem_free(cbplist, ssize);
29627c478bd9Sstevel@tonic-gate 			return (EFAULT);
29637c478bd9Sstevel@tonic-gate 		}
296434709573Sraf 		error = port_alloc_event(pnotify.portnfy_port,
296534709573Sraf 		    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp);
296634709573Sraf 		if (error) {
296734709573Sraf 			if (error == ENOMEM || error == EAGAIN)
296834709573Sraf 				error = EAGAIN;
296934709573Sraf 			else
297034709573Sraf 				error = EINVAL;
297134709573Sraf 			kmem_free(cbplist, ssize);
297234709573Sraf 			return (error);
297334709573Sraf 		}
297434709573Sraf 		lio_head_port = pnotify.portnfy_port;
297534b3058fSpraks 		portused = 1;
29767c478bd9Sstevel@tonic-gate 	}
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	/*
29797c478bd9Sstevel@tonic-gate 	 * a list head should be allocated if notification is
29807c478bd9Sstevel@tonic-gate 	 * enabled for this list.
29817c478bd9Sstevel@tonic-gate 	 */
29827c478bd9Sstevel@tonic-gate 	head = NULL;
29837c478bd9Sstevel@tonic-gate 
298434709573Sraf 	if (mode_arg == LIO_WAIT || sigev) {
29857c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
29867c478bd9Sstevel@tonic-gate 		error = aio_lio_alloc(&head);
29877c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
29887c478bd9Sstevel@tonic-gate 		if (error)
29897c478bd9Sstevel@tonic-gate 			goto done;
29907c478bd9Sstevel@tonic-gate 		deadhead = 1;
29917c478bd9Sstevel@tonic-gate 		head->lio_nent = nent;
29927c478bd9Sstevel@tonic-gate 		head->lio_refcnt = nent;
299334709573Sraf 		head->lio_port = -1;
299434709573Sraf 		head->lio_portkev = NULL;
299534709573Sraf 		if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL &&
299634709573Sraf 		    sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) {
29977c478bd9Sstevel@tonic-gate 			sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP);
29987c478bd9Sstevel@tonic-gate 			if (sqp == NULL) {
29997c478bd9Sstevel@tonic-gate 				error = EAGAIN;
30007c478bd9Sstevel@tonic-gate 				goto done;
30017c478bd9Sstevel@tonic-gate 			}
30027c478bd9Sstevel@tonic-gate 			sqp->sq_func = NULL;
30037c478bd9Sstevel@tonic-gate 			sqp->sq_next = NULL;
30047c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_code = SI_ASYNCIO;
30057c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_pid = curproc->p_pid;
30067c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_ctid = PRCTID(curproc);
30077c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_zoneid = getzoneid();
30087c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_uid = crgetuid(curproc->p_cred);
30097c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_signo = sigevk.sigev_signo;
30107c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_value.sival_int =
30117c478bd9Sstevel@tonic-gate 			    sigevk.sigev_value.sival_int;
30127c478bd9Sstevel@tonic-gate 			head->lio_sigqp = sqp;
30137c478bd9Sstevel@tonic-gate 		} else {
30147c478bd9Sstevel@tonic-gate 			head->lio_sigqp = NULL;
30157c478bd9Sstevel@tonic-gate 		}
301634709573Sraf 		if (pkevtp) {
301734709573Sraf 			/*
301834709573Sraf 			 * Prepare data to send when list of aiocb's
301934709573Sraf 			 * has completed.
302034709573Sraf 			 */
302134709573Sraf 			port_init_event(pkevtp, (uintptr_t)sigev,
302234709573Sraf 			    (void *)(uintptr_t)pnotify.portnfy_user,
302334709573Sraf 			    NULL, head);
302434709573Sraf 			pkevtp->portkev_events = AIOLIO64;
302534709573Sraf 			head->lio_portkev = pkevtp;
302634709573Sraf 			head->lio_port = pnotify.portnfy_port;
302734709573Sraf 		}
30287c478bd9Sstevel@tonic-gate 	}
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate 	for (i = 0; i < nent; i++, ucbp++) {
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate 		cbp = (aiocb64_32_t *)(uintptr_t)*ucbp;
30337c478bd9Sstevel@tonic-gate 		/* skip entry if it can't be copied. */
303434709573Sraf 		if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb))) {
30357c478bd9Sstevel@tonic-gate 			if (head) {
30367c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
30377c478bd9Sstevel@tonic-gate 				head->lio_nent--;
30387c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
30397c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
30407c478bd9Sstevel@tonic-gate 			}
30417c478bd9Sstevel@tonic-gate 			continue;
30427c478bd9Sstevel@tonic-gate 		}
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 		/* skip if opcode for aiocb is LIO_NOP */
30457c478bd9Sstevel@tonic-gate 		mode = aiocb->aio_lio_opcode;
30467c478bd9Sstevel@tonic-gate 		if (mode == LIO_NOP) {
30477c478bd9Sstevel@tonic-gate 			cbp = NULL;
30487c478bd9Sstevel@tonic-gate 			if (head) {
30497c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
30507c478bd9Sstevel@tonic-gate 				head->lio_nent--;
30517c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
30527c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
30537c478bd9Sstevel@tonic-gate 			}
30547c478bd9Sstevel@tonic-gate 			continue;
30557c478bd9Sstevel@tonic-gate 		}
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate 		/* increment file descriptor's ref count. */
30587c478bd9Sstevel@tonic-gate 		if ((fp = getf(aiocb->aio_fildes)) == NULL) {
30597c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
30607c478bd9Sstevel@tonic-gate 			if (head) {
30617c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
30627c478bd9Sstevel@tonic-gate 				head->lio_nent--;
30637c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
30647c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
30657c478bd9Sstevel@tonic-gate 			}
30667c478bd9Sstevel@tonic-gate 			aio_errors++;
30677c478bd9Sstevel@tonic-gate 			continue;
30687c478bd9Sstevel@tonic-gate 		}
30697c478bd9Sstevel@tonic-gate 
30707c478bd9Sstevel@tonic-gate 		/*
30717c478bd9Sstevel@tonic-gate 		 * check the permission of the partition
30727c478bd9Sstevel@tonic-gate 		 */
30737c478bd9Sstevel@tonic-gate 		if ((fp->f_flag & mode) == 0) {
30747c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
30757c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
30767c478bd9Sstevel@tonic-gate 			if (head) {
30777c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
30787c478bd9Sstevel@tonic-gate 				head->lio_nent--;
30797c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
30807c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
30817c478bd9Sstevel@tonic-gate 			}
30827c478bd9Sstevel@tonic-gate 			aio_errors++;
30837c478bd9Sstevel@tonic-gate 			continue;
30847c478bd9Sstevel@tonic-gate 		}
30857c478bd9Sstevel@tonic-gate 
30867c478bd9Sstevel@tonic-gate 		/*
30877c478bd9Sstevel@tonic-gate 		 * common case where requests are to the same fd
30887c478bd9Sstevel@tonic-gate 		 * for the same r/w operation
30897c478bd9Sstevel@tonic-gate 		 * for UFS, need to set EBADFD
30907c478bd9Sstevel@tonic-gate 		 */
309134709573Sraf 		vp = fp->f_vnode;
309234709573Sraf 		if (fp != prev_fp || mode != prev_mode) {
30937c478bd9Sstevel@tonic-gate 			aio_func = check_vp(vp, mode);
30947c478bd9Sstevel@tonic-gate 			if (aio_func == NULL) {
30957c478bd9Sstevel@tonic-gate 				prev_fp = NULL;
30967c478bd9Sstevel@tonic-gate 				releasef(aiocb->aio_fildes);
30977c478bd9Sstevel@tonic-gate 				lio_set_uerror(&cbp->aio_resultp, EBADFD);
30987c478bd9Sstevel@tonic-gate 				aio_notsupported++;
30997c478bd9Sstevel@tonic-gate 				if (head) {
31007c478bd9Sstevel@tonic-gate 					mutex_enter(&aiop->aio_mutex);
31017c478bd9Sstevel@tonic-gate 					head->lio_nent--;
31027c478bd9Sstevel@tonic-gate 					head->lio_refcnt--;
31037c478bd9Sstevel@tonic-gate 					mutex_exit(&aiop->aio_mutex);
31047c478bd9Sstevel@tonic-gate 				}
31057c478bd9Sstevel@tonic-gate 				continue;
31067c478bd9Sstevel@tonic-gate 			} else {
31077c478bd9Sstevel@tonic-gate 				prev_fp = fp;
31087c478bd9Sstevel@tonic-gate 				prev_mode = mode;
31097c478bd9Sstevel@tonic-gate 			}
31107c478bd9Sstevel@tonic-gate 		}
311134709573Sraf 
31127c478bd9Sstevel@tonic-gate #ifdef	_LP64
31137c478bd9Sstevel@tonic-gate 		aiocb_LFton(aiocb, &aiocb_n);
31147c478bd9Sstevel@tonic-gate 		error = aio_req_setup(&reqp, aiop, &aiocb_n,
3115*d2749ac6SRoger A. Faulkner 		    (aio_result_t *)&cbp->aio_resultp, vp, 0);
31167c478bd9Sstevel@tonic-gate #else
31177c478bd9Sstevel@tonic-gate 		error = aio_req_setupLF(&reqp, aiop, aiocb,
3118*d2749ac6SRoger A. Faulkner 		    (aio_result_t *)&cbp->aio_resultp, vp, 0);
31197c478bd9Sstevel@tonic-gate #endif  /* _LP64 */
31207c478bd9Sstevel@tonic-gate 		if (error) {
31217c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
312234709573Sraf 			lio_set_uerror(&cbp->aio_resultp, error);
31237c478bd9Sstevel@tonic-gate 			if (head) {
31247c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
31257c478bd9Sstevel@tonic-gate 				head->lio_nent--;
31267c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
31277c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
31287c478bd9Sstevel@tonic-gate 			}
31297c478bd9Sstevel@tonic-gate 			aio_errors++;
31307c478bd9Sstevel@tonic-gate 			continue;
31317c478bd9Sstevel@tonic-gate 		}
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 		reqp->aio_req_lio = head;
31347c478bd9Sstevel@tonic-gate 		deadhead = 0;
31357c478bd9Sstevel@tonic-gate 
31367c478bd9Sstevel@tonic-gate 		/*
31377c478bd9Sstevel@tonic-gate 		 * Set the errno field now before sending the request to
31387c478bd9Sstevel@tonic-gate 		 * the driver to avoid a race condition
31397c478bd9Sstevel@tonic-gate 		 */
31407c478bd9Sstevel@tonic-gate 		(void) suword32(&cbp->aio_resultp.aio_errno,
31417c478bd9Sstevel@tonic-gate 		    EINPROGRESS);
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 		reqp->aio_req_iocb.iocb32 = *ucbp;
31447c478bd9Sstevel@tonic-gate 
314534709573Sraf 		event = (mode == LIO_READ)? AIOAREAD64 : AIOAWRITE64;
314634709573Sraf 		aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT);
314734709573Sraf 		aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD);
314834709573Sraf 		if (aio_port | aio_thread) {
314934709573Sraf 			port_kevent_t *lpkevp;
315034709573Sraf 			/*
315134709573Sraf 			 * Prepare data to send with each aiocb completed.
315234709573Sraf 			 */
315334709573Sraf 			if (aio_port) {
315434709573Sraf 				void *paddr = (void *)(uintptr_t)
315534709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
315634709573Sraf 				if (copyin(paddr, &pnotify, sizeof (pnotify)))
315734709573Sraf 					error = EFAULT;
315834709573Sraf 			} else {	/* aio_thread */
315934709573Sraf 				pnotify.portnfy_port =
316034709573Sraf 				    aiocb->aio_sigevent.sigev_signo;
316134709573Sraf 				pnotify.portnfy_user =
316234709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
316334709573Sraf 			}
316434709573Sraf 			if (error)
316534709573Sraf 				/* EMPTY */;
316634709573Sraf 			else if (pkevtp != NULL &&
316734709573Sraf 			    pnotify.portnfy_port == lio_head_port)
316834709573Sraf 				error = port_dup_event(pkevtp, &lpkevp,
316934709573Sraf 				    PORT_ALLOC_DEFAULT);
317034709573Sraf 			else
317134709573Sraf 				error = port_alloc_event(pnotify.portnfy_port,
317234709573Sraf 				    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO,
317334709573Sraf 				    &lpkevp);
317434709573Sraf 			if (error == 0) {
317534709573Sraf 				port_init_event(lpkevp, (uintptr_t)*ucbp,
31767c478bd9Sstevel@tonic-gate 				    (void *)(uintptr_t)pnotify.portnfy_user,
317734709573Sraf 				    aio_port_callback, reqp);
317834709573Sraf 				lpkevp->portkev_events = event;
317934709573Sraf 				reqp->aio_req_portkev = lpkevp;
318034709573Sraf 				reqp->aio_req_port = pnotify.portnfy_port;
318134709573Sraf 			}
31827c478bd9Sstevel@tonic-gate 		}
31837c478bd9Sstevel@tonic-gate 
31847c478bd9Sstevel@tonic-gate 		/*
31857c478bd9Sstevel@tonic-gate 		 * send the request to driver.
31867c478bd9Sstevel@tonic-gate 		 */
31877c478bd9Sstevel@tonic-gate 		if (error == 0) {
31887c478bd9Sstevel@tonic-gate 			if (aiocb->aio_nbytes == 0) {
31897c478bd9Sstevel@tonic-gate 				clear_active_fd(aiocb->aio_fildes);
31907c478bd9Sstevel@tonic-gate 				aio_zerolen(reqp);
31917c478bd9Sstevel@tonic-gate 				continue;
31927c478bd9Sstevel@tonic-gate 			}
31937c478bd9Sstevel@tonic-gate 			error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req,
31947c478bd9Sstevel@tonic-gate 			    CRED());
31957c478bd9Sstevel@tonic-gate 		}
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 		/*
31987c478bd9Sstevel@tonic-gate 		 * the fd's ref count is not decremented until the IO has
31997c478bd9Sstevel@tonic-gate 		 * completed unless there was an error.
32007c478bd9Sstevel@tonic-gate 		 */
32017c478bd9Sstevel@tonic-gate 		if (error) {
32027c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
32037c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, error);
32047c478bd9Sstevel@tonic-gate 			if (head) {
32057c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
32067c478bd9Sstevel@tonic-gate 				head->lio_nent--;
32077c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
32087c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
32097c478bd9Sstevel@tonic-gate 			}
32107c478bd9Sstevel@tonic-gate 			if (error == ENOTSUP)
32117c478bd9Sstevel@tonic-gate 				aio_notsupported++;
32127c478bd9Sstevel@tonic-gate 			else
32137c478bd9Sstevel@tonic-gate 				aio_errors++;
321434b3058fSpraks 			lio_set_error(reqp, portused);
32157c478bd9Sstevel@tonic-gate 		} else {
32167c478bd9Sstevel@tonic-gate 			clear_active_fd(aiocb->aio_fildes);
32177c478bd9Sstevel@tonic-gate 		}
32187c478bd9Sstevel@tonic-gate 	}
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	if (aio_notsupported) {
32217c478bd9Sstevel@tonic-gate 		error = ENOTSUP;
32227c478bd9Sstevel@tonic-gate 	} else if (aio_errors) {
32237c478bd9Sstevel@tonic-gate 		/*
32247c478bd9Sstevel@tonic-gate 		 * return EIO if any request failed
32257c478bd9Sstevel@tonic-gate 		 */
32267c478bd9Sstevel@tonic-gate 		error = EIO;
32277c478bd9Sstevel@tonic-gate 	}
32287c478bd9Sstevel@tonic-gate 
32297c478bd9Sstevel@tonic-gate 	if (mode_arg == LIO_WAIT) {
32307c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
32317c478bd9Sstevel@tonic-gate 		while (head->lio_refcnt > 0) {
32327c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) {
32337c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
32347c478bd9Sstevel@tonic-gate 				error = EINTR;
32357c478bd9Sstevel@tonic-gate 				goto done;
32367c478bd9Sstevel@tonic-gate 			}
32377c478bd9Sstevel@tonic-gate 		}
32387c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
32397c478bd9Sstevel@tonic-gate 		alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_LARGEFILE);
32407c478bd9Sstevel@tonic-gate 	}
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate done:
32437c478bd9Sstevel@tonic-gate 	kmem_free(cbplist, ssize);
32447c478bd9Sstevel@tonic-gate 	if (deadhead) {
32457c478bd9Sstevel@tonic-gate 		if (head->lio_sigqp)
32467c478bd9Sstevel@tonic-gate 			kmem_free(head->lio_sigqp, sizeof (sigqueue_t));
324734709573Sraf 		if (head->lio_portkev)
324834709573Sraf 			port_free_event(head->lio_portkev);
32497c478bd9Sstevel@tonic-gate 		kmem_free(head, sizeof (aio_lio_t));
32507c478bd9Sstevel@tonic-gate 	}
32517c478bd9Sstevel@tonic-gate 	return (error);
32527c478bd9Sstevel@tonic-gate }
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
32557c478bd9Sstevel@tonic-gate static void
aiocb_LFton(aiocb64_32_t * src,aiocb_t * dest)32567c478bd9Sstevel@tonic-gate aiocb_LFton(aiocb64_32_t *src, aiocb_t *dest)
32577c478bd9Sstevel@tonic-gate {
32587c478bd9Sstevel@tonic-gate 	dest->aio_fildes = src->aio_fildes;
32597c478bd9Sstevel@tonic-gate 	dest->aio_buf = (void *)(uintptr_t)src->aio_buf;
32607c478bd9Sstevel@tonic-gate 	dest->aio_nbytes = (size_t)src->aio_nbytes;
32617c478bd9Sstevel@tonic-gate 	dest->aio_offset = (off_t)src->aio_offset;
32627c478bd9Sstevel@tonic-gate 	dest->aio_reqprio = src->aio_reqprio;
32637c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify = src->aio_sigevent.sigev_notify;
32647c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_signo = src->aio_sigevent.sigev_signo;
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate 	/*
32677c478bd9Sstevel@tonic-gate 	 * See comment in sigqueue32() on handling of 32-bit
32687c478bd9Sstevel@tonic-gate 	 * sigvals in a 64-bit kernel.
32697c478bd9Sstevel@tonic-gate 	 */
32707c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_value.sival_int =
32717c478bd9Sstevel@tonic-gate 	    (int)src->aio_sigevent.sigev_value.sival_int;
32727c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify_function = (void (*)(union sigval))
32737c478bd9Sstevel@tonic-gate 	    (uintptr_t)src->aio_sigevent.sigev_notify_function;
32747c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify_attributes = (pthread_attr_t *)
32757c478bd9Sstevel@tonic-gate 	    (uintptr_t)src->aio_sigevent.sigev_notify_attributes;
32767c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.__sigev_pad2 = src->aio_sigevent.__sigev_pad2;
32777c478bd9Sstevel@tonic-gate 	dest->aio_lio_opcode = src->aio_lio_opcode;
32787c478bd9Sstevel@tonic-gate 	dest->aio_state = src->aio_state;
32797c478bd9Sstevel@tonic-gate 	dest->aio__pad[0] = src->aio__pad[0];
32807c478bd9Sstevel@tonic-gate }
32817c478bd9Sstevel@tonic-gate #endif
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate /*
32847c478bd9Sstevel@tonic-gate  * This function is used only for largefile calls made by
328534709573Sraf  * 32 bit applications.
32867c478bd9Sstevel@tonic-gate  */
32877c478bd9Sstevel@tonic-gate static int
aio_req_setupLF(aio_req_t ** reqpp,aio_t * aiop,aiocb64_32_t * arg,aio_result_t * resultp,vnode_t * vp,int old_solaris_req)32887c478bd9Sstevel@tonic-gate aio_req_setupLF(
32897c478bd9Sstevel@tonic-gate 	aio_req_t	**reqpp,
32907c478bd9Sstevel@tonic-gate 	aio_t		*aiop,
32917c478bd9Sstevel@tonic-gate 	aiocb64_32_t	*arg,
32927c478bd9Sstevel@tonic-gate 	aio_result_t	*resultp,
3293*d2749ac6SRoger A. Faulkner 	vnode_t		*vp,
3294*d2749ac6SRoger A. Faulkner 	int		old_solaris_req)
32957c478bd9Sstevel@tonic-gate {
329634709573Sraf 	sigqueue_t	*sqp = NULL;
32977c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
32987c478bd9Sstevel@tonic-gate 	struct uio	*uio;
329934709573Sraf 	struct sigevent32 *sigev;
33007c478bd9Sstevel@tonic-gate 	int 		error;
33017c478bd9Sstevel@tonic-gate 
330234709573Sraf 	sigev = &arg->aio_sigevent;
330334709573Sraf 	if (sigev->sigev_notify == SIGEV_SIGNAL &&
330434709573Sraf 	    sigev->sigev_signo > 0 && sigev->sigev_signo < NSIG) {
33057c478bd9Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP);
33067c478bd9Sstevel@tonic-gate 		if (sqp == NULL)
33077c478bd9Sstevel@tonic-gate 			return (EAGAIN);
33087c478bd9Sstevel@tonic-gate 		sqp->sq_func = NULL;
33097c478bd9Sstevel@tonic-gate 		sqp->sq_next = NULL;
33107c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_code = SI_ASYNCIO;
33117c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_pid = curproc->p_pid;
33127c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_ctid = PRCTID(curproc);
33137c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_zoneid = getzoneid();
33147c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_uid = crgetuid(curproc->p_cred);
33157c478bd9Sstevel@tonic-gate 		sqp->sq_info.si_signo = sigev->sigev_signo;
331634709573Sraf 		sqp->sq_info.si_value.sival_int = sigev->sigev_value.sival_int;
331734709573Sraf 	}
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_REQ_BLOCK) {
33227c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
33237c478bd9Sstevel@tonic-gate 		if (sqp)
33247c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
33257c478bd9Sstevel@tonic-gate 		return (EIO);
33267c478bd9Sstevel@tonic-gate 	}
33277c478bd9Sstevel@tonic-gate 	/*
33287c478bd9Sstevel@tonic-gate 	 * get an aio_reqp from the free list or allocate one
33297c478bd9Sstevel@tonic-gate 	 * from dynamic memory.
33307c478bd9Sstevel@tonic-gate 	 */
33317c478bd9Sstevel@tonic-gate 	if (error = aio_req_alloc(&reqp, resultp)) {
33327c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
33337c478bd9Sstevel@tonic-gate 		if (sqp)
33347c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
33357c478bd9Sstevel@tonic-gate 		return (error);
33367c478bd9Sstevel@tonic-gate 	}
33377c478bd9Sstevel@tonic-gate 	aiop->aio_pending++;
33387c478bd9Sstevel@tonic-gate 	aiop->aio_outstanding++;
33397c478bd9Sstevel@tonic-gate 	reqp->aio_req_flags = AIO_PENDING;
3340*d2749ac6SRoger A. Faulkner 	if (old_solaris_req) {
3341*d2749ac6SRoger A. Faulkner 		/* this is an old solaris aio request */
3342*d2749ac6SRoger A. Faulkner 		reqp->aio_req_flags |= AIO_SOLARIS;
3343*d2749ac6SRoger A. Faulkner 		aiop->aio_flags |= AIO_SOLARIS_REQ;
3344*d2749ac6SRoger A. Faulkner 	}
334534709573Sraf 	if (sigev->sigev_notify == SIGEV_THREAD ||
334634709573Sraf 	    sigev->sigev_notify == SIGEV_PORT)
334734709573Sraf 		aio_enq(&aiop->aio_portpending, reqp, 0);
33487c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
33497c478bd9Sstevel@tonic-gate 	/*
33507c478bd9Sstevel@tonic-gate 	 * initialize aio request.
33517c478bd9Sstevel@tonic-gate 	 */
33527c478bd9Sstevel@tonic-gate 	reqp->aio_req_fd = arg->aio_fildes;
33537c478bd9Sstevel@tonic-gate 	reqp->aio_req_sigqp = sqp;
33547c478bd9Sstevel@tonic-gate 	reqp->aio_req_iocb.iocb = NULL;
335534709573Sraf 	reqp->aio_req_lio = NULL;
33567c478bd9Sstevel@tonic-gate 	reqp->aio_req_buf.b_file = vp;
33577c478bd9Sstevel@tonic-gate 	uio = reqp->aio_req.aio_uio;
33587c478bd9Sstevel@tonic-gate 	uio->uio_iovcnt = 1;
33597c478bd9Sstevel@tonic-gate 	uio->uio_iov->iov_base = (caddr_t)(uintptr_t)arg->aio_buf;
33607c478bd9Sstevel@tonic-gate 	uio->uio_iov->iov_len = arg->aio_nbytes;
33617c478bd9Sstevel@tonic-gate 	uio->uio_loffset = arg->aio_offset;
33627c478bd9Sstevel@tonic-gate 	*reqpp = reqp;
33637c478bd9Sstevel@tonic-gate 	return (0);
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate /*
33677c478bd9Sstevel@tonic-gate  * This routine is called when a non largefile call is made by a 32bit
33687c478bd9Sstevel@tonic-gate  * process on a ILP32 or LP64 kernel.
33697c478bd9Sstevel@tonic-gate  */
33707c478bd9Sstevel@tonic-gate static int
alio32(int mode_arg,void * aiocb_arg,int nent,void * sigev)33717c478bd9Sstevel@tonic-gate alio32(
33727c478bd9Sstevel@tonic-gate 	int		mode_arg,
33737c478bd9Sstevel@tonic-gate 	void		*aiocb_arg,
33747c478bd9Sstevel@tonic-gate 	int		nent,
337534709573Sraf 	void		*sigev)
33767c478bd9Sstevel@tonic-gate {
33777c478bd9Sstevel@tonic-gate 	file_t		*fp;
33787c478bd9Sstevel@tonic-gate 	file_t		*prev_fp = NULL;
33797c478bd9Sstevel@tonic-gate 	int		prev_mode = -1;
33807c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
33817c478bd9Sstevel@tonic-gate 	aio_lio_t	*head;
33827c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp;
33837c478bd9Sstevel@tonic-gate 	aio_t		*aiop;
338434709573Sraf 	caddr_t		cbplist;
33857c478bd9Sstevel@tonic-gate 	aiocb_t		cb;
33867c478bd9Sstevel@tonic-gate 	aiocb_t		*aiocb = &cb;
33877c478bd9Sstevel@tonic-gate #ifdef	_LP64
33887c478bd9Sstevel@tonic-gate 	aiocb32_t	*cbp;
33897c478bd9Sstevel@tonic-gate 	caddr32_t	*ucbp;
33907c478bd9Sstevel@tonic-gate 	aiocb32_t	cb32;
33917c478bd9Sstevel@tonic-gate 	aiocb32_t	*aiocb32 = &cb32;
339234709573Sraf 	struct sigevent32	sigevk;
33937c478bd9Sstevel@tonic-gate #else
33947c478bd9Sstevel@tonic-gate 	aiocb_t		*cbp, **ucbp;
339534709573Sraf 	struct sigevent	sigevk;
33967c478bd9Sstevel@tonic-gate #endif
33977c478bd9Sstevel@tonic-gate 	sigqueue_t	*sqp;
33987c478bd9Sstevel@tonic-gate 	int		(*aio_func)();
33997c478bd9Sstevel@tonic-gate 	int		mode;
340034709573Sraf 	int		error = 0;
340134709573Sraf 	int		aio_errors = 0;
34027c478bd9Sstevel@tonic-gate 	int		i;
34037c478bd9Sstevel@tonic-gate 	size_t		ssize;
34047c478bd9Sstevel@tonic-gate 	int		deadhead = 0;
34057c478bd9Sstevel@tonic-gate 	int		aio_notsupported = 0;
340634709573Sraf 	int		lio_head_port;
340734709573Sraf 	int		aio_port;
340834709573Sraf 	int		aio_thread;
34097c478bd9Sstevel@tonic-gate 	port_kevent_t	*pkevtp = NULL;
341034b3058fSpraks 	int		portused = 0;
34117c478bd9Sstevel@tonic-gate #ifdef	_LP64
34127c478bd9Sstevel@tonic-gate 	port_notify32_t	pnotify;
34137c478bd9Sstevel@tonic-gate #else
34147c478bd9Sstevel@tonic-gate 	port_notify_t	pnotify;
34157c478bd9Sstevel@tonic-gate #endif
341634709573Sraf 	int		event;
341734709573Sraf 
34187c478bd9Sstevel@tonic-gate 	aiop = curproc->p_aio;
34197c478bd9Sstevel@tonic-gate 	if (aiop == NULL || nent <= 0 || nent > _AIO_LISTIO_MAX)
34207c478bd9Sstevel@tonic-gate 		return (EINVAL);
34217c478bd9Sstevel@tonic-gate 
34227c478bd9Sstevel@tonic-gate #ifdef	_LP64
34237c478bd9Sstevel@tonic-gate 	ssize = (sizeof (caddr32_t) * nent);
34247c478bd9Sstevel@tonic-gate #else
34257c478bd9Sstevel@tonic-gate 	ssize = (sizeof (aiocb_t *) * nent);
34267c478bd9Sstevel@tonic-gate #endif
34277c478bd9Sstevel@tonic-gate 	cbplist = kmem_alloc(ssize, KM_SLEEP);
34287c478bd9Sstevel@tonic-gate 	ucbp = (void *)cbplist;
34297c478bd9Sstevel@tonic-gate 
343034709573Sraf 	if (copyin(aiocb_arg, cbplist, ssize) ||
343134709573Sraf 	    (sigev && copyin(sigev, &sigevk, sizeof (struct sigevent32)))) {
34327c478bd9Sstevel@tonic-gate 		kmem_free(cbplist, ssize);
34337c478bd9Sstevel@tonic-gate 		return (EFAULT);
34347c478bd9Sstevel@tonic-gate 	}
34357c478bd9Sstevel@tonic-gate 
343634709573Sraf 	/* Event Ports  */
343734709573Sraf 	if (sigev &&
343834709573Sraf 	    (sigevk.sigev_notify == SIGEV_THREAD ||
343934709573Sraf 	    sigevk.sigev_notify == SIGEV_PORT)) {
344034709573Sraf 		if (sigevk.sigev_notify == SIGEV_THREAD) {
344134709573Sraf 			pnotify.portnfy_port = sigevk.sigev_signo;
344234709573Sraf 			pnotify.portnfy_user = sigevk.sigev_value.sival_ptr;
344334709573Sraf 		} else if (copyin(
344434709573Sraf 		    (void *)(uintptr_t)sigevk.sigev_value.sival_ptr,
344534709573Sraf 		    &pnotify, sizeof (pnotify))) {
34467c478bd9Sstevel@tonic-gate 			kmem_free(cbplist, ssize);
34477c478bd9Sstevel@tonic-gate 			return (EFAULT);
34487c478bd9Sstevel@tonic-gate 		}
344934709573Sraf 		error = port_alloc_event(pnotify.portnfy_port,
345034709573Sraf 		    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO, &pkevtp);
345134709573Sraf 		if (error) {
345234709573Sraf 			if (error == ENOMEM || error == EAGAIN)
345334709573Sraf 				error = EAGAIN;
345434709573Sraf 			else
345534709573Sraf 				error = EINVAL;
345634709573Sraf 			kmem_free(cbplist, ssize);
345734709573Sraf 			return (error);
345834709573Sraf 		}
345934709573Sraf 		lio_head_port = pnotify.portnfy_port;
346034b3058fSpraks 		portused = 1;
34617c478bd9Sstevel@tonic-gate 	}
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 	/*
34647c478bd9Sstevel@tonic-gate 	 * a list head should be allocated if notification is
34657c478bd9Sstevel@tonic-gate 	 * enabled for this list.
34667c478bd9Sstevel@tonic-gate 	 */
34677c478bd9Sstevel@tonic-gate 	head = NULL;
34687c478bd9Sstevel@tonic-gate 
346934709573Sraf 	if (mode_arg == LIO_WAIT || sigev) {
34707c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
34717c478bd9Sstevel@tonic-gate 		error = aio_lio_alloc(&head);
34727c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
34737c478bd9Sstevel@tonic-gate 		if (error)
34747c478bd9Sstevel@tonic-gate 			goto done;
34757c478bd9Sstevel@tonic-gate 		deadhead = 1;
34767c478bd9Sstevel@tonic-gate 		head->lio_nent = nent;
34777c478bd9Sstevel@tonic-gate 		head->lio_refcnt = nent;
347834709573Sraf 		head->lio_port = -1;
347934709573Sraf 		head->lio_portkev = NULL;
348034709573Sraf 		if (sigev && sigevk.sigev_notify == SIGEV_SIGNAL &&
348134709573Sraf 		    sigevk.sigev_signo > 0 && sigevk.sigev_signo < NSIG) {
34827c478bd9Sstevel@tonic-gate 			sqp = kmem_zalloc(sizeof (sigqueue_t), KM_NOSLEEP);
34837c478bd9Sstevel@tonic-gate 			if (sqp == NULL) {
34847c478bd9Sstevel@tonic-gate 				error = EAGAIN;
34857c478bd9Sstevel@tonic-gate 				goto done;
34867c478bd9Sstevel@tonic-gate 			}
34877c478bd9Sstevel@tonic-gate 			sqp->sq_func = NULL;
34887c478bd9Sstevel@tonic-gate 			sqp->sq_next = NULL;
34897c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_code = SI_ASYNCIO;
34907c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_pid = curproc->p_pid;
34917c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_ctid = PRCTID(curproc);
34927c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_zoneid = getzoneid();
34937c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_uid = crgetuid(curproc->p_cred);
349434709573Sraf 			sqp->sq_info.si_signo = sigevk.sigev_signo;
34957c478bd9Sstevel@tonic-gate 			sqp->sq_info.si_value.sival_int =
349634709573Sraf 			    sigevk.sigev_value.sival_int;
34977c478bd9Sstevel@tonic-gate 			head->lio_sigqp = sqp;
34987c478bd9Sstevel@tonic-gate 		} else {
34997c478bd9Sstevel@tonic-gate 			head->lio_sigqp = NULL;
35007c478bd9Sstevel@tonic-gate 		}
350134709573Sraf 		if (pkevtp) {
350234709573Sraf 			/*
350334709573Sraf 			 * Prepare data to send when list of aiocb's has
350434709573Sraf 			 * completed.
350534709573Sraf 			 */
350634709573Sraf 			port_init_event(pkevtp, (uintptr_t)sigev,
350734709573Sraf 			    (void *)(uintptr_t)pnotify.portnfy_user,
350834709573Sraf 			    NULL, head);
350934709573Sraf 			pkevtp->portkev_events = AIOLIO;
351034709573Sraf 			head->lio_portkev = pkevtp;
351134709573Sraf 			head->lio_port = pnotify.portnfy_port;
351234709573Sraf 		}
35137c478bd9Sstevel@tonic-gate 	}
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 	for (i = 0; i < nent; i++, ucbp++) {
35167c478bd9Sstevel@tonic-gate 
35177c478bd9Sstevel@tonic-gate 		/* skip entry if it can't be copied. */
35187c478bd9Sstevel@tonic-gate #ifdef	_LP64
35197c478bd9Sstevel@tonic-gate 		cbp = (aiocb32_t *)(uintptr_t)*ucbp;
352034709573Sraf 		if (cbp == NULL || copyin(cbp, aiocb32, sizeof (*aiocb32)))
35217c478bd9Sstevel@tonic-gate #else
35227c478bd9Sstevel@tonic-gate 		cbp = (aiocb_t *)*ucbp;
352334709573Sraf 		if (cbp == NULL || copyin(cbp, aiocb, sizeof (*aiocb)))
35247c478bd9Sstevel@tonic-gate #endif
352534709573Sraf 		{
35267c478bd9Sstevel@tonic-gate 			if (head) {
35277c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
35287c478bd9Sstevel@tonic-gate 				head->lio_nent--;
35297c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
35307c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
35317c478bd9Sstevel@tonic-gate 			}
35327c478bd9Sstevel@tonic-gate 			continue;
35337c478bd9Sstevel@tonic-gate 		}
35347c478bd9Sstevel@tonic-gate #ifdef	_LP64
35357c478bd9Sstevel@tonic-gate 		/*
35367c478bd9Sstevel@tonic-gate 		 * copy 32 bit structure into 64 bit structure
35377c478bd9Sstevel@tonic-gate 		 */
35387c478bd9Sstevel@tonic-gate 		aiocb_32ton(aiocb32, aiocb);
35397c478bd9Sstevel@tonic-gate #endif /* _LP64 */
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate 		/* skip if opcode for aiocb is LIO_NOP */
35427c478bd9Sstevel@tonic-gate 		mode = aiocb->aio_lio_opcode;
35437c478bd9Sstevel@tonic-gate 		if (mode == LIO_NOP) {
35447c478bd9Sstevel@tonic-gate 			cbp = NULL;
35457c478bd9Sstevel@tonic-gate 			if (head) {
35467c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
35477c478bd9Sstevel@tonic-gate 				head->lio_nent--;
35487c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
35497c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
35507c478bd9Sstevel@tonic-gate 			}
35517c478bd9Sstevel@tonic-gate 			continue;
35527c478bd9Sstevel@tonic-gate 		}
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 		/* increment file descriptor's ref count. */
35557c478bd9Sstevel@tonic-gate 		if ((fp = getf(aiocb->aio_fildes)) == NULL) {
35567c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
35577c478bd9Sstevel@tonic-gate 			if (head) {
35587c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
35597c478bd9Sstevel@tonic-gate 				head->lio_nent--;
35607c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
35617c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
35627c478bd9Sstevel@tonic-gate 			}
35637c478bd9Sstevel@tonic-gate 			aio_errors++;
35647c478bd9Sstevel@tonic-gate 			continue;
35657c478bd9Sstevel@tonic-gate 		}
35667c478bd9Sstevel@tonic-gate 
35677c478bd9Sstevel@tonic-gate 		/*
35687c478bd9Sstevel@tonic-gate 		 * check the permission of the partition
35697c478bd9Sstevel@tonic-gate 		 */
35707c478bd9Sstevel@tonic-gate 		if ((fp->f_flag & mode) == 0) {
35717c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
35727c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, EBADF);
35737c478bd9Sstevel@tonic-gate 			if (head) {
35747c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
35757c478bd9Sstevel@tonic-gate 				head->lio_nent--;
35767c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
35777c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
35787c478bd9Sstevel@tonic-gate 			}
35797c478bd9Sstevel@tonic-gate 			aio_errors++;
35807c478bd9Sstevel@tonic-gate 			continue;
35817c478bd9Sstevel@tonic-gate 		}
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate 		/*
35847c478bd9Sstevel@tonic-gate 		 * common case where requests are to the same fd
35857c478bd9Sstevel@tonic-gate 		 * for the same r/w operation
35867c478bd9Sstevel@tonic-gate 		 * for UFS, need to set EBADFD
35877c478bd9Sstevel@tonic-gate 		 */
358834709573Sraf 		vp = fp->f_vnode;
358934709573Sraf 		if (fp != prev_fp || mode != prev_mode) {
35907c478bd9Sstevel@tonic-gate 			aio_func = check_vp(vp, mode);
35917c478bd9Sstevel@tonic-gate 			if (aio_func == NULL) {
35927c478bd9Sstevel@tonic-gate 				prev_fp = NULL;
35937c478bd9Sstevel@tonic-gate 				releasef(aiocb->aio_fildes);
359434709573Sraf 				lio_set_uerror(&cbp->aio_resultp, EBADFD);
35957c478bd9Sstevel@tonic-gate 				aio_notsupported++;
35967c478bd9Sstevel@tonic-gate 				if (head) {
35977c478bd9Sstevel@tonic-gate 					mutex_enter(&aiop->aio_mutex);
35987c478bd9Sstevel@tonic-gate 					head->lio_nent--;
35997c478bd9Sstevel@tonic-gate 					head->lio_refcnt--;
36007c478bd9Sstevel@tonic-gate 					mutex_exit(&aiop->aio_mutex);
36017c478bd9Sstevel@tonic-gate 				}
36027c478bd9Sstevel@tonic-gate 				continue;
36037c478bd9Sstevel@tonic-gate 			} else {
36047c478bd9Sstevel@tonic-gate 				prev_fp = fp;
36057c478bd9Sstevel@tonic-gate 				prev_mode = mode;
36067c478bd9Sstevel@tonic-gate 			}
36077c478bd9Sstevel@tonic-gate 		}
360834709573Sraf 
360934709573Sraf 		error = aio_req_setup(&reqp, aiop, aiocb,
3610*d2749ac6SRoger A. Faulkner 		    (aio_result_t *)&cbp->aio_resultp, vp, 0);
361134709573Sraf 		if (error) {
36127c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
36137c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, error);
36147c478bd9Sstevel@tonic-gate 			if (head) {
36157c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
36167c478bd9Sstevel@tonic-gate 				head->lio_nent--;
36177c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
36187c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
36197c478bd9Sstevel@tonic-gate 			}
36207c478bd9Sstevel@tonic-gate 			aio_errors++;
36217c478bd9Sstevel@tonic-gate 			continue;
36227c478bd9Sstevel@tonic-gate 		}
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate 		reqp->aio_req_lio = head;
36257c478bd9Sstevel@tonic-gate 		deadhead = 0;
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate 		/*
36287c478bd9Sstevel@tonic-gate 		 * Set the errno field now before sending the request to
36297c478bd9Sstevel@tonic-gate 		 * the driver to avoid a race condition
36307c478bd9Sstevel@tonic-gate 		 */
36317c478bd9Sstevel@tonic-gate 		(void) suword32(&cbp->aio_resultp.aio_errno,
36327c478bd9Sstevel@tonic-gate 		    EINPROGRESS);
36337c478bd9Sstevel@tonic-gate 
363434709573Sraf 		reqp->aio_req_iocb.iocb32 = (caddr32_t)(uintptr_t)cbp;
36357c478bd9Sstevel@tonic-gate 
363634709573Sraf 		event = (mode == LIO_READ)? AIOAREAD : AIOAWRITE;
363734709573Sraf 		aio_port = (aiocb->aio_sigevent.sigev_notify == SIGEV_PORT);
363834709573Sraf 		aio_thread = (aiocb->aio_sigevent.sigev_notify == SIGEV_THREAD);
363934709573Sraf 		if (aio_port | aio_thread) {
364034709573Sraf 			port_kevent_t *lpkevp;
364134709573Sraf 			/*
364234709573Sraf 			 * Prepare data to send with each aiocb completed.
364334709573Sraf 			 */
36447c478bd9Sstevel@tonic-gate #ifdef _LP64
364534709573Sraf 			if (aio_port) {
364634709573Sraf 				void *paddr = (void  *)(uintptr_t)
364734709573Sraf 				    aiocb32->aio_sigevent.sigev_value.sival_ptr;
364834709573Sraf 				if (copyin(paddr, &pnotify, sizeof (pnotify)))
364934709573Sraf 					error = EFAULT;
365034709573Sraf 			} else {	/* aio_thread */
365134709573Sraf 				pnotify.portnfy_port =
365234709573Sraf 				    aiocb32->aio_sigevent.sigev_signo;
365334709573Sraf 				pnotify.portnfy_user =
365434709573Sraf 				    aiocb32->aio_sigevent.sigev_value.sival_ptr;
365534709573Sraf 			}
36567c478bd9Sstevel@tonic-gate #else
365734709573Sraf 			if (aio_port) {
365834709573Sraf 				void *paddr =
365934709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
366034709573Sraf 				if (copyin(paddr, &pnotify, sizeof (pnotify)))
366134709573Sraf 					error = EFAULT;
366234709573Sraf 			} else {	/* aio_thread */
366334709573Sraf 				pnotify.portnfy_port =
366434709573Sraf 				    aiocb->aio_sigevent.sigev_signo;
366534709573Sraf 				pnotify.portnfy_user =
366634709573Sraf 				    aiocb->aio_sigevent.sigev_value.sival_ptr;
366734709573Sraf 			}
36687c478bd9Sstevel@tonic-gate #endif
366934709573Sraf 			if (error)
367034709573Sraf 				/* EMPTY */;
367134709573Sraf 			else if (pkevtp != NULL &&
367234709573Sraf 			    pnotify.portnfy_port == lio_head_port)
367334709573Sraf 				error = port_dup_event(pkevtp, &lpkevp,
367434709573Sraf 				    PORT_ALLOC_DEFAULT);
367534709573Sraf 			else
367634709573Sraf 				error = port_alloc_event(pnotify.portnfy_port,
367734709573Sraf 				    PORT_ALLOC_DEFAULT, PORT_SOURCE_AIO,
367834709573Sraf 				    &lpkevp);
367934709573Sraf 			if (error == 0) {
368034709573Sraf 				port_init_event(lpkevp, (uintptr_t)cbp,
368134709573Sraf 				    (void *)(uintptr_t)pnotify.portnfy_user,
368234709573Sraf 				    aio_port_callback, reqp);
368334709573Sraf 				lpkevp->portkev_events = event;
368434709573Sraf 				reqp->aio_req_portkev = lpkevp;
368534709573Sraf 				reqp->aio_req_port = pnotify.portnfy_port;
368634709573Sraf 			}
36877c478bd9Sstevel@tonic-gate 		}
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 		/*
36907c478bd9Sstevel@tonic-gate 		 * send the request to driver.
36917c478bd9Sstevel@tonic-gate 		 */
36927c478bd9Sstevel@tonic-gate 		if (error == 0) {
36937c478bd9Sstevel@tonic-gate 			if (aiocb->aio_nbytes == 0) {
36947c478bd9Sstevel@tonic-gate 				clear_active_fd(aiocb->aio_fildes);
36957c478bd9Sstevel@tonic-gate 				aio_zerolen(reqp);
36967c478bd9Sstevel@tonic-gate 				continue;
36977c478bd9Sstevel@tonic-gate 			}
36987c478bd9Sstevel@tonic-gate 			error = (*aio_func)(vp, (aio_req_t *)&reqp->aio_req,
36997c478bd9Sstevel@tonic-gate 			    CRED());
37007c478bd9Sstevel@tonic-gate 		}
37017c478bd9Sstevel@tonic-gate 
37027c478bd9Sstevel@tonic-gate 		/*
37037c478bd9Sstevel@tonic-gate 		 * the fd's ref count is not decremented until the IO has
37047c478bd9Sstevel@tonic-gate 		 * completed unless there was an error.
37057c478bd9Sstevel@tonic-gate 		 */
37067c478bd9Sstevel@tonic-gate 		if (error) {
37077c478bd9Sstevel@tonic-gate 			releasef(aiocb->aio_fildes);
37087c478bd9Sstevel@tonic-gate 			lio_set_uerror(&cbp->aio_resultp, error);
37097c478bd9Sstevel@tonic-gate 			if (head) {
37107c478bd9Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
37117c478bd9Sstevel@tonic-gate 				head->lio_nent--;
37127c478bd9Sstevel@tonic-gate 				head->lio_refcnt--;
37137c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
37147c478bd9Sstevel@tonic-gate 			}
37157c478bd9Sstevel@tonic-gate 			if (error == ENOTSUP)
37167c478bd9Sstevel@tonic-gate 				aio_notsupported++;
37177c478bd9Sstevel@tonic-gate 			else
37187c478bd9Sstevel@tonic-gate 				aio_errors++;
371934b3058fSpraks 			lio_set_error(reqp, portused);
37207c478bd9Sstevel@tonic-gate 		} else {
37217c478bd9Sstevel@tonic-gate 			clear_active_fd(aiocb->aio_fildes);
37227c478bd9Sstevel@tonic-gate 		}
37237c478bd9Sstevel@tonic-gate 	}
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 	if (aio_notsupported) {
37267c478bd9Sstevel@tonic-gate 		error = ENOTSUP;
37277c478bd9Sstevel@tonic-gate 	} else if (aio_errors) {
37287c478bd9Sstevel@tonic-gate 		/*
37297c478bd9Sstevel@tonic-gate 		 * return EIO if any request failed
37307c478bd9Sstevel@tonic-gate 		 */
37317c478bd9Sstevel@tonic-gate 		error = EIO;
37327c478bd9Sstevel@tonic-gate 	}
37337c478bd9Sstevel@tonic-gate 
37347c478bd9Sstevel@tonic-gate 	if (mode_arg == LIO_WAIT) {
37357c478bd9Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
37367c478bd9Sstevel@tonic-gate 		while (head->lio_refcnt > 0) {
37377c478bd9Sstevel@tonic-gate 			if (!cv_wait_sig(&head->lio_notify, &aiop->aio_mutex)) {
37387c478bd9Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
37397c478bd9Sstevel@tonic-gate 				error = EINTR;
37407c478bd9Sstevel@tonic-gate 				goto done;
37417c478bd9Sstevel@tonic-gate 			}
37427c478bd9Sstevel@tonic-gate 		}
37437c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
37447c478bd9Sstevel@tonic-gate 		alio_cleanup(aiop, (aiocb_t **)cbplist, nent, AIO_32);
37457c478bd9Sstevel@tonic-gate 	}
37467c478bd9Sstevel@tonic-gate 
37477c478bd9Sstevel@tonic-gate done:
37487c478bd9Sstevel@tonic-gate 	kmem_free(cbplist, ssize);
37497c478bd9Sstevel@tonic-gate 	if (deadhead) {
37507c478bd9Sstevel@tonic-gate 		if (head->lio_sigqp)
37517c478bd9Sstevel@tonic-gate 			kmem_free(head->lio_sigqp, sizeof (sigqueue_t));
375234709573Sraf 		if (head->lio_portkev)
375334709573Sraf 			port_free_event(head->lio_portkev);
37547c478bd9Sstevel@tonic-gate 		kmem_free(head, sizeof (aio_lio_t));
37557c478bd9Sstevel@tonic-gate 	}
37567c478bd9Sstevel@tonic-gate 	return (error);
37577c478bd9Sstevel@tonic-gate }
37587c478bd9Sstevel@tonic-gate 
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32_IMPL
37617c478bd9Sstevel@tonic-gate void
aiocb_32ton(aiocb32_t * src,aiocb_t * dest)37627c478bd9Sstevel@tonic-gate aiocb_32ton(aiocb32_t *src, aiocb_t *dest)
37637c478bd9Sstevel@tonic-gate {
37647c478bd9Sstevel@tonic-gate 	dest->aio_fildes = src->aio_fildes;
37657c478bd9Sstevel@tonic-gate 	dest->aio_buf = (caddr_t)(uintptr_t)src->aio_buf;
37667c478bd9Sstevel@tonic-gate 	dest->aio_nbytes = (size_t)src->aio_nbytes;
37677c478bd9Sstevel@tonic-gate 	dest->aio_offset = (off_t)src->aio_offset;
37687c478bd9Sstevel@tonic-gate 	dest->aio_reqprio = src->aio_reqprio;
37697c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify = src->aio_sigevent.sigev_notify;
37707c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_signo = src->aio_sigevent.sigev_signo;
37717c478bd9Sstevel@tonic-gate 
37727c478bd9Sstevel@tonic-gate 	/*
37737c478bd9Sstevel@tonic-gate 	 * See comment in sigqueue32() on handling of 32-bit
37747c478bd9Sstevel@tonic-gate 	 * sigvals in a 64-bit kernel.
37757c478bd9Sstevel@tonic-gate 	 */
37767c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_value.sival_int =
37777c478bd9Sstevel@tonic-gate 	    (int)src->aio_sigevent.sigev_value.sival_int;
37787c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify_function = (void (*)(union sigval))
37797c478bd9Sstevel@tonic-gate 	    (uintptr_t)src->aio_sigevent.sigev_notify_function;
37807c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.sigev_notify_attributes = (pthread_attr_t *)
37817c478bd9Sstevel@tonic-gate 	    (uintptr_t)src->aio_sigevent.sigev_notify_attributes;
37827c478bd9Sstevel@tonic-gate 	dest->aio_sigevent.__sigev_pad2 = src->aio_sigevent.__sigev_pad2;
37837c478bd9Sstevel@tonic-gate 	dest->aio_lio_opcode = src->aio_lio_opcode;
37847c478bd9Sstevel@tonic-gate 	dest->aio_state = src->aio_state;
37857c478bd9Sstevel@tonic-gate 	dest->aio__pad[0] = src->aio__pad[0];
37867c478bd9Sstevel@tonic-gate }
37877c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
37887c478bd9Sstevel@tonic-gate 
37897c478bd9Sstevel@tonic-gate /*
37907c478bd9Sstevel@tonic-gate  * aio_port_callback() is called just before the event is retrieved from the
37917c478bd9Sstevel@tonic-gate  * port. The task of this callback function is to finish the work of the
37927c478bd9Sstevel@tonic-gate  * transaction for the application, it means :
37937c478bd9Sstevel@tonic-gate  * - copyout transaction data to the application
37947c478bd9Sstevel@tonic-gate  *	(this thread is running in the right process context)
37957c478bd9Sstevel@tonic-gate  * - keep trace of the transaction (update of counters).
37967c478bd9Sstevel@tonic-gate  * - free allocated buffers
37977c478bd9Sstevel@tonic-gate  * The aiocb pointer is the object element of the port_kevent_t structure.
37987c478bd9Sstevel@tonic-gate  *
37997c478bd9Sstevel@tonic-gate  * flag :
38007c478bd9Sstevel@tonic-gate  *	PORT_CALLBACK_DEFAULT : do copyout and free resources
38017c478bd9Sstevel@tonic-gate  *	PORT_CALLBACK_CLOSE   : don't do copyout, free resources
38027c478bd9Sstevel@tonic-gate  */
38037c478bd9Sstevel@tonic-gate 
38047c478bd9Sstevel@tonic-gate /*ARGSUSED*/
38057c478bd9Sstevel@tonic-gate int
aio_port_callback(void * arg,int * events,pid_t pid,int flag,void * evp)38067c478bd9Sstevel@tonic-gate aio_port_callback(void *arg, int *events, pid_t pid, int flag, void *evp)
38077c478bd9Sstevel@tonic-gate {
38087c478bd9Sstevel@tonic-gate 	aio_t		*aiop = curproc->p_aio;
38097c478bd9Sstevel@tonic-gate 	aio_req_t	*reqp = arg;
38107c478bd9Sstevel@tonic-gate 	struct	iovec	*iov;
38117c478bd9Sstevel@tonic-gate 	struct	buf	*bp;
38127c478bd9Sstevel@tonic-gate 	void		*resultp;
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	if (pid != curproc->p_pid) {
38157c478bd9Sstevel@tonic-gate 		/* wrong proc !!, can not deliver data here ... */
38167c478bd9Sstevel@tonic-gate 		return (EACCES);
38177c478bd9Sstevel@tonic-gate 	}
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_portq_mutex);
38207c478bd9Sstevel@tonic-gate 	reqp->aio_req_portkev = NULL;
38217c478bd9Sstevel@tonic-gate 	aio_req_remove_portq(aiop, reqp); /* remove request from portq */
38227c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_portq_mutex);
38237c478bd9Sstevel@tonic-gate 	aphysio_unlock(reqp);		/* unlock used pages */
38247c478bd9Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
38257c478bd9Sstevel@tonic-gate 	if (reqp->aio_req_flags & AIO_COPYOUTDONE) {
38267c478bd9Sstevel@tonic-gate 		aio_req_free_port(aiop, reqp);	/* back to free list */
38277c478bd9Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
38287c478bd9Sstevel@tonic-gate 		return (0);
38297c478bd9Sstevel@tonic-gate 	}
38307c478bd9Sstevel@tonic-gate 
38317c478bd9Sstevel@tonic-gate 	iov = reqp->aio_req_uio.uio_iov;
38327c478bd9Sstevel@tonic-gate 	bp = &reqp->aio_req_buf;
38337c478bd9Sstevel@tonic-gate 	resultp = (void *)reqp->aio_req_resultp;
38347c478bd9Sstevel@tonic-gate 	aio_req_free_port(aiop, reqp);	/* request struct back to free list */
38357c478bd9Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
38367c478bd9Sstevel@tonic-gate 	if (flag == PORT_CALLBACK_DEFAULT)
38377c478bd9Sstevel@tonic-gate 		aio_copyout_result_port(iov, bp, resultp);
38387c478bd9Sstevel@tonic-gate 	return (0);
38397c478bd9Sstevel@tonic-gate }
3840