xref: /onnv-gate/usr/src/uts/common/os/aio_subr.c (revision 41:3cf903690aea)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*41Spraks  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/proc.h>
310Sstevel@tonic-gate #include <sys/file.h>
320Sstevel@tonic-gate #include <sys/errno.h>
330Sstevel@tonic-gate #include <sys/param.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/cmn_err.h>
360Sstevel@tonic-gate #include <sys/systm.h>
370Sstevel@tonic-gate #include <vm/as.h>
380Sstevel@tonic-gate #include <vm/page.h>
390Sstevel@tonic-gate #include <sys/uio.h>
400Sstevel@tonic-gate #include <sys/kmem.h>
410Sstevel@tonic-gate #include <sys/debug.h>
420Sstevel@tonic-gate #include <sys/aio_impl.h>
430Sstevel@tonic-gate #include <sys/epm.h>
440Sstevel@tonic-gate #include <sys/fs/snode.h>
450Sstevel@tonic-gate #include <sys/siginfo.h>
460Sstevel@tonic-gate #include <sys/cpuvar.h>
470Sstevel@tonic-gate #include <sys/tnf_probe.h>
480Sstevel@tonic-gate #include <sys/conf.h>
490Sstevel@tonic-gate #include <sys/sdt.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate int aphysio(int (*)(), int (*)(), dev_t, int, void (*)(), struct aio_req *);
520Sstevel@tonic-gate void aio_done(struct buf *);
530Sstevel@tonic-gate void aphysio_unlock(aio_req_t *);
540Sstevel@tonic-gate void aio_cleanup(int);
550Sstevel@tonic-gate void aio_cleanup_exit(void);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * private functions
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate static void aio_sigev_send(proc_t *, sigqueue_t *);
610Sstevel@tonic-gate static void aio_hash_delete(aio_t *, aio_req_t *);
620Sstevel@tonic-gate static void aio_lio_free(aio_t *, aio_lio_t *);
630Sstevel@tonic-gate static void aio_enq(aio_req_t **, aio_req_t *, int);
640Sstevel@tonic-gate static void aio_cleanup_cleanupq(aio_t *, aio_req_t *, int);
650Sstevel@tonic-gate static int aio_cleanup_notifyq(aio_t *, aio_req_t *, int);
660Sstevel@tonic-gate static void aio_cleanup_pollq(aio_t *, aio_req_t *, int);
670Sstevel@tonic-gate static void aio_enq_doneq(aio_t *aiop, aio_req_t *reqp);
680Sstevel@tonic-gate static void aio_enq_portq(aio_t *, aio_req_t *, int);
690Sstevel@tonic-gate static void aio_enq_port_cleanupq(aio_t *, aio_req_t *);
700Sstevel@tonic-gate static void aio_cleanup_portq(aio_t *, aio_req_t *, int);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * async version of physio() that doesn't wait synchronously
740Sstevel@tonic-gate  * for the driver's strategy routine to complete.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate int
780Sstevel@tonic-gate aphysio(
790Sstevel@tonic-gate 	int (*strategy)(struct buf *),
800Sstevel@tonic-gate 	int (*cancel)(struct buf *),
810Sstevel@tonic-gate 	dev_t dev,
820Sstevel@tonic-gate 	int rw,
830Sstevel@tonic-gate 	void (*mincnt)(struct buf *),
840Sstevel@tonic-gate 	struct aio_req *aio)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	struct uio *uio = aio->aio_uio;
870Sstevel@tonic-gate 	aio_req_t *reqp = (aio_req_t *)aio->aio_private;
880Sstevel@tonic-gate 	struct buf *bp = &reqp->aio_req_buf;
890Sstevel@tonic-gate 	struct iovec *iov;
900Sstevel@tonic-gate 	struct as *as;
910Sstevel@tonic-gate 	char *a;
920Sstevel@tonic-gate 	int	error;
930Sstevel@tonic-gate 	size_t	c;
940Sstevel@tonic-gate 	struct page **pplist;
950Sstevel@tonic-gate 	struct dev_ops *ops = devopsp[getmajor(dev)];
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	if (uio->uio_loffset < 0)
980Sstevel@tonic-gate 		return (EINVAL);
990Sstevel@tonic-gate #ifdef	_ILP32
1000Sstevel@tonic-gate 	/*
1010Sstevel@tonic-gate 	 * For 32-bit kernels, check against SPEC_MAXOFFSET_T which represents
1020Sstevel@tonic-gate 	 * the maximum size that can be supported by the IO subsystem.
1030Sstevel@tonic-gate 	 * XXX this code assumes a D_64BIT driver.
1040Sstevel@tonic-gate 	 */
1050Sstevel@tonic-gate 	if (uio->uio_loffset > SPEC_MAXOFFSET_T)
1060Sstevel@tonic-gate 		return (EINVAL);
1070Sstevel@tonic-gate #endif	/* _ILP32 */
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	TNF_PROBE_5(aphysio_start, "kaio", /* CSTYLED */,
1100Sstevel@tonic-gate 		tnf_opaque, bp, bp,
1110Sstevel@tonic-gate 		tnf_device, device, dev,
1120Sstevel@tonic-gate 		tnf_offset, blkno, btodt(uio->uio_loffset),
1130Sstevel@tonic-gate 		tnf_size, size, uio->uio_iov->iov_len,
1140Sstevel@tonic-gate 		tnf_bioflags, rw, rw);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if (rw == B_READ) {
1170Sstevel@tonic-gate 		CPU_STATS_ADD_K(sys, phread, 1);
1180Sstevel@tonic-gate 	} else {
1190Sstevel@tonic-gate 		CPU_STATS_ADD_K(sys, phwrite, 1);
1200Sstevel@tonic-gate 	}
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	iov = uio->uio_iov;
1230Sstevel@tonic-gate 	sema_init(&bp->b_sem, 0, NULL, SEMA_DEFAULT, NULL);
1240Sstevel@tonic-gate 	sema_init(&bp->b_io, 0, NULL, SEMA_DEFAULT, NULL);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	bp->b_error = 0;
1270Sstevel@tonic-gate 	bp->b_flags = B_BUSY | B_PHYS | B_ASYNC | rw;
1280Sstevel@tonic-gate 	bp->b_edev = dev;
1290Sstevel@tonic-gate 	bp->b_dev = cmpdev(dev);
1300Sstevel@tonic-gate 	bp->b_lblkno = btodt(uio->uio_loffset);
1310Sstevel@tonic-gate 	bp->b_offset = uio->uio_loffset;
1320Sstevel@tonic-gate 	(void) ops->devo_getinfo(NULL, DDI_INFO_DEVT2DEVINFO,
1330Sstevel@tonic-gate 	    (void *)bp->b_edev, (void **)&bp->b_dip);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * Clustering: Clustering can set the b_iodone, b_forw and
1370Sstevel@tonic-gate 	 * b_proc fields to cluster-specifc values.
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	if (bp->b_iodone == NULL) {
1400Sstevel@tonic-gate 		bp->b_iodone = (int (*)()) aio_done;
1410Sstevel@tonic-gate 		/* b_forw points at an aio_req_t structure */
1420Sstevel@tonic-gate 		bp->b_forw = (struct buf *)reqp;
1430Sstevel@tonic-gate 		bp->b_proc = curproc;
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	a = bp->b_un.b_addr = iov->iov_base;
1470Sstevel@tonic-gate 	c = bp->b_bcount = iov->iov_len;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	(*mincnt)(bp);
1500Sstevel@tonic-gate 	if (bp->b_bcount != iov->iov_len)
1510Sstevel@tonic-gate 		return (ENOTSUP);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	as = bp->b_proc->p_as;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	error = as_pagelock(as, &pplist, a,
1560Sstevel@tonic-gate 	    c, rw == B_READ? S_WRITE : S_READ);
1570Sstevel@tonic-gate 	if (error != 0) {
1580Sstevel@tonic-gate 		bp->b_flags |= B_ERROR;
1590Sstevel@tonic-gate 		bp->b_error = error;
1600Sstevel@tonic-gate 		bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_SHADOW);
1610Sstevel@tonic-gate 		return (error);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_PAGELOCKDONE;
1640Sstevel@tonic-gate 	bp->b_shadow = pplist;
1650Sstevel@tonic-gate 	if (pplist != NULL) {
1660Sstevel@tonic-gate 		bp->b_flags |= B_SHADOW;
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (cancel != anocancel)
1700Sstevel@tonic-gate 		cmn_err(CE_PANIC,
1710Sstevel@tonic-gate 		    "aphysio: cancellation not supported, use anocancel");
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	reqp->aio_req_cancel = cancel;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	DTRACE_IO1(start, struct buf *, bp);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	return ((*strategy)(bp));
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*ARGSUSED*/
1810Sstevel@tonic-gate int
1820Sstevel@tonic-gate anocancel(struct buf *bp)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	return (ENXIO);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate  * Called from biodone().
1890Sstevel@tonic-gate  * Notify process that a pending AIO has finished.
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * Clustering: This function is made non-static as it is used
1940Sstevel@tonic-gate  * by clustering s/w as contract private interface.
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate void
1980Sstevel@tonic-gate aio_done(struct buf *bp)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	proc_t *p;
2010Sstevel@tonic-gate 	struct as *as;
2020Sstevel@tonic-gate 	aio_req_t *reqp;
2030Sstevel@tonic-gate 	aio_lio_t *head;
2040Sstevel@tonic-gate 	aio_t *aiop;
2050Sstevel@tonic-gate 	sigqueue_t *sigev;
2060Sstevel@tonic-gate 	sigqueue_t *lio_sigev = NULL;
2070Sstevel@tonic-gate 	int fd;
2080Sstevel@tonic-gate 	int cleanupqflag;
2090Sstevel@tonic-gate 	int pollqflag;
2100Sstevel@tonic-gate 	int portevpend;
2110Sstevel@tonic-gate 	void (*func)();
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	p = bp->b_proc;
2140Sstevel@tonic-gate 	reqp = (aio_req_t *)bp->b_forw;
2150Sstevel@tonic-gate 	fd = reqp->aio_req_fd;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	TNF_PROBE_5(aphysio_end, "kaio", /* CSTYLED */,
2180Sstevel@tonic-gate 		tnf_opaque, bp, bp,
2190Sstevel@tonic-gate 		tnf_device, device, bp->b_edev,
2200Sstevel@tonic-gate 		tnf_offset, blkno, btodt(reqp->aio_req_uio.uio_loffset),
2210Sstevel@tonic-gate 		tnf_size, size, reqp->aio_req_uio.uio_iov->iov_len,
2220Sstevel@tonic-gate 		tnf_bioflags, rw, (bp->b_flags & (B_READ|B_WRITE)));
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	/*
2250Sstevel@tonic-gate 	 * mapout earlier so that more kmem is available when aio is
2260Sstevel@tonic-gate 	 * heavily used. bug #1262082
2270Sstevel@tonic-gate 	 */
2280Sstevel@tonic-gate 	if (bp->b_flags & B_REMAPPED)
2290Sstevel@tonic-gate 		bp_mapout(bp);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/* decrement fd's ref count by one, now that aio request is done. */
2320Sstevel@tonic-gate 	areleasef(fd, P_FINFO(p));
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	aiop = p->p_aio;
2350Sstevel@tonic-gate 	ASSERT(aiop != NULL);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (reqp->aio_req_portkev) {
2380Sstevel@tonic-gate 		mutex_enter(&aiop->aio_portq_mutex);
2390Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
2400Sstevel@tonic-gate 		aiop->aio_pending--;
2410Sstevel@tonic-gate 		reqp->aio_req_flags &= ~AIO_PENDING;
2420Sstevel@tonic-gate 		/* Event port notification is desired for this transaction */
2430Sstevel@tonic-gate 		if (reqp->aio_req_flags & AIO_CLOSE_PORT) {
2440Sstevel@tonic-gate 			/*
2450Sstevel@tonic-gate 			 * The port is being closed and it is waiting for
2460Sstevel@tonic-gate 			 * pending asynchronous I/O transactions to complete.
2470Sstevel@tonic-gate 			 */
2480Sstevel@tonic-gate 			portevpend = --aiop->aio_portpendcnt;
2490Sstevel@tonic-gate 			aio_enq_portq(aiop, reqp, 1);
2500Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
2510Sstevel@tonic-gate 			mutex_exit(&aiop->aio_portq_mutex);
2520Sstevel@tonic-gate 			(void) port_send_event(reqp->aio_req_portkev);
2530Sstevel@tonic-gate 			if (portevpend == 0)
2540Sstevel@tonic-gate 				cv_broadcast(&aiop->aio_portcv);
2550Sstevel@tonic-gate 			return;
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		if (aiop->aio_flags & AIO_CLEANUP) {
2590Sstevel@tonic-gate 			/*
2600Sstevel@tonic-gate 			 * aio_cleanup_thread() is waiting for completion of
2610Sstevel@tonic-gate 			 * transactions.
2620Sstevel@tonic-gate 			 */
2630Sstevel@tonic-gate 			as = p->p_as;
2640Sstevel@tonic-gate 			mutex_enter(&as->a_contents);
2650Sstevel@tonic-gate 			aio_enq_port_cleanupq(aiop, reqp);
2660Sstevel@tonic-gate 			cv_signal(&aiop->aio_cleanupcv);
2670Sstevel@tonic-gate 			mutex_exit(&as->a_contents);
2680Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
2690Sstevel@tonic-gate 			mutex_exit(&aiop->aio_portq_mutex);
2700Sstevel@tonic-gate 			return;
2710Sstevel@tonic-gate 		}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		aio_enq_portq(aiop, reqp, 1);
2740Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
2750Sstevel@tonic-gate 		mutex_exit(&aiop->aio_portq_mutex);
2760Sstevel@tonic-gate 		(void) port_send_event(reqp->aio_req_portkev);
2770Sstevel@tonic-gate 		return;
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
2810Sstevel@tonic-gate 	ASSERT(aiop->aio_pending > 0);
2820Sstevel@tonic-gate 	ASSERT(reqp->aio_req_flags & AIO_PENDING);
2830Sstevel@tonic-gate 	aiop->aio_pending--;
2840Sstevel@tonic-gate 	reqp->aio_req_flags &= ~AIO_PENDING;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	reqp->aio_req_next = NULL;
2870Sstevel@tonic-gate 	/*
2880Sstevel@tonic-gate 	 * when the AIO_CLEANUP flag is enabled for this
2890Sstevel@tonic-gate 	 * process, or when the AIO_POLL bit is set for
2900Sstevel@tonic-gate 	 * this request, special handling is required.
2910Sstevel@tonic-gate 	 * otherwise the request is put onto the doneq.
2920Sstevel@tonic-gate 	 */
2930Sstevel@tonic-gate 	cleanupqflag = (aiop->aio_flags & AIO_CLEANUP);
2940Sstevel@tonic-gate 	pollqflag = (reqp->aio_req_flags & AIO_POLL);
2950Sstevel@tonic-gate 	if (cleanupqflag | pollqflag) {
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		if (cleanupqflag) {
2980Sstevel@tonic-gate 			as = p->p_as;
2990Sstevel@tonic-gate 			mutex_enter(&as->a_contents);
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		/*
3030Sstevel@tonic-gate 		 * requests with their AIO_POLL bit set are put
3040Sstevel@tonic-gate 		 * on the pollq, requests with sigevent structures
3050Sstevel@tonic-gate 		 * or with listio heads are put on the notifyq, and
3060Sstevel@tonic-gate 		 * the remaining requests don't require any special
3070Sstevel@tonic-gate 		 * cleanup handling, so they're put onto the default
3080Sstevel@tonic-gate 		 * cleanupq.
3090Sstevel@tonic-gate 		 */
3100Sstevel@tonic-gate 		if (pollqflag)
3110Sstevel@tonic-gate 			aio_enq(&aiop->aio_pollq, reqp, AIO_POLLQ);
3120Sstevel@tonic-gate 		else if (reqp->aio_req_sigqp || reqp->aio_req_lio)
3130Sstevel@tonic-gate 			aio_enq(&aiop->aio_notifyq, reqp, AIO_NOTIFYQ);
3140Sstevel@tonic-gate 		else
3150Sstevel@tonic-gate 			aio_enq(&aiop->aio_cleanupq, reqp, AIO_CLEANUPQ);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 		if (cleanupqflag) {
3180Sstevel@tonic-gate 			cv_signal(&aiop->aio_cleanupcv);
3190Sstevel@tonic-gate 			mutex_exit(&as->a_contents);
3200Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
3210Sstevel@tonic-gate 		} else {
3220Sstevel@tonic-gate 			ASSERT(pollqflag);
3230Sstevel@tonic-gate 			/* block aio_cleanup_exit until we're done */
3240Sstevel@tonic-gate 			aiop->aio_flags |= AIO_DONE_ACTIVE;
3250Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
3260Sstevel@tonic-gate 			/*
3270Sstevel@tonic-gate 			 * let the cleanup processing happen from an
3280Sstevel@tonic-gate 			 * AST. set an AST on all threads in this process
3290Sstevel@tonic-gate 			 */
3300Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
3310Sstevel@tonic-gate 			set_proc_ast(p);
3320Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3330Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
3340Sstevel@tonic-gate 			/* wakeup anybody waiting in aiowait() */
3350Sstevel@tonic-gate 			cv_broadcast(&aiop->aio_waitcv);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 			/* wakeup aio_cleanup_exit if needed */
3380Sstevel@tonic-gate 			if (aiop->aio_flags & AIO_CLEANUP)
3390Sstevel@tonic-gate 				cv_signal(&aiop->aio_cleanupcv);
3400Sstevel@tonic-gate 			aiop->aio_flags &= ~AIO_DONE_ACTIVE;
3410Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
3420Sstevel@tonic-gate 		}
3430Sstevel@tonic-gate 		return;
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/* put request on done queue. */
3470Sstevel@tonic-gate 	aio_enq_doneq(aiop, reqp);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/*
3500Sstevel@tonic-gate 	 * save req's sigevent pointer, and check its
3510Sstevel@tonic-gate 	 * value after releasing aio_mutex lock.
3520Sstevel@tonic-gate 	 */
3530Sstevel@tonic-gate 	sigev = reqp->aio_req_sigqp;
3540Sstevel@tonic-gate 	reqp->aio_req_sigqp = NULL;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	/*
3570Sstevel@tonic-gate 	 * when list IO notification is enabled, a signal
3580Sstevel@tonic-gate 	 * is sent only when all entries in the list are
3590Sstevel@tonic-gate 	 * done.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	if ((head = reqp->aio_req_lio) != NULL) {
3620Sstevel@tonic-gate 		ASSERT(head->lio_refcnt > 0);
3630Sstevel@tonic-gate 		if (--head->lio_refcnt == 0) {
3640Sstevel@tonic-gate 			cv_signal(&head->lio_notify);
3650Sstevel@tonic-gate 			/*
3660Sstevel@tonic-gate 			 * save lio's sigevent pointer, and check
3670Sstevel@tonic-gate 			 * its value after releasing aio_mutex
3680Sstevel@tonic-gate 			 * lock.
3690Sstevel@tonic-gate 			 */
3700Sstevel@tonic-gate 			lio_sigev = head->lio_sigqp;
3710Sstevel@tonic-gate 			head->lio_sigqp = NULL;
3720Sstevel@tonic-gate 		}
3730Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
3740Sstevel@tonic-gate 		if (sigev)
3750Sstevel@tonic-gate 			aio_sigev_send(p, sigev);
3760Sstevel@tonic-gate 		if (lio_sigev)
3770Sstevel@tonic-gate 			aio_sigev_send(p, lio_sigev);
3780Sstevel@tonic-gate 		return;
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/*
3820Sstevel@tonic-gate 	 * if AIO_WAITN set then
3830Sstevel@tonic-gate 	 * send signal only when we reached the
3840Sstevel@tonic-gate 	 * required amount of IO's finished
3850Sstevel@tonic-gate 	 * or when all IO's are done
3860Sstevel@tonic-gate 	 */
3870Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_WAITN) {
3880Sstevel@tonic-gate 		if (aiop->aio_waitncnt > 0)
3890Sstevel@tonic-gate 			aiop->aio_waitncnt--;
3900Sstevel@tonic-gate 		if (aiop->aio_pending == 0 ||
3910Sstevel@tonic-gate 		    aiop->aio_waitncnt == 0)
3920Sstevel@tonic-gate 			cv_broadcast(&aiop->aio_waitcv);
3930Sstevel@tonic-gate 	} else {
3940Sstevel@tonic-gate 		cv_broadcast(&aiop->aio_waitcv);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
3980Sstevel@tonic-gate 	if (sigev)
3990Sstevel@tonic-gate 		aio_sigev_send(p, sigev);
4000Sstevel@tonic-gate 	else {
4010Sstevel@tonic-gate 		/*
4020Sstevel@tonic-gate 		 * send a SIGIO signal when the process
4030Sstevel@tonic-gate 		 * has a handler enabled.
4040Sstevel@tonic-gate 		 */
4050Sstevel@tonic-gate 		if ((func = p->p_user.u_signal[SIGIO - 1]) !=
4060Sstevel@tonic-gate 		    SIG_DFL && (func != SIG_IGN))
4070Sstevel@tonic-gate 			psignal(p, SIGIO);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * send a queued signal to the specified process when
4130Sstevel@tonic-gate  * the event signal is non-NULL. A return value of 1
4140Sstevel@tonic-gate  * will indicate that a signal is queued, and 0 means that
4150Sstevel@tonic-gate  * no signal was specified, nor sent.
4160Sstevel@tonic-gate  */
4170Sstevel@tonic-gate static void
4180Sstevel@tonic-gate aio_sigev_send(proc_t *p, sigqueue_t *sigev)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 	ASSERT(sigev != NULL);
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
4230Sstevel@tonic-gate 	sigaddqa(p, NULL, sigev);
4240Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate  * special case handling for zero length requests. the aio request
4290Sstevel@tonic-gate  * short circuits the normal completion path since all that's required
4300Sstevel@tonic-gate  * to complete this request is to copyout a zero to the aio request's
4310Sstevel@tonic-gate  * return value.
4320Sstevel@tonic-gate  */
4330Sstevel@tonic-gate void
4340Sstevel@tonic-gate aio_zerolen(aio_req_t *reqp)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	struct buf *bp = &reqp->aio_req_buf;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_ZEROLEN;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	bp->b_forw = (struct buf *)reqp;
4420Sstevel@tonic-gate 	bp->b_proc = curproc;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	bp->b_resid = 0;
4450Sstevel@tonic-gate 	bp->b_flags = 0;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	aio_done(bp);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * unlock pages previously locked by as_pagelock
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate void
4540Sstevel@tonic-gate aphysio_unlock(aio_req_t *reqp)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	struct buf *bp;
4570Sstevel@tonic-gate 	struct iovec *iov;
4580Sstevel@tonic-gate 	int flags;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (reqp->aio_req_flags & AIO_PHYSIODONE)
4610Sstevel@tonic-gate 		return;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_PHYSIODONE;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	if (reqp->aio_req_flags & AIO_ZEROLEN)
4660Sstevel@tonic-gate 		return;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	bp = &reqp->aio_req_buf;
4690Sstevel@tonic-gate 	iov = reqp->aio_req_uio.uio_iov;
4700Sstevel@tonic-gate 	flags = (((bp->b_flags & B_READ) == B_READ) ? S_WRITE : S_READ);
4710Sstevel@tonic-gate 	if (reqp->aio_req_flags & AIO_PAGELOCKDONE) {
4720Sstevel@tonic-gate 		as_pageunlock(bp->b_proc->p_as,
4730Sstevel@tonic-gate 			bp->b_flags & B_SHADOW ? bp->b_shadow : NULL,
4740Sstevel@tonic-gate 			iov->iov_base, iov->iov_len, flags);
4750Sstevel@tonic-gate 		reqp->aio_req_flags &= ~AIO_PAGELOCKDONE;
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_SHADOW);
4780Sstevel@tonic-gate 	bp->b_flags |= B_DONE;
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate  * deletes a requests id from the hash table of outstanding
4830Sstevel@tonic-gate  * io.
4840Sstevel@tonic-gate  */
4850Sstevel@tonic-gate static void
4860Sstevel@tonic-gate aio_hash_delete(
4870Sstevel@tonic-gate 	aio_t *aiop,
4880Sstevel@tonic-gate 	struct aio_req_t *reqp)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	long index;
4910Sstevel@tonic-gate 	aio_result_t *resultp = reqp->aio_req_resultp;
4920Sstevel@tonic-gate 	aio_req_t *current;
4930Sstevel@tonic-gate 	aio_req_t **nextp;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	index = AIO_HASH(resultp);
4960Sstevel@tonic-gate 	nextp = (aiop->aio_hash + index);
4970Sstevel@tonic-gate 	while ((current = *nextp) != NULL) {
4980Sstevel@tonic-gate 		if (current->aio_req_resultp == resultp) {
4990Sstevel@tonic-gate 			*nextp = current->aio_hash_next;
5000Sstevel@tonic-gate 			return;
5010Sstevel@tonic-gate 		}
5020Sstevel@tonic-gate 		nextp = &current->aio_hash_next;
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate  * Put a list head struct onto its free list.
5080Sstevel@tonic-gate  */
5090Sstevel@tonic-gate static void
5100Sstevel@tonic-gate aio_lio_free(aio_t *aiop, aio_lio_t *head)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	if (head->lio_sigqp != NULL)
5150Sstevel@tonic-gate 		kmem_free(head->lio_sigqp, sizeof (sigqueue_t));
5160Sstevel@tonic-gate 	head->lio_next = aiop->aio_lio_free;
5170Sstevel@tonic-gate 	aiop->aio_lio_free = head;
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate /*
5210Sstevel@tonic-gate  * Put a reqp onto the freelist.
5220Sstevel@tonic-gate  */
5230Sstevel@tonic-gate void
5240Sstevel@tonic-gate aio_req_free(aio_t *aiop, aio_req_t *reqp)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	aio_lio_t *liop;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (reqp->aio_req_portkev) {
5310Sstevel@tonic-gate 		port_free_event(reqp->aio_req_portkev);
5320Sstevel@tonic-gate 		reqp->aio_req_portkev = NULL;
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if ((liop = reqp->aio_req_lio) != NULL) {
5360Sstevel@tonic-gate 		if (--liop->lio_nent == 0)
5370Sstevel@tonic-gate 			aio_lio_free(aiop, liop);
5380Sstevel@tonic-gate 		reqp->aio_req_lio = NULL;
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 	if (reqp->aio_req_sigqp != NULL)
5410Sstevel@tonic-gate 		kmem_free(reqp->aio_req_sigqp, sizeof (sigqueue_t));
5420Sstevel@tonic-gate 	reqp->aio_req_next = aiop->aio_free;
5430Sstevel@tonic-gate 	aiop->aio_free = reqp;
5440Sstevel@tonic-gate 	aiop->aio_outstanding--;
5450Sstevel@tonic-gate 	if (aiop->aio_outstanding == 0)
5460Sstevel@tonic-gate 		cv_broadcast(&aiop->aio_waitcv);
5470Sstevel@tonic-gate 	aio_hash_delete(aiop, reqp);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate  * Put a reqp onto the freelist.
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate void
5540Sstevel@tonic-gate aio_req_free_port(aio_t *aiop, aio_req_t *reqp)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	reqp->aio_req_next = aiop->aio_free;
5590Sstevel@tonic-gate 	aiop->aio_free = reqp;
5600Sstevel@tonic-gate 	aiop->aio_outstanding--;
5610Sstevel@tonic-gate 	aio_hash_delete(aiop, reqp);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate  * Put a completed request onto its appropiate done queue.
5670Sstevel@tonic-gate  */
5680Sstevel@tonic-gate /*ARGSUSED*/
5690Sstevel@tonic-gate static void
5700Sstevel@tonic-gate aio_enq(aio_req_t **qhead, aio_req_t *reqp, int qflg_new)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	if (*qhead == NULL) {
5730Sstevel@tonic-gate 		*qhead = reqp;
5740Sstevel@tonic-gate 		reqp->aio_req_next = reqp;
5750Sstevel@tonic-gate 		reqp->aio_req_prev = reqp;
5760Sstevel@tonic-gate 	} else {
5770Sstevel@tonic-gate 		reqp->aio_req_next = *qhead;
5780Sstevel@tonic-gate 		reqp->aio_req_prev = (*qhead)->aio_req_prev;
5790Sstevel@tonic-gate 		reqp->aio_req_prev->aio_req_next = reqp;
5800Sstevel@tonic-gate 		(*qhead)->aio_req_prev = reqp;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	reqp->aio_req_flags |= qflg_new;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate  * Put a completed request onto its appropiate done queue.
5880Sstevel@tonic-gate  */
5890Sstevel@tonic-gate static void
5900Sstevel@tonic-gate aio_enq_doneq(aio_t *aiop, aio_req_t *reqp)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if (aiop->aio_doneq == NULL) {
5940Sstevel@tonic-gate 		aiop->aio_doneq = reqp;
5950Sstevel@tonic-gate 		reqp->aio_req_next = reqp;
5960Sstevel@tonic-gate 		reqp->aio_req_prev = reqp;
5970Sstevel@tonic-gate 	} else {
5980Sstevel@tonic-gate 		reqp->aio_req_next = aiop->aio_doneq;
5990Sstevel@tonic-gate 		reqp->aio_req_prev = aiop->aio_doneq->aio_req_prev;
6000Sstevel@tonic-gate 		reqp->aio_req_prev->aio_req_next = reqp;
6010Sstevel@tonic-gate 		aiop->aio_doneq->aio_req_prev = reqp;
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_DONEQ;
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate #ifdef DEBUG
6080Sstevel@tonic-gate /* ARGSUSED */
6090Sstevel@tonic-gate void
6100Sstevel@tonic-gate aio_check_flag(aio_req_t *reqp, int check, int val, int flag)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	int	lval;
6130Sstevel@tonic-gate 	if (reqp == NULL)
6140Sstevel@tonic-gate 		return;
6150Sstevel@tonic-gate 	lval = reqp->aio_req_flags & check;
6160Sstevel@tonic-gate 	ASSERT(lval == val);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate void
6200Sstevel@tonic-gate aio_checkset_flag(aio_req_t *reqp, int checkdel, int set)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate 	aio_check_flag(reqp, checkdel, checkdel, 0);
6230Sstevel@tonic-gate 	reqp->aio_req_flags &= ~checkdel;
6240Sstevel@tonic-gate 	reqp->aio_req_flags |= set;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	aio_check_flag(reqp->aio_req_next, set, set, 1);
6270Sstevel@tonic-gate 	aio_check_flag(reqp->aio_req_prev, set, set, 2);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate #endif	/* DEBUG */
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate /*
6320Sstevel@tonic-gate  * Put a pending request onto the pending port queue.
6330Sstevel@tonic-gate  */
6340Sstevel@tonic-gate void
6350Sstevel@tonic-gate aio_enq_port_pending(aio_t *aiop, aio_req_t *reqp)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_mutex));
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	if (aiop->aio_portpending != NULL) {
6400Sstevel@tonic-gate 		reqp->aio_req_next = aiop->aio_portpending;
6410Sstevel@tonic-gate 		aiop->aio_portpending->aio_req_prev = reqp;
6420Sstevel@tonic-gate 	} else {
6430Sstevel@tonic-gate 		reqp->aio_req_next = NULL;
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 	reqp->aio_req_prev = NULL;
6460Sstevel@tonic-gate 	aiop->aio_portpending = reqp;
6470Sstevel@tonic-gate #ifdef DEBUG
6480Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_REQ_PEND;
6490Sstevel@tonic-gate #endif
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate /*
6530Sstevel@tonic-gate  * Put a completed request onto the port queue.
6540Sstevel@tonic-gate  */
6550Sstevel@tonic-gate static void
6560Sstevel@tonic-gate aio_enq_portq(aio_t *aiop, aio_req_t *reqp, int pending)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_portq_mutex));
6600Sstevel@tonic-gate 	if (pending) {
6610Sstevel@tonic-gate #ifdef DEBUG
6620Sstevel@tonic-gate 		aio_checkset_flag(reqp, AIO_REQ_PEND, AIO_REQ_PEND);
6630Sstevel@tonic-gate #endif
6640Sstevel@tonic-gate 		/* first take request out of the pending queue ... */
6650Sstevel@tonic-gate 		if (reqp->aio_req_prev == NULL)
6660Sstevel@tonic-gate 			/* first request */
6670Sstevel@tonic-gate 			aiop->aio_portpending = reqp->aio_req_next;
6680Sstevel@tonic-gate 		else
6690Sstevel@tonic-gate 			reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
6700Sstevel@tonic-gate 		if (reqp->aio_req_next != NULL)
6710Sstevel@tonic-gate 			reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/* ... and insert request into done queue */
6750Sstevel@tonic-gate 	if (aiop->aio_portq != NULL) {
6760Sstevel@tonic-gate 		reqp->aio_req_next = aiop->aio_portq;
6770Sstevel@tonic-gate 		aiop->aio_portq->aio_req_prev = reqp;
6780Sstevel@tonic-gate 	} else {
6790Sstevel@tonic-gate 		reqp->aio_req_next = NULL;
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 	reqp->aio_req_prev = NULL;
6820Sstevel@tonic-gate 	aiop->aio_portq = reqp;
6830Sstevel@tonic-gate #ifdef DEBUG
6840Sstevel@tonic-gate 	if (pending)
6850Sstevel@tonic-gate 		aio_checkset_flag(reqp, AIO_REQ_PEND, AIO_REQ_PORTQ);
6860Sstevel@tonic-gate 	else
6870Sstevel@tonic-gate 		aio_checkset_flag(reqp, AIO_REQ_CLEAN, AIO_REQ_PORTQ);
6880Sstevel@tonic-gate #endif
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate  * Put a completed request onto the port cleanup queue.
6930Sstevel@tonic-gate  */
6940Sstevel@tonic-gate static void
6950Sstevel@tonic-gate aio_enq_port_cleanupq(aio_t *aiop, aio_req_t *reqp)
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate #ifdef DEBUG
6990Sstevel@tonic-gate 	aio_checkset_flag(reqp, AIO_REQ_PEND, AIO_REQ_PEND);
7000Sstevel@tonic-gate #endif
7010Sstevel@tonic-gate 	/* first take request out of the pending queue ... */
7020Sstevel@tonic-gate 	if (reqp->aio_req_prev == NULL)
7030Sstevel@tonic-gate 		/* first request */
7040Sstevel@tonic-gate 		aiop->aio_portpending = reqp->aio_req_next;
7050Sstevel@tonic-gate 	else
7060Sstevel@tonic-gate 		reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (reqp->aio_req_next != NULL)
7090Sstevel@tonic-gate 		reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/* ... and insert request into the cleanup queue */
7120Sstevel@tonic-gate 	reqp->aio_req_next = aiop->aio_portcleanupq;
7130Sstevel@tonic-gate 	aiop->aio_portcleanupq = reqp;
7140Sstevel@tonic-gate #ifdef DEBUG
7150Sstevel@tonic-gate 	reqp->aio_req_prev = NULL;
7160Sstevel@tonic-gate 	aio_checkset_flag(reqp, AIO_REQ_PEND, AIO_REQ_CLEAN);
7170Sstevel@tonic-gate #endif
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * concatenate a specified queue with the cleanupq. the specified
7220Sstevel@tonic-gate  * queue is put onto the tail of the cleanupq. all elements on the
7230Sstevel@tonic-gate  * specified queue should have their aio_req_flags field cleared.
7240Sstevel@tonic-gate  */
7250Sstevel@tonic-gate /*ARGSUSED*/
7260Sstevel@tonic-gate void
7270Sstevel@tonic-gate aio_cleanupq_concat(aio_t *aiop, aio_req_t *q2, int qflg)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	aio_req_t *cleanupqhead, *q2tail;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate #ifdef DEBUG
7320Sstevel@tonic-gate 	aio_req_t *reqp = q2;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	do {
7350Sstevel@tonic-gate 		ASSERT(reqp->aio_req_flags & qflg);
7360Sstevel@tonic-gate 		reqp->aio_req_flags &= ~qflg;
7370Sstevel@tonic-gate 		reqp->aio_req_flags |= AIO_CLEANUPQ;
7380Sstevel@tonic-gate 	} while ((reqp = reqp->aio_req_next) != q2);
7390Sstevel@tonic-gate #endif
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	cleanupqhead = aiop->aio_cleanupq;
7420Sstevel@tonic-gate 	if (cleanupqhead == NULL)
7430Sstevel@tonic-gate 		aiop->aio_cleanupq = q2;
7440Sstevel@tonic-gate 	else {
7450Sstevel@tonic-gate 		cleanupqhead->aio_req_prev->aio_req_next = q2;
7460Sstevel@tonic-gate 		q2tail = q2->aio_req_prev;
7470Sstevel@tonic-gate 		q2tail->aio_req_next = cleanupqhead;
7480Sstevel@tonic-gate 		q2->aio_req_prev = cleanupqhead->aio_req_prev;
7490Sstevel@tonic-gate 		cleanupqhead->aio_req_prev = q2tail;
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate /*
7540Sstevel@tonic-gate  * cleanup aio requests that are on the per-process poll queue.
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate void
7570Sstevel@tonic-gate aio_cleanup(int flag)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	aio_t *aiop = curproc->p_aio;
7600Sstevel@tonic-gate 	aio_req_t *pollqhead, *cleanupqhead, *notifyqhead;
7610Sstevel@tonic-gate 	aio_req_t *cleanupport;
7620Sstevel@tonic-gate 	aio_req_t *portq = NULL;
7630Sstevel@tonic-gate 	void (*func)();
7640Sstevel@tonic-gate 	int signalled = 0;
7650Sstevel@tonic-gate 	int qflag = 0;
7660Sstevel@tonic-gate 	int exitflg;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	ASSERT(aiop != NULL);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (flag == AIO_CLEANUP_EXIT)
7710Sstevel@tonic-gate 		exitflg = AIO_CLEANUP_EXIT;
7720Sstevel@tonic-gate 	else
7730Sstevel@tonic-gate 		exitflg = 0;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/*
7760Sstevel@tonic-gate 	 * We need to get the aio_cleanupq_mutex because we are calling
7770Sstevel@tonic-gate 	 * aio_cleanup_cleanupq()
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	mutex_enter(&aiop->aio_cleanupq_mutex);
7800Sstevel@tonic-gate 	/*
7810Sstevel@tonic-gate 	 * take all the requests off the cleanupq, the notifyq,
7820Sstevel@tonic-gate 	 * and the pollq.
7830Sstevel@tonic-gate 	 */
7840Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
7850Sstevel@tonic-gate 	if ((cleanupqhead = aiop->aio_cleanupq) != NULL) {
7860Sstevel@tonic-gate 		aiop->aio_cleanupq = NULL;
7870Sstevel@tonic-gate 		qflag++;
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 	if ((notifyqhead = aiop->aio_notifyq) != NULL) {
7900Sstevel@tonic-gate 		aiop->aio_notifyq = NULL;
7910Sstevel@tonic-gate 		qflag++;
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 	if ((pollqhead = aiop->aio_pollq) != NULL) {
7940Sstevel@tonic-gate 		aiop->aio_pollq = NULL;
7950Sstevel@tonic-gate 		qflag++;
7960Sstevel@tonic-gate 	}
7970Sstevel@tonic-gate 	if (flag) {
7980Sstevel@tonic-gate 		if ((portq = aiop->aio_portq) != NULL)
7990Sstevel@tonic-gate 			qflag++;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 		if ((cleanupport = aiop->aio_portcleanupq) != NULL) {
8020Sstevel@tonic-gate 			aiop->aio_portcleanupq = NULL;
8030Sstevel@tonic-gate 			qflag++;
8040Sstevel@tonic-gate 		}
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * return immediately if cleanupq, pollq, and
8100Sstevel@tonic-gate 	 * notifyq are all empty. someone else must have
8110Sstevel@tonic-gate 	 * emptied them.
8120Sstevel@tonic-gate 	 */
8130Sstevel@tonic-gate 	if (!qflag) {
8140Sstevel@tonic-gate 		mutex_exit(&aiop->aio_cleanupq_mutex);
8150Sstevel@tonic-gate 		return;
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/*
8190Sstevel@tonic-gate 	 * do cleanup for the various queues.
8200Sstevel@tonic-gate 	 */
8210Sstevel@tonic-gate 	if (cleanupqhead)
8220Sstevel@tonic-gate 		aio_cleanup_cleanupq(aiop, cleanupqhead, exitflg);
8230Sstevel@tonic-gate 	mutex_exit(&aiop->aio_cleanupq_mutex);
8240Sstevel@tonic-gate 	if (notifyqhead)
8250Sstevel@tonic-gate 		signalled = aio_cleanup_notifyq(aiop, notifyqhead, exitflg);
8260Sstevel@tonic-gate 	if (pollqhead)
8270Sstevel@tonic-gate 		aio_cleanup_pollq(aiop, pollqhead, exitflg);
8280Sstevel@tonic-gate 	if (flag && (cleanupport || portq))
8290Sstevel@tonic-gate 		aio_cleanup_portq(aiop, cleanupport, exitflg);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	if (exitflg)
8320Sstevel@tonic-gate 		return;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	/*
8350Sstevel@tonic-gate 	 * If we have an active aio_cleanup_thread it's possible for
8360Sstevel@tonic-gate 	 * this routine to push something on to the done queue after
8370Sstevel@tonic-gate 	 * an aiowait/aiosuspend thread has already decided to block.
8380Sstevel@tonic-gate 	 * This being the case, we need a cv_broadcast here to wake
8390Sstevel@tonic-gate 	 * these threads up. It is simpler and cleaner to do this
8400Sstevel@tonic-gate 	 * broadcast here than in the individual cleanup routines.
8410Sstevel@tonic-gate 	 */
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
8440Sstevel@tonic-gate 	cv_broadcast(&aiop->aio_waitcv);
8450Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	/*
8480Sstevel@tonic-gate 	 * Only if the process wasn't already signalled,
8490Sstevel@tonic-gate 	 * determine if a SIGIO signal should be delievered.
8500Sstevel@tonic-gate 	 */
8510Sstevel@tonic-gate 	if (!signalled &&
8520Sstevel@tonic-gate 	    (func = curproc->p_user.u_signal[SIGIO - 1]) != SIG_DFL &&
8530Sstevel@tonic-gate 	    func != SIG_IGN)
8540Sstevel@tonic-gate 		psignal(curproc, SIGIO);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate /*
8590Sstevel@tonic-gate  * Do cleanup for every element of the port cleanup queue.
8600Sstevel@tonic-gate  */
8610Sstevel@tonic-gate static void
8620Sstevel@tonic-gate aio_cleanup_portq(aio_t *aiop, aio_req_t *cleanupq, int exitflag)
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate 	aio_req_t	*reqp;
8650Sstevel@tonic-gate 	aio_req_t	*next;
8660Sstevel@tonic-gate 	aio_req_t	*headp;
8670Sstevel@tonic-gate 	aio_req_t	*tailp;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	/* first check the portq */
8700Sstevel@tonic-gate 	if (exitflag || ((aiop->aio_flags & AIO_CLEANUP_PORT) == 0)) {
8710Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
8720Sstevel@tonic-gate 		if (aiop->aio_flags & AIO_CLEANUP)
8730Sstevel@tonic-gate 			aiop->aio_flags |= AIO_CLEANUP_PORT;
8740Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		mutex_enter(&aiop->aio_portq_mutex);
8770Sstevel@tonic-gate 		headp = aiop->aio_portq;
8780Sstevel@tonic-gate 		aiop->aio_portq = NULL;
8790Sstevel@tonic-gate 		mutex_exit(&aiop->aio_portq_mutex);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 		for (reqp = headp; reqp != NULL; reqp = next) {
8820Sstevel@tonic-gate 			tailp = reqp;
8830Sstevel@tonic-gate 			next = reqp->aio_req_next;
8840Sstevel@tonic-gate 			/*
8850Sstevel@tonic-gate 			 * It is not allowed to hold locks during
8860Sstevel@tonic-gate 			 * aphysio_unlock(). The aio_done() interrupt function
8870Sstevel@tonic-gate 			 * will try to acquire aio_mutex and aio_portq_mutex.
8880Sstevel@tonic-gate 			 */
8890Sstevel@tonic-gate 			aphysio_unlock(reqp);
8900Sstevel@tonic-gate 			if (exitflag) {
8910Sstevel@tonic-gate 				mutex_enter(&aiop->aio_mutex);
8920Sstevel@tonic-gate 				aio_req_free(aiop, reqp);
8930Sstevel@tonic-gate 				mutex_exit(&aiop->aio_mutex);
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		if (headp != NULL && exitflag == 0) {
8980Sstevel@tonic-gate 			/* move unlocked requests back to the done queue */
8990Sstevel@tonic-gate 			mutex_enter(&aiop->aio_portq_mutex);
9000Sstevel@tonic-gate 			if (aiop->aio_portq != NULL) {
9010Sstevel@tonic-gate 				tailp->aio_req_next = aiop->aio_portq;
9020Sstevel@tonic-gate 				aiop->aio_portq->aio_req_prev = tailp;
9030Sstevel@tonic-gate 			}
9040Sstevel@tonic-gate 			aiop->aio_portq = headp;
9050Sstevel@tonic-gate 			cv_broadcast(&aiop->aio_portcv);
9060Sstevel@tonic-gate 			mutex_exit(&aiop->aio_portq_mutex);
9070Sstevel@tonic-gate 		}
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/* now check the port cleanup queue */
9110Sstevel@tonic-gate 	for (reqp = cleanupq; reqp != NULL; reqp = next) {
9120Sstevel@tonic-gate #ifdef DEBUG
9130Sstevel@tonic-gate 		aio_checkset_flag(reqp, AIO_REQ_CLEAN, AIO_REQ_CLEAN);
9140Sstevel@tonic-gate #endif
9150Sstevel@tonic-gate 		next = reqp->aio_req_next;
9160Sstevel@tonic-gate 		aphysio_unlock(reqp);
9170Sstevel@tonic-gate 		if (exitflag) {
9180Sstevel@tonic-gate #ifdef DEBUG
9190Sstevel@tonic-gate 			aio_checkset_flag(reqp, AIO_REQ_CLEAN, AIO_REQ_FREE);
9200Sstevel@tonic-gate #endif
9210Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
9220Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
9230Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
9240Sstevel@tonic-gate 		} else {
9250Sstevel@tonic-gate 			mutex_enter(&aiop->aio_portq_mutex);
9260Sstevel@tonic-gate 			aio_enq_portq(aiop, reqp, 0);
9270Sstevel@tonic-gate 			mutex_exit(&aiop->aio_portq_mutex);
9280Sstevel@tonic-gate 			(void) port_send_event(reqp->aio_req_portkev);
9290Sstevel@tonic-gate 		}
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate  * Do cleanup for every element of the cleanupq.
9350Sstevel@tonic-gate  */
9360Sstevel@tonic-gate static void
9370Sstevel@tonic-gate aio_cleanup_cleanupq(aio_t *aiop, aio_req_t *qhead, int exitflg)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	aio_req_t *reqp, *next;
9400Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex));
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	/*
9430Sstevel@tonic-gate 	 * Since aio_req_done() or aio_req_find() use the HASH list to find
9440Sstevel@tonic-gate 	 * the required requests, they could potentially take away elements
9450Sstevel@tonic-gate 	 * if they are already done (AIO_DONEQ is set).
9460Sstevel@tonic-gate 	 * The aio_cleanupq_mutex protects the queue for the duration of the
9470Sstevel@tonic-gate 	 * loop from aio_req_done() and aio_req_find().
9480Sstevel@tonic-gate 	 */
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	qhead->aio_req_prev->aio_req_next = NULL;
9510Sstevel@tonic-gate 	for (reqp = qhead; reqp != NULL; reqp = next) {
9520Sstevel@tonic-gate 		ASSERT(reqp->aio_req_flags & AIO_CLEANUPQ);
9530Sstevel@tonic-gate 		next = reqp->aio_req_next;
9540Sstevel@tonic-gate 		aphysio_unlock(reqp);
9550Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
9560Sstevel@tonic-gate 		if (exitflg) {
9570Sstevel@tonic-gate 			/*
9580Sstevel@tonic-gate 			 * reqp can't be referenced after its freed
9590Sstevel@tonic-gate 			 */
9600Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
9610Sstevel@tonic-gate 		} else {
9620Sstevel@tonic-gate 			if (reqp->aio_req_portkev &&
9630Sstevel@tonic-gate 			    ((reqp->aio_req_flags & AIO_DONEQ) == 0)) {
9640Sstevel@tonic-gate 				aio_enq_doneq(aiop, reqp);
9650Sstevel@tonic-gate 				(void) port_send_event(reqp->aio_req_portkev);
9660Sstevel@tonic-gate 			} else {
9670Sstevel@tonic-gate 				aio_enq_doneq(aiop, reqp);
9680Sstevel@tonic-gate 			}
9690Sstevel@tonic-gate 		}
9700Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
9710Sstevel@tonic-gate 	}
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate /*
9750Sstevel@tonic-gate  * do cleanup for every element of the notify queue.
9760Sstevel@tonic-gate  */
9770Sstevel@tonic-gate static int
9780Sstevel@tonic-gate aio_cleanup_notifyq(aio_t *aiop, aio_req_t *qhead, int exitflg)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate 	aio_req_t *reqp, *next;
9810Sstevel@tonic-gate 	aio_lio_t *liohead;
9820Sstevel@tonic-gate 	sigqueue_t *sigev, *lio_sigev = NULL;
9830Sstevel@tonic-gate 	int signalled = 0;
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	qhead->aio_req_prev->aio_req_next = NULL;
9860Sstevel@tonic-gate 	for (reqp = qhead; reqp != NULL; reqp = next) {
9870Sstevel@tonic-gate 		ASSERT(reqp->aio_req_flags & AIO_NOTIFYQ);
9880Sstevel@tonic-gate 		next = reqp->aio_req_next;
9890Sstevel@tonic-gate 		aphysio_unlock(reqp);
9900Sstevel@tonic-gate 		if (exitflg) {
9910Sstevel@tonic-gate 			/* reqp cann't be referenced after its freed */
9920Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
9930Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
9940Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
9950Sstevel@tonic-gate 			continue;
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
9980Sstevel@tonic-gate 		aio_enq_doneq(aiop, reqp);
9990Sstevel@tonic-gate 		sigev = reqp->aio_req_sigqp;
10000Sstevel@tonic-gate 		reqp->aio_req_sigqp = NULL;
10010Sstevel@tonic-gate 		/* check if list IO completion notification is required */
10020Sstevel@tonic-gate 		if ((liohead = reqp->aio_req_lio) != NULL) {
10030Sstevel@tonic-gate 			ASSERT(liohead->lio_refcnt > 0);
10040Sstevel@tonic-gate 			if (--liohead->lio_refcnt == 0) {
10050Sstevel@tonic-gate 				cv_signal(&liohead->lio_notify);
10060Sstevel@tonic-gate 				lio_sigev = liohead->lio_sigqp;
10070Sstevel@tonic-gate 				liohead->lio_sigqp = NULL;
10080Sstevel@tonic-gate 			}
10090Sstevel@tonic-gate 		}
10100Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
10110Sstevel@tonic-gate 		if (sigev) {
10120Sstevel@tonic-gate 			signalled++;
10130Sstevel@tonic-gate 			aio_sigev_send(reqp->aio_req_buf.b_proc, sigev);
10140Sstevel@tonic-gate 		}
10150Sstevel@tonic-gate 		if (lio_sigev) {
10160Sstevel@tonic-gate 			signalled++;
10170Sstevel@tonic-gate 			aio_sigev_send(reqp->aio_req_buf.b_proc, lio_sigev);
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 	return (signalled);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate /*
10240Sstevel@tonic-gate  * Do cleanup for every element of the poll queue.
10250Sstevel@tonic-gate  */
10260Sstevel@tonic-gate static void
10270Sstevel@tonic-gate aio_cleanup_pollq(aio_t *aiop, aio_req_t *qhead, int exitflg)
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	aio_req_t *reqp, *next;
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	/*
10320Sstevel@tonic-gate 	 * As no other threads should be accessing the queue at this point,
10330Sstevel@tonic-gate 	 * it isn't necessary to hold aio_mutex while we traverse its elements.
10340Sstevel@tonic-gate 	 */
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	qhead->aio_req_prev->aio_req_next = NULL;
10370Sstevel@tonic-gate 	for (reqp = qhead; reqp != NULL; reqp = next) {
10380Sstevel@tonic-gate 		ASSERT(reqp->aio_req_flags & AIO_POLLQ);
10390Sstevel@tonic-gate 		next = reqp->aio_req_next;
10400Sstevel@tonic-gate 		aphysio_unlock(reqp);
10410Sstevel@tonic-gate 		if (exitflg) {
10420Sstevel@tonic-gate 			/* reqp cann't be referenced after its freed */
10430Sstevel@tonic-gate 			mutex_enter(&aiop->aio_mutex);
10440Sstevel@tonic-gate 			aio_req_free(aiop, reqp);
10450Sstevel@tonic-gate 			mutex_exit(&aiop->aio_mutex);
10460Sstevel@tonic-gate 			continue;
10470Sstevel@tonic-gate 		}
10480Sstevel@tonic-gate 		/* copy out request's result_t. */
10490Sstevel@tonic-gate 		aio_copyout_result(reqp);
10500Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
10510Sstevel@tonic-gate 		aio_enq_doneq(aiop, reqp);
10520Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate /*
10570Sstevel@tonic-gate  * called by exit(). waits for all outstanding kaio to finish
10580Sstevel@tonic-gate  * before the kaio resources are freed.
10590Sstevel@tonic-gate  */
10600Sstevel@tonic-gate void
10610Sstevel@tonic-gate aio_cleanup_exit(void)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	proc_t *p = curproc;
10640Sstevel@tonic-gate 	aio_t *aiop = p->p_aio;
10650Sstevel@tonic-gate 	aio_req_t *reqp, *next, *head;
10660Sstevel@tonic-gate 	aio_lio_t *nxtlio, *liop;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/*
10690Sstevel@tonic-gate 	 * wait for all outstanding kaio to complete. process
10700Sstevel@tonic-gate 	 * is now single-threaded; no other kaio requests can
10710Sstevel@tonic-gate 	 * happen once aio_pending is zero.
10720Sstevel@tonic-gate 	 */
10730Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
10740Sstevel@tonic-gate 	aiop->aio_flags |= AIO_CLEANUP;
10750Sstevel@tonic-gate 	while ((aiop->aio_pending != 0) || (aiop->aio_flags & AIO_DONE_ACTIVE))
10760Sstevel@tonic-gate 		cv_wait(&aiop->aio_cleanupcv, &aiop->aio_mutex);
10770Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	/* cleanup the cleanup-thread queues. */
10800Sstevel@tonic-gate 	aio_cleanup(AIO_CLEANUP_EXIT);
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	/*
10830Sstevel@tonic-gate 	 * Although this process is now single-threaded, we
10840Sstevel@tonic-gate 	 * still need to protect ourselves against a race with
10850Sstevel@tonic-gate 	 * aio_cleanup_dr_delete_memory().
10860Sstevel@tonic-gate 	 */
10870Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	/*
10900Sstevel@tonic-gate 	 * free up the done queue's resources.
10910Sstevel@tonic-gate 	 */
10920Sstevel@tonic-gate 	if ((head = aiop->aio_doneq) != NULL) {
10930Sstevel@tonic-gate 		head->aio_req_prev->aio_req_next = NULL;
10940Sstevel@tonic-gate 		for (reqp = head; reqp != NULL; reqp = next) {
10950Sstevel@tonic-gate 			next = reqp->aio_req_next;
10960Sstevel@tonic-gate 			aphysio_unlock(reqp);
10970Sstevel@tonic-gate 			kmem_free(reqp, sizeof (struct aio_req_t));
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 	/*
11010Sstevel@tonic-gate 	 * release aio request freelist.
11020Sstevel@tonic-gate 	 */
11030Sstevel@tonic-gate 	for (reqp = aiop->aio_free; reqp != NULL; reqp = next) {
11040Sstevel@tonic-gate 		next = reqp->aio_req_next;
11050Sstevel@tonic-gate 		kmem_free(reqp, sizeof (struct aio_req_t));
11060Sstevel@tonic-gate 	}
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	/*
11090Sstevel@tonic-gate 	 * release io list head freelist.
11100Sstevel@tonic-gate 	 */
11110Sstevel@tonic-gate 	for (liop = aiop->aio_lio_free; liop != NULL; liop = nxtlio) {
11120Sstevel@tonic-gate 		nxtlio = liop->lio_next;
11130Sstevel@tonic-gate 		kmem_free(liop, sizeof (aio_lio_t));
11140Sstevel@tonic-gate 	}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	if (aiop->aio_iocb)
11170Sstevel@tonic-gate 		kmem_free(aiop->aio_iocb, aiop->aio_iocbsz);
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	mutex_destroy(&aiop->aio_mutex);
11200Sstevel@tonic-gate 	mutex_destroy(&aiop->aio_portq_mutex);
11210Sstevel@tonic-gate 	mutex_destroy(&aiop->aio_cleanupq_mutex);
11220Sstevel@tonic-gate 	p->p_aio = NULL;
11230Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11240Sstevel@tonic-gate 	kmem_free(aiop, sizeof (struct aio));
11250Sstevel@tonic-gate }
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate /*
11280Sstevel@tonic-gate  * copy out aio request's result to a user-level result_t buffer.
11290Sstevel@tonic-gate  */
11300Sstevel@tonic-gate void
11310Sstevel@tonic-gate aio_copyout_result(aio_req_t *reqp)
11320Sstevel@tonic-gate {
11330Sstevel@tonic-gate 	struct buf	*bp;
11340Sstevel@tonic-gate 	struct iovec	*iov;
11350Sstevel@tonic-gate 	void		*resultp;
11360Sstevel@tonic-gate 	int		error;
11370Sstevel@tonic-gate 	size_t		retval;
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	if (reqp->aio_req_flags & AIO_COPYOUTDONE)
11400Sstevel@tonic-gate 		return;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	reqp->aio_req_flags |= AIO_COPYOUTDONE;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	iov = reqp->aio_req_uio.uio_iov;
11450Sstevel@tonic-gate 	bp = &reqp->aio_req_buf;
11460Sstevel@tonic-gate 	/* "resultp" points to user-level result_t buffer */
11470Sstevel@tonic-gate 	resultp = (void *)reqp->aio_req_resultp;
11480Sstevel@tonic-gate 	if (bp->b_flags & B_ERROR) {
11490Sstevel@tonic-gate 		if (bp->b_error)
11500Sstevel@tonic-gate 			error = bp->b_error;
11510Sstevel@tonic-gate 		else
11520Sstevel@tonic-gate 			error = EIO;
11530Sstevel@tonic-gate 		retval = (size_t)-1;
11540Sstevel@tonic-gate 	} else {
11550Sstevel@tonic-gate 		error = 0;
11560Sstevel@tonic-gate 		retval = iov->iov_len - bp->b_resid;
11570Sstevel@tonic-gate 	}
11580Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
11590Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
11600Sstevel@tonic-gate 		(void) sulword(&((aio_result_t *)resultp)->aio_return, retval);
11610Sstevel@tonic-gate 		(void) suword32(&((aio_result_t *)resultp)->aio_errno, error);
11620Sstevel@tonic-gate 	} else {
11630Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_return,
11640Sstevel@tonic-gate 		    (int)retval);
11650Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_errno, error);
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate #else
11680Sstevel@tonic-gate 	(void) suword32(&((aio_result_t *)resultp)->aio_return, retval);
11690Sstevel@tonic-gate 	(void) suword32(&((aio_result_t *)resultp)->aio_errno, error);
11700Sstevel@tonic-gate #endif
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate void
11750Sstevel@tonic-gate aio_copyout_result_port(struct iovec *iov, struct buf *bp, void *resultp)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	int errno;
11780Sstevel@tonic-gate 	size_t retval;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	if (bp->b_flags & B_ERROR) {
11810Sstevel@tonic-gate 		if (bp->b_error)
11820Sstevel@tonic-gate 			errno = bp->b_error;
11830Sstevel@tonic-gate 		else
11840Sstevel@tonic-gate 			errno = EIO;
11850Sstevel@tonic-gate 		retval = (size_t)-1;
11860Sstevel@tonic-gate 	} else {
11870Sstevel@tonic-gate 		errno = 0;
11880Sstevel@tonic-gate 		retval = iov->iov_len - bp->b_resid;
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
11910Sstevel@tonic-gate 	if (get_udatamodel() == DATAMODEL_NATIVE) {
11920Sstevel@tonic-gate 		(void) sulword(&((aio_result_t *)resultp)->aio_return, retval);
11930Sstevel@tonic-gate 		(void) suword32(&((aio_result_t *)resultp)->aio_errno, errno);
11940Sstevel@tonic-gate 	} else {
11950Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_return,
11960Sstevel@tonic-gate 		    (int)retval);
11970Sstevel@tonic-gate 		(void) suword32(&((aio_result32_t *)resultp)->aio_errno, errno);
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate #else
12000Sstevel@tonic-gate 	(void) suword32(&((aio_result_t *)resultp)->aio_return, retval);
12010Sstevel@tonic-gate 	(void) suword32(&((aio_result_t *)resultp)->aio_errno, errno);
12020Sstevel@tonic-gate #endif
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate /*
12060Sstevel@tonic-gate  * This function is used to remove a request from the done queue.
12070Sstevel@tonic-gate  */
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate void
12100Sstevel@tonic-gate aio_req_remove_portq(aio_t *aiop, aio_req_t *reqp)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&aiop->aio_portq_mutex));
12130Sstevel@tonic-gate 	while (aiop->aio_portq == NULL) {
12140Sstevel@tonic-gate 		/*
12150Sstevel@tonic-gate 		 * aio_portq is set to NULL when aio_cleanup_portq()
12160Sstevel@tonic-gate 		 * is working with the event queue.
12170Sstevel@tonic-gate 		 * The aio_cleanup_thread() uses aio_cleanup_portq()
12180Sstevel@tonic-gate 		 * to unlock all AIO buffers with completed transactions.
12190Sstevel@tonic-gate 		 * Wait here until aio_cleanup_portq() restores the
12200Sstevel@tonic-gate 		 * list of completed transactions in aio_portq.
12210Sstevel@tonic-gate 		 */
12220Sstevel@tonic-gate 		cv_wait(&aiop->aio_portcv, &aiop->aio_portq_mutex);
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 	if (reqp == aiop->aio_portq) {
12250Sstevel@tonic-gate 		/* first request in the queue */
12260Sstevel@tonic-gate 		aiop->aio_portq = reqp->aio_req_next;
12270Sstevel@tonic-gate 	} else {
12280Sstevel@tonic-gate 		reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
12290Sstevel@tonic-gate 		if (reqp->aio_req_next)
12300Sstevel@tonic-gate 			reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate /* ARGSUSED */
12350Sstevel@tonic-gate void
12360Sstevel@tonic-gate aio_close_port(void *arg, int port, pid_t pid, int lastclose)
12370Sstevel@tonic-gate {
12380Sstevel@tonic-gate 	aio_t		*aiop;
12390Sstevel@tonic-gate 	aio_req_t 	*reqp;
12400Sstevel@tonic-gate 	aio_req_t 	*next;
12410Sstevel@tonic-gate 	aio_req_t	*headp;
12420Sstevel@tonic-gate 	int		counter;
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	if (arg == NULL)
12450Sstevel@tonic-gate 		aiop = curproc->p_aio;
12460Sstevel@tonic-gate 	else
12470Sstevel@tonic-gate 		aiop = (aio_t *)arg;
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	/*
12500Sstevel@tonic-gate 	 * The PORT_SOURCE_AIO source is always associated with every new
12510Sstevel@tonic-gate 	 * created port by default.
12520Sstevel@tonic-gate 	 * If no asynchronous I/O transactions were associated with the port
12530Sstevel@tonic-gate 	 * then the aiop pointer will still be set to NULL.
12540Sstevel@tonic-gate 	 */
12550Sstevel@tonic-gate 	if (aiop == NULL)
12560Sstevel@tonic-gate 		return;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	/*
12590Sstevel@tonic-gate 	 * Within a process event ports can be used to collect events other
12600Sstevel@tonic-gate 	 * than PORT_SOURCE_AIO events. At the same time the process can submit
12610Sstevel@tonic-gate 	 * asynchronous I/Os transactions which are not associated with the
12620Sstevel@tonic-gate 	 * current port.
12630Sstevel@tonic-gate 	 * The current process oriented model of AIO uses a sigle queue for
12640Sstevel@tonic-gate 	 * pending events. On close the pending queue (queue of asynchronous
12650Sstevel@tonic-gate 	 * I/O transactions using event port notification) must be scanned
12660Sstevel@tonic-gate 	 * to detect and handle pending I/Os using the current port.
12670Sstevel@tonic-gate 	 */
12680Sstevel@tonic-gate 	mutex_enter(&aiop->aio_portq_mutex);
12690Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
12700Sstevel@tonic-gate 	reqp = aiop->aio_portpending;
12710Sstevel@tonic-gate 	for (counter = 0; reqp != NULL; reqp = reqp->aio_req_next) {
12720Sstevel@tonic-gate 		if (reqp->aio_req_portkev && (reqp->aio_req_port == port)) {
12730Sstevel@tonic-gate 			reqp->aio_req_flags |= AIO_CLOSE_PORT;
12740Sstevel@tonic-gate 			counter++;
12750Sstevel@tonic-gate 		}
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 	if (counter == 0) {
12780Sstevel@tonic-gate 		/* no AIOs pending */
12790Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
12800Sstevel@tonic-gate 		mutex_exit(&aiop->aio_portq_mutex);
12810Sstevel@tonic-gate 		return;
12820Sstevel@tonic-gate 	}
12830Sstevel@tonic-gate 	aiop->aio_portpendcnt += counter;
1284*41Spraks 	mutex_exit(&aiop->aio_mutex);
12850Sstevel@tonic-gate 	while (aiop->aio_portpendcnt)
1286*41Spraks 		cv_wait(&aiop->aio_portcv, &aiop->aio_portq_mutex);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	/*
12890Sstevel@tonic-gate 	 * all pending AIOs are completed.
12900Sstevel@tonic-gate 	 * check port doneq
12910Sstevel@tonic-gate 	 */
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	reqp = aiop->aio_portq;
12940Sstevel@tonic-gate 	headp = NULL;
12950Sstevel@tonic-gate 	for (; reqp != NULL; reqp = next) {
12960Sstevel@tonic-gate 		next = reqp->aio_req_next;
12970Sstevel@tonic-gate 		if (reqp->aio_req_port == port) {
12980Sstevel@tonic-gate 			/* discard event */
12990Sstevel@tonic-gate 			aio_req_remove_portq(aiop, reqp);
13000Sstevel@tonic-gate 			port_free_event(reqp->aio_req_portkev);
13010Sstevel@tonic-gate 			/* put request in temporary queue */
13020Sstevel@tonic-gate 			reqp->aio_req_next = headp;
13030Sstevel@tonic-gate 			headp = reqp;
13040Sstevel@tonic-gate 		}
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 	mutex_exit(&aiop->aio_portq_mutex);
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	/* headp points to the list of requests to be discarded */
13090Sstevel@tonic-gate 	for (reqp = headp; reqp != NULL; reqp = next) {
13100Sstevel@tonic-gate 		next = reqp->aio_req_next;
13110Sstevel@tonic-gate 		aphysio_unlock(reqp);
13120Sstevel@tonic-gate 		mutex_enter(&aiop->aio_mutex);
13130Sstevel@tonic-gate 		aio_req_free_port(aiop, reqp);
13140Sstevel@tonic-gate 		mutex_exit(&aiop->aio_mutex);
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	if (aiop->aio_flags & AIO_CLEANUP)
13180Sstevel@tonic-gate 		cv_broadcast(&aiop->aio_waitcv);
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate /*
13220Sstevel@tonic-gate  * aio_cleanup_dr_delete_memory is used by dr's delete_memory_thread
13230Sstevel@tonic-gate  * to force aio cleanup for a given process.  This is needed so that
13240Sstevel@tonic-gate  * delete_memory_thread can obtain writer locks on pages that need to
13250Sstevel@tonic-gate  * be relocated during a dr memory delete operation, otherwise a
13260Sstevel@tonic-gate  * deadly embrace may occur.
13270Sstevel@tonic-gate  * This implementation uses code from aio_cleanup_thread to move
13280Sstevel@tonic-gate  * entries from the doneq to the cleanupq; it also uses code from
13290Sstevel@tonic-gate  * aio_cleanup to cleanup the various queues and to signal the process's
13300Sstevel@tonic-gate  * aio_cleanup_thread.
13310Sstevel@tonic-gate  * Returns: non-zero if aio cleanup occurred, otherwise 0 is returned.
13320Sstevel@tonic-gate  */
13330Sstevel@tonic-gate int
13340Sstevel@tonic-gate aio_cleanup_dr_delete_memory(proc_t *procp)
13350Sstevel@tonic-gate {
13360Sstevel@tonic-gate 	aio_req_t *cleanupqhead, *notifyqhead;
13370Sstevel@tonic-gate 	aio_req_t *cleanupport;
13380Sstevel@tonic-gate 	aio_req_t *portq;
13390Sstevel@tonic-gate 	int qflag;
13400Sstevel@tonic-gate 	void (*func)();
13410Sstevel@tonic-gate 	int signalled = 0;
13420Sstevel@tonic-gate 	struct aio *aiop = procp->p_aio;
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&procp->p_lock));
13450Sstevel@tonic-gate 	ASSERT(aiop != NULL);
13460Sstevel@tonic-gate 	qflag = 0;
13470Sstevel@tonic-gate 	/*
13480Sstevel@tonic-gate 	 * we need to get aio_cleanupq_mutex.
13490Sstevel@tonic-gate 	 */
13500Sstevel@tonic-gate 	mutex_enter(&aiop->aio_cleanupq_mutex);
13510Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
13520Sstevel@tonic-gate 	/*
13530Sstevel@tonic-gate 	 * do aio cleanup for this process, this code was shamelessly
13540Sstevel@tonic-gate 	 * stolen from aio_cleanup_thread and aio_cleanup
13550Sstevel@tonic-gate 	 */
13560Sstevel@tonic-gate 	if (aiop->aio_doneq) {
13570Sstevel@tonic-gate 		/* move doneq's aio_req_t's to cleanupq */
13580Sstevel@tonic-gate 		aio_req_t *doneqhead = aiop->aio_doneq;
13590Sstevel@tonic-gate 		aiop->aio_doneq = NULL;
13600Sstevel@tonic-gate 		aio_cleanupq_concat(aiop, doneqhead, AIO_DONEQ);
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 	/*
13630Sstevel@tonic-gate 	 * take all the requests off the cleanupq, the notifyq,
13640Sstevel@tonic-gate 	 * and the event port queues (aio_portq and
13650Sstevel@tonic-gate 	 * aio_portcleanupq).  we cannot process the pollq from
13660Sstevel@tonic-gate 	 * a kernel thread that has an invalid secondary context,
13670Sstevel@tonic-gate 	 * as aio_copyout_result requires the secondary context
13680Sstevel@tonic-gate 	 * to be a valid user context.
13690Sstevel@tonic-gate 	 */
13700Sstevel@tonic-gate 	if ((cleanupqhead = aiop->aio_cleanupq) != NULL) {
13710Sstevel@tonic-gate 		aiop->aio_cleanupq = NULL;
13720Sstevel@tonic-gate 		qflag++;
13730Sstevel@tonic-gate 	}
13740Sstevel@tonic-gate 	if ((notifyqhead = aiop->aio_notifyq) != NULL) {
13750Sstevel@tonic-gate 		aiop->aio_notifyq = NULL;
13760Sstevel@tonic-gate 		qflag++;
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 	if ((portq = aiop->aio_portq) != NULL)
13790Sstevel@tonic-gate 		qflag++;
13800Sstevel@tonic-gate 	if ((cleanupport = aiop->aio_portcleanupq) != NULL) {
13810Sstevel@tonic-gate 		aiop->aio_portcleanupq = NULL;
13820Sstevel@tonic-gate 		qflag++;
13830Sstevel@tonic-gate 	}
13840Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
13850Sstevel@tonic-gate 	/*
13860Sstevel@tonic-gate 	 * return immediately if cleanupq and
13870Sstevel@tonic-gate 	 * notifyq are all empty. someone else must have
13880Sstevel@tonic-gate 	 * emptied them.
13890Sstevel@tonic-gate 	 */
13900Sstevel@tonic-gate 	if (!qflag) {
13910Sstevel@tonic-gate 		mutex_exit(&aiop->aio_cleanupq_mutex);
13920Sstevel@tonic-gate 		return (0);
13930Sstevel@tonic-gate 	}
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	/*
13960Sstevel@tonic-gate 	 * do cleanup for the various queues.
13970Sstevel@tonic-gate 	 */
13980Sstevel@tonic-gate 	if (cleanupqhead)
13990Sstevel@tonic-gate 		aio_cleanup_cleanupq(aiop, cleanupqhead, 0);
14000Sstevel@tonic-gate 	mutex_exit(&aiop->aio_cleanupq_mutex);
14010Sstevel@tonic-gate 	if (notifyqhead)
14020Sstevel@tonic-gate 		signalled = aio_cleanup_notifyq(aiop, notifyqhead, 0);
14030Sstevel@tonic-gate 	if (cleanupport || portq)
14040Sstevel@tonic-gate 		aio_cleanup_portq(aiop, cleanupport, 0);
14050Sstevel@tonic-gate 	/*
14060Sstevel@tonic-gate 	 * If we have an active aio_cleanup_thread it's possible for
14070Sstevel@tonic-gate 	 * this routine to push something on to the done queue after
14080Sstevel@tonic-gate 	 * an aiowait/aiosuspend thread has already decided to block.
14090Sstevel@tonic-gate 	 * This being the case, we need a cv_broadcast here to wake
14100Sstevel@tonic-gate 	 * these threads up. It is simpler and cleaner to do this
14110Sstevel@tonic-gate 	 * broadcast here than in the individual cleanup routines.
14120Sstevel@tonic-gate 	 */
14130Sstevel@tonic-gate 	mutex_enter(&aiop->aio_mutex);
14140Sstevel@tonic-gate 	/* also re-enable aio requests */
14150Sstevel@tonic-gate 	cv_broadcast(&aiop->aio_waitcv);
14160Sstevel@tonic-gate 	mutex_exit(&aiop->aio_mutex);
14170Sstevel@tonic-gate 	/*
14180Sstevel@tonic-gate 	 * Only if the process wasn't already signalled,
14190Sstevel@tonic-gate 	 * determine if a SIGIO signal should be delievered.
14200Sstevel@tonic-gate 	 */
14210Sstevel@tonic-gate 	if (!signalled &&
14220Sstevel@tonic-gate 	    (func = procp->p_user.u_signal[SIGIO - 1]) != SIG_DFL &&
14230Sstevel@tonic-gate 	    func != SIG_IGN)
14240Sstevel@tonic-gate 		sigtoproc(procp, NULL, SIGIO);
14250Sstevel@tonic-gate 	return (qflag);
14260Sstevel@tonic-gate }
1427