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
51885Sraf * Common Development and Distribution License (the "License").
61885Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211885Sraf
220Sstevel@tonic-gate /*
239973SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/proc.h>
290Sstevel@tonic-gate #include <sys/file.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <vm/as.h>
360Sstevel@tonic-gate #include <vm/page.h>
370Sstevel@tonic-gate #include <sys/uio.h>
380Sstevel@tonic-gate #include <sys/kmem.h>
390Sstevel@tonic-gate #include <sys/debug.h>
400Sstevel@tonic-gate #include <sys/aio_impl.h>
410Sstevel@tonic-gate #include <sys/epm.h>
420Sstevel@tonic-gate #include <sys/fs/snode.h>
430Sstevel@tonic-gate #include <sys/siginfo.h>
440Sstevel@tonic-gate #include <sys/cpuvar.h>
450Sstevel@tonic-gate #include <sys/tnf_probe.h>
460Sstevel@tonic-gate #include <sys/conf.h>
470Sstevel@tonic-gate #include <sys/sdt.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate int aphysio(int (*)(), int (*)(), dev_t, int, void (*)(), struct aio_req *);
500Sstevel@tonic-gate void aio_done(struct buf *);
510Sstevel@tonic-gate void aphysio_unlock(aio_req_t *);
520Sstevel@tonic-gate void aio_cleanup(int);
530Sstevel@tonic-gate void aio_cleanup_exit(void);
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * private functions
570Sstevel@tonic-gate */
580Sstevel@tonic-gate static void aio_sigev_send(proc_t *, sigqueue_t *);
590Sstevel@tonic-gate static void aio_hash_delete(aio_t *, aio_req_t *);
600Sstevel@tonic-gate static void aio_lio_free(aio_t *, aio_lio_t *);
619973SSurya.Prakki@Sun.COM static int aio_cleanup_cleanupq(aio_t *, aio_req_t *, int);
620Sstevel@tonic-gate static int aio_cleanup_notifyq(aio_t *, aio_req_t *, int);
630Sstevel@tonic-gate static void aio_cleanup_pollq(aio_t *, aio_req_t *, int);
640Sstevel@tonic-gate static void aio_cleanup_portq(aio_t *, aio_req_t *, int);
650Sstevel@tonic-gate
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate * async version of physio() that doesn't wait synchronously
680Sstevel@tonic-gate * for the driver's strategy routine to complete.
690Sstevel@tonic-gate */
700Sstevel@tonic-gate
710Sstevel@tonic-gate int
aphysio(int (* strategy)(struct buf *),int (* cancel)(struct buf *),dev_t dev,int rw,void (* mincnt)(struct buf *),struct aio_req * aio)720Sstevel@tonic-gate aphysio(
730Sstevel@tonic-gate int (*strategy)(struct buf *),
740Sstevel@tonic-gate int (*cancel)(struct buf *),
750Sstevel@tonic-gate dev_t dev,
760Sstevel@tonic-gate int rw,
770Sstevel@tonic-gate void (*mincnt)(struct buf *),
780Sstevel@tonic-gate struct aio_req *aio)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate struct uio *uio = aio->aio_uio;
810Sstevel@tonic-gate aio_req_t *reqp = (aio_req_t *)aio->aio_private;
820Sstevel@tonic-gate struct buf *bp = &reqp->aio_req_buf;
830Sstevel@tonic-gate struct iovec *iov;
840Sstevel@tonic-gate struct as *as;
850Sstevel@tonic-gate char *a;
860Sstevel@tonic-gate int error;
870Sstevel@tonic-gate size_t c;
880Sstevel@tonic-gate struct page **pplist;
890Sstevel@tonic-gate struct dev_ops *ops = devopsp[getmajor(dev)];
900Sstevel@tonic-gate
910Sstevel@tonic-gate if (uio->uio_loffset < 0)
920Sstevel@tonic-gate return (EINVAL);
930Sstevel@tonic-gate #ifdef _ILP32
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * For 32-bit kernels, check against SPEC_MAXOFFSET_T which represents
960Sstevel@tonic-gate * the maximum size that can be supported by the IO subsystem.
970Sstevel@tonic-gate * XXX this code assumes a D_64BIT driver.
980Sstevel@tonic-gate */
990Sstevel@tonic-gate if (uio->uio_loffset > SPEC_MAXOFFSET_T)
1000Sstevel@tonic-gate return (EINVAL);
1010Sstevel@tonic-gate #endif /* _ILP32 */
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate TNF_PROBE_5(aphysio_start, "kaio", /* CSTYLED */,
1049973SSurya.Prakki@Sun.COM tnf_opaque, bp, bp,
1059973SSurya.Prakki@Sun.COM tnf_device, device, dev,
1069973SSurya.Prakki@Sun.COM tnf_offset, blkno, btodt(uio->uio_loffset),
1079973SSurya.Prakki@Sun.COM tnf_size, size, uio->uio_iov->iov_len,
1089973SSurya.Prakki@Sun.COM tnf_bioflags, rw, rw);
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate if (rw == B_READ) {
1110Sstevel@tonic-gate CPU_STATS_ADD_K(sys, phread, 1);
1120Sstevel@tonic-gate } else {
1130Sstevel@tonic-gate CPU_STATS_ADD_K(sys, phwrite, 1);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate iov = uio->uio_iov;
1170Sstevel@tonic-gate sema_init(&bp->b_sem, 0, NULL, SEMA_DEFAULT, NULL);
1180Sstevel@tonic-gate sema_init(&bp->b_io, 0, NULL, SEMA_DEFAULT, NULL);
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate bp->b_error = 0;
1210Sstevel@tonic-gate bp->b_flags = B_BUSY | B_PHYS | B_ASYNC | rw;
1220Sstevel@tonic-gate bp->b_edev = dev;
1230Sstevel@tonic-gate bp->b_dev = cmpdev(dev);
1240Sstevel@tonic-gate bp->b_lblkno = btodt(uio->uio_loffset);
1250Sstevel@tonic-gate bp->b_offset = uio->uio_loffset;
1260Sstevel@tonic-gate (void) ops->devo_getinfo(NULL, DDI_INFO_DEVT2DEVINFO,
1270Sstevel@tonic-gate (void *)bp->b_edev, (void **)&bp->b_dip);
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate * Clustering: Clustering can set the b_iodone, b_forw and
1310Sstevel@tonic-gate * b_proc fields to cluster-specifc values.
1320Sstevel@tonic-gate */
1330Sstevel@tonic-gate if (bp->b_iodone == NULL) {
1340Sstevel@tonic-gate bp->b_iodone = (int (*)()) aio_done;
1350Sstevel@tonic-gate /* b_forw points at an aio_req_t structure */
1360Sstevel@tonic-gate bp->b_forw = (struct buf *)reqp;
1370Sstevel@tonic-gate bp->b_proc = curproc;
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate a = bp->b_un.b_addr = iov->iov_base;
1410Sstevel@tonic-gate c = bp->b_bcount = iov->iov_len;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate (*mincnt)(bp);
1440Sstevel@tonic-gate if (bp->b_bcount != iov->iov_len)
1450Sstevel@tonic-gate return (ENOTSUP);
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate as = bp->b_proc->p_as;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate error = as_pagelock(as, &pplist, a,
1500Sstevel@tonic-gate c, rw == B_READ? S_WRITE : S_READ);
1510Sstevel@tonic-gate if (error != 0) {
1520Sstevel@tonic-gate bp->b_flags |= B_ERROR;
1530Sstevel@tonic-gate bp->b_error = error;
1540Sstevel@tonic-gate bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_SHADOW);
1550Sstevel@tonic-gate return (error);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate reqp->aio_req_flags |= AIO_PAGELOCKDONE;
1580Sstevel@tonic-gate bp->b_shadow = pplist;
1590Sstevel@tonic-gate if (pplist != NULL) {
1600Sstevel@tonic-gate bp->b_flags |= B_SHADOW;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate if (cancel != anocancel)
1640Sstevel@tonic-gate cmn_err(CE_PANIC,
1650Sstevel@tonic-gate "aphysio: cancellation not supported, use anocancel");
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate reqp->aio_req_cancel = cancel;
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate DTRACE_IO1(start, struct buf *, bp);
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate return ((*strategy)(bp));
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*ARGSUSED*/
1750Sstevel@tonic-gate int
anocancel(struct buf * bp)1760Sstevel@tonic-gate anocancel(struct buf *bp)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate return (ENXIO);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate * Called from biodone().
1830Sstevel@tonic-gate * Notify process that a pending AIO has finished.
1840Sstevel@tonic-gate */
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * Clustering: This function is made non-static as it is used
1880Sstevel@tonic-gate * by clustering s/w as contract private interface.
1890Sstevel@tonic-gate */
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate void
aio_done(struct buf * bp)1920Sstevel@tonic-gate aio_done(struct buf *bp)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate proc_t *p;
1950Sstevel@tonic-gate struct as *as;
1960Sstevel@tonic-gate aio_req_t *reqp;
1971885Sraf aio_lio_t *head = NULL;
1980Sstevel@tonic-gate aio_t *aiop;
1991885Sraf sigqueue_t *sigev = NULL;
2000Sstevel@tonic-gate sigqueue_t *lio_sigev = NULL;
2011885Sraf port_kevent_t *pkevp = NULL;
2021885Sraf port_kevent_t *lio_pkevp = NULL;
2030Sstevel@tonic-gate int fd;
2040Sstevel@tonic-gate int cleanupqflag;
2050Sstevel@tonic-gate int pollqflag;
2060Sstevel@tonic-gate int portevpend;
2070Sstevel@tonic-gate void (*func)();
2081885Sraf int use_port = 0;
2094532Ssp92102 int reqp_flags = 0;
21010620SSurya.Prakki@Sun.COM int send_signal = 0;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate p = bp->b_proc;
2134532Ssp92102 as = p->p_as;
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 */,
2189973SSurya.Prakki@Sun.COM tnf_opaque, bp, bp,
2199973SSurya.Prakki@Sun.COM tnf_device, device, bp->b_edev,
2209973SSurya.Prakki@Sun.COM tnf_offset, blkno, btodt(reqp->aio_req_uio.uio_loffset),
2219973SSurya.Prakki@Sun.COM tnf_size, size, reqp->aio_req_uio.uio_iov->iov_len,
2229973SSurya.Prakki@Sun.COM 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
2371885Sraf mutex_enter(&aiop->aio_portq_mutex);
2381885Sraf mutex_enter(&aiop->aio_mutex);
2391885Sraf ASSERT(aiop->aio_pending > 0);
2401885Sraf ASSERT(reqp->aio_req_flags & AIO_PENDING);
2411885Sraf aiop->aio_pending--;
2421885Sraf reqp->aio_req_flags &= ~AIO_PENDING;
2434532Ssp92102 reqp_flags = reqp->aio_req_flags;
2441885Sraf if ((pkevp = reqp->aio_req_portkev) != NULL) {
2450Sstevel@tonic-gate /* Event port notification is desired for this transaction */
2460Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_CLOSE_PORT) {
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * The port is being closed and it is waiting for
2490Sstevel@tonic-gate * pending asynchronous I/O transactions to complete.
2500Sstevel@tonic-gate */
2510Sstevel@tonic-gate portevpend = --aiop->aio_portpendcnt;
2521885Sraf aio_deq(&aiop->aio_portpending, reqp);
2531885Sraf aio_enq(&aiop->aio_portq, reqp, 0);
2540Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
2550Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
2561885Sraf port_send_event(pkevp);
2570Sstevel@tonic-gate if (portevpend == 0)
2580Sstevel@tonic-gate cv_broadcast(&aiop->aio_portcv);
2590Sstevel@tonic-gate return;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate if (aiop->aio_flags & AIO_CLEANUP) {
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * aio_cleanup_thread() is waiting for completion of
2650Sstevel@tonic-gate * transactions.
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate mutex_enter(&as->a_contents);
2681885Sraf aio_deq(&aiop->aio_portpending, reqp);
2691885Sraf aio_enq(&aiop->aio_portcleanupq, reqp, 0);
2700Sstevel@tonic-gate cv_signal(&aiop->aio_cleanupcv);
2710Sstevel@tonic-gate mutex_exit(&as->a_contents);
2720Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
2730Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
2740Sstevel@tonic-gate return;
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2771885Sraf aio_deq(&aiop->aio_portpending, reqp);
2781885Sraf aio_enq(&aiop->aio_portq, reqp, 0);
2790Sstevel@tonic-gate
2801885Sraf use_port = 1;
2811885Sraf } else {
2821885Sraf /*
2831885Sraf * when the AIO_CLEANUP flag is enabled for this
2841885Sraf * process, or when the AIO_POLL bit is set for
2851885Sraf * this request, special handling is required.
2861885Sraf * otherwise the request is put onto the doneq.
2871885Sraf */
2881885Sraf cleanupqflag = (aiop->aio_flags & AIO_CLEANUP);
2891885Sraf pollqflag = (reqp->aio_req_flags & AIO_POLL);
2901885Sraf if (cleanupqflag | pollqflag) {
2911885Sraf
2924532Ssp92102 if (cleanupqflag)
2931885Sraf mutex_enter(&as->a_contents);
2940Sstevel@tonic-gate
2951885Sraf /*
2961885Sraf * requests with their AIO_POLL bit set are put
2971885Sraf * on the pollq, requests with sigevent structures
2981885Sraf * or with listio heads are put on the notifyq, and
2991885Sraf * the remaining requests don't require any special
3001885Sraf * cleanup handling, so they're put onto the default
3011885Sraf * cleanupq.
3021885Sraf */
3031885Sraf if (pollqflag)
3041885Sraf aio_enq(&aiop->aio_pollq, reqp, AIO_POLLQ);
3051885Sraf else if (reqp->aio_req_sigqp || reqp->aio_req_lio)
3061885Sraf aio_enq(&aiop->aio_notifyq, reqp, AIO_NOTIFYQ);
3071885Sraf else
3081885Sraf aio_enq(&aiop->aio_cleanupq, reqp,
3091885Sraf AIO_CLEANUPQ);
3100Sstevel@tonic-gate
3111885Sraf if (cleanupqflag) {
3121885Sraf cv_signal(&aiop->aio_cleanupcv);
3131885Sraf mutex_exit(&as->a_contents);
3141885Sraf mutex_exit(&aiop->aio_mutex);
3151885Sraf mutex_exit(&aiop->aio_portq_mutex);
3161885Sraf } else {
3171885Sraf ASSERT(pollqflag);
3181885Sraf /* block aio_cleanup_exit until we're done */
3191885Sraf aiop->aio_flags |= AIO_DONE_ACTIVE;
3201885Sraf mutex_exit(&aiop->aio_mutex);
3211885Sraf mutex_exit(&aiop->aio_portq_mutex);
3221885Sraf /*
3231885Sraf * let the cleanup processing happen from an AST
3241885Sraf * set an AST on all threads in this process
3251885Sraf */
3261885Sraf mutex_enter(&p->p_lock);
3271885Sraf set_proc_ast(p);
3281885Sraf mutex_exit(&p->p_lock);
3291885Sraf mutex_enter(&aiop->aio_mutex);
3301885Sraf /* wakeup anybody waiting in aiowait() */
3311885Sraf cv_broadcast(&aiop->aio_waitcv);
3321885Sraf
3331885Sraf /* wakeup aio_cleanup_exit if needed */
3341885Sraf if (aiop->aio_flags & AIO_CLEANUP)
3351885Sraf cv_signal(&aiop->aio_cleanupcv);
3361885Sraf aiop->aio_flags &= ~AIO_DONE_ACTIVE;
3371885Sraf mutex_exit(&aiop->aio_mutex);
3381885Sraf }
3391885Sraf return;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate /*
3431885Sraf * save req's sigevent pointer, and check its
3441885Sraf * value after releasing aio_mutex lock.
3450Sstevel@tonic-gate */
3461885Sraf sigev = reqp->aio_req_sigqp;
3471885Sraf reqp->aio_req_sigqp = NULL;
3480Sstevel@tonic-gate
3491885Sraf /* put request on done queue. */
3501885Sraf aio_enq(&aiop->aio_doneq, reqp, AIO_DONEQ);
3511885Sraf } /* portkevent */
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate /*
3541885Sraf * when list IO notification is enabled, a notification or
3551885Sraf * signal is sent only when all entries in the list are done.
3560Sstevel@tonic-gate */
3570Sstevel@tonic-gate if ((head = reqp->aio_req_lio) != NULL) {
3580Sstevel@tonic-gate ASSERT(head->lio_refcnt > 0);
3590Sstevel@tonic-gate if (--head->lio_refcnt == 0) {
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * save lio's sigevent pointer, and check
3621885Sraf * its value after releasing aio_mutex lock.
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate lio_sigev = head->lio_sigqp;
3650Sstevel@tonic-gate head->lio_sigqp = NULL;
3661885Sraf cv_signal(&head->lio_notify);
3671885Sraf if (head->lio_port >= 0 &&
3681885Sraf (lio_pkevp = head->lio_portkev) != NULL)
3691885Sraf head->lio_port = -1;
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate * if AIO_WAITN set then
3750Sstevel@tonic-gate * send signal only when we reached the
3760Sstevel@tonic-gate * required amount of IO's finished
3770Sstevel@tonic-gate * or when all IO's are done
3780Sstevel@tonic-gate */
3790Sstevel@tonic-gate if (aiop->aio_flags & AIO_WAITN) {
3800Sstevel@tonic-gate if (aiop->aio_waitncnt > 0)
3810Sstevel@tonic-gate aiop->aio_waitncnt--;
3820Sstevel@tonic-gate if (aiop->aio_pending == 0 ||
3830Sstevel@tonic-gate aiop->aio_waitncnt == 0)
3840Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv);
3850Sstevel@tonic-gate } else {
3860Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
38910620SSurya.Prakki@Sun.COM /*
39010620SSurya.Prakki@Sun.COM * No need to set this flag for pollq, portq, lio requests.
391*10719SRoger.Faulkner@Sun.COM * If this is an old Solaris aio request, and the process has
392*10719SRoger.Faulkner@Sun.COM * a SIGIO signal handler enabled, then send a SIGIO signal.
39310620SSurya.Prakki@Sun.COM */
39410620SSurya.Prakki@Sun.COM if (!sigev && !use_port && head == NULL &&
395*10719SRoger.Faulkner@Sun.COM (reqp->aio_req_flags & AIO_SOLARIS) &&
39610620SSurya.Prakki@Sun.COM (func = PTOU(p)->u_signal[SIGIO - 1]) != SIG_DFL &&
39710620SSurya.Prakki@Sun.COM (func != SIG_IGN)) {
39810620SSurya.Prakki@Sun.COM send_signal = 1;
39910620SSurya.Prakki@Sun.COM reqp->aio_req_flags |= AIO_SIGNALLED;
40010620SSurya.Prakki@Sun.COM }
40110620SSurya.Prakki@Sun.COM
4020Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
4031885Sraf mutex_exit(&aiop->aio_portq_mutex);
4041885Sraf
4054532Ssp92102 /*
4064532Ssp92102 * Could the cleanup thread be waiting for AIO with locked
4074532Ssp92102 * resources to finish?
4084532Ssp92102 * Ideally in that case cleanup thread should block on cleanupcv,
4094532Ssp92102 * but there is a window, where it could miss to see a new aio
4104532Ssp92102 * request that sneaked in.
4114532Ssp92102 */
4124532Ssp92102 mutex_enter(&as->a_contents);
4134532Ssp92102 if ((reqp_flags & AIO_PAGELOCKDONE) && AS_ISUNMAPWAIT(as))
4144532Ssp92102 cv_broadcast(&as->a_cv);
4154532Ssp92102 mutex_exit(&as->a_contents);
4164532Ssp92102
4170Sstevel@tonic-gate if (sigev)
4180Sstevel@tonic-gate aio_sigev_send(p, sigev);
41910620SSurya.Prakki@Sun.COM else if (send_signal)
42010620SSurya.Prakki@Sun.COM psignal(p, SIGIO);
42110620SSurya.Prakki@Sun.COM
4221885Sraf if (pkevp)
4231885Sraf port_send_event(pkevp);
4241885Sraf if (lio_sigev)
4251885Sraf aio_sigev_send(p, lio_sigev);
4261885Sraf if (lio_pkevp)
4271885Sraf port_send_event(lio_pkevp);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate * send a queued signal to the specified process when
4320Sstevel@tonic-gate * the event signal is non-NULL. A return value of 1
4330Sstevel@tonic-gate * will indicate that a signal is queued, and 0 means that
4340Sstevel@tonic-gate * no signal was specified, nor sent.
4350Sstevel@tonic-gate */
4360Sstevel@tonic-gate static void
aio_sigev_send(proc_t * p,sigqueue_t * sigev)4370Sstevel@tonic-gate aio_sigev_send(proc_t *p, sigqueue_t *sigev)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate ASSERT(sigev != NULL);
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate mutex_enter(&p->p_lock);
4420Sstevel@tonic-gate sigaddqa(p, NULL, sigev);
4430Sstevel@tonic-gate mutex_exit(&p->p_lock);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate * special case handling for zero length requests. the aio request
4480Sstevel@tonic-gate * short circuits the normal completion path since all that's required
4490Sstevel@tonic-gate * to complete this request is to copyout a zero to the aio request's
4500Sstevel@tonic-gate * return value.
4510Sstevel@tonic-gate */
4520Sstevel@tonic-gate void
aio_zerolen(aio_req_t * reqp)4530Sstevel@tonic-gate aio_zerolen(aio_req_t *reqp)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate struct buf *bp = &reqp->aio_req_buf;
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate reqp->aio_req_flags |= AIO_ZEROLEN;
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate bp->b_forw = (struct buf *)reqp;
4610Sstevel@tonic-gate bp->b_proc = curproc;
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate bp->b_resid = 0;
4640Sstevel@tonic-gate bp->b_flags = 0;
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate aio_done(bp);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * unlock pages previously locked by as_pagelock
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate void
aphysio_unlock(aio_req_t * reqp)4730Sstevel@tonic-gate aphysio_unlock(aio_req_t *reqp)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate struct buf *bp;
4760Sstevel@tonic-gate struct iovec *iov;
4770Sstevel@tonic-gate int flags;
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_PHYSIODONE)
4800Sstevel@tonic-gate return;
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate reqp->aio_req_flags |= AIO_PHYSIODONE;
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_ZEROLEN)
4850Sstevel@tonic-gate return;
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate bp = &reqp->aio_req_buf;
4880Sstevel@tonic-gate iov = reqp->aio_req_uio.uio_iov;
4890Sstevel@tonic-gate flags = (((bp->b_flags & B_READ) == B_READ) ? S_WRITE : S_READ);
4900Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_PAGELOCKDONE) {
4910Sstevel@tonic-gate as_pageunlock(bp->b_proc->p_as,
4929973SSurya.Prakki@Sun.COM bp->b_flags & B_SHADOW ? bp->b_shadow : NULL,
4939973SSurya.Prakki@Sun.COM iov->iov_base, iov->iov_len, flags);
4940Sstevel@tonic-gate reqp->aio_req_flags &= ~AIO_PAGELOCKDONE;
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_SHADOW);
4970Sstevel@tonic-gate bp->b_flags |= B_DONE;
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate /*
5011885Sraf * deletes a requests id from the hash table of outstanding io.
5020Sstevel@tonic-gate */
5030Sstevel@tonic-gate static void
aio_hash_delete(aio_t * aiop,struct aio_req_t * reqp)5041885Sraf aio_hash_delete(aio_t *aiop, struct aio_req_t *reqp)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate long index;
5070Sstevel@tonic-gate aio_result_t *resultp = reqp->aio_req_resultp;
5080Sstevel@tonic-gate aio_req_t *current;
5090Sstevel@tonic-gate aio_req_t **nextp;
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate index = AIO_HASH(resultp);
5120Sstevel@tonic-gate nextp = (aiop->aio_hash + index);
5130Sstevel@tonic-gate while ((current = *nextp) != NULL) {
5140Sstevel@tonic-gate if (current->aio_req_resultp == resultp) {
5150Sstevel@tonic-gate *nextp = current->aio_hash_next;
5160Sstevel@tonic-gate return;
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate nextp = ¤t->aio_hash_next;
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /*
5230Sstevel@tonic-gate * Put a list head struct onto its free list.
5240Sstevel@tonic-gate */
5250Sstevel@tonic-gate static void
aio_lio_free(aio_t * aiop,aio_lio_t * head)5260Sstevel@tonic-gate aio_lio_free(aio_t *aiop, aio_lio_t *head)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate if (head->lio_sigqp != NULL)
5310Sstevel@tonic-gate kmem_free(head->lio_sigqp, sizeof (sigqueue_t));
5320Sstevel@tonic-gate head->lio_next = aiop->aio_lio_free;
5330Sstevel@tonic-gate aiop->aio_lio_free = head;
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate
5360Sstevel@tonic-gate /*
5370Sstevel@tonic-gate * Put a reqp onto the freelist.
5380Sstevel@tonic-gate */
5390Sstevel@tonic-gate void
aio_req_free(aio_t * aiop,aio_req_t * reqp)5400Sstevel@tonic-gate aio_req_free(aio_t *aiop, aio_req_t *reqp)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate aio_lio_t *liop;
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate if (reqp->aio_req_portkev) {
5470Sstevel@tonic-gate port_free_event(reqp->aio_req_portkev);
5480Sstevel@tonic-gate reqp->aio_req_portkev = NULL;
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate if ((liop = reqp->aio_req_lio) != NULL) {
5520Sstevel@tonic-gate if (--liop->lio_nent == 0)
5530Sstevel@tonic-gate aio_lio_free(aiop, liop);
5540Sstevel@tonic-gate reqp->aio_req_lio = NULL;
5550Sstevel@tonic-gate }
5561885Sraf if (reqp->aio_req_sigqp != NULL) {
5570Sstevel@tonic-gate kmem_free(reqp->aio_req_sigqp, sizeof (sigqueue_t));
5581885Sraf reqp->aio_req_sigqp = NULL;
5591885Sraf }
5600Sstevel@tonic-gate reqp->aio_req_next = aiop->aio_free;
5611885Sraf reqp->aio_req_prev = NULL;
5620Sstevel@tonic-gate aiop->aio_free = reqp;
5630Sstevel@tonic-gate aiop->aio_outstanding--;
5640Sstevel@tonic-gate if (aiop->aio_outstanding == 0)
5650Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv);
5660Sstevel@tonic-gate aio_hash_delete(aiop, reqp);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate /*
5700Sstevel@tonic-gate * Put a reqp onto the freelist.
5710Sstevel@tonic-gate */
5720Sstevel@tonic-gate void
aio_req_free_port(aio_t * aiop,aio_req_t * reqp)5730Sstevel@tonic-gate aio_req_free_port(aio_t *aiop, aio_req_t *reqp)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_mutex));
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate reqp->aio_req_next = aiop->aio_free;
5781885Sraf reqp->aio_req_prev = NULL;
5790Sstevel@tonic-gate aiop->aio_free = reqp;
5800Sstevel@tonic-gate aiop->aio_outstanding--;
5810Sstevel@tonic-gate aio_hash_delete(aiop, reqp);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /*
5861885Sraf * Verify the integrity of a queue.
5870Sstevel@tonic-gate */
5881885Sraf #if defined(DEBUG)
5890Sstevel@tonic-gate static void
aio_verify_queue(aio_req_t * head,aio_req_t * entry_present,aio_req_t * entry_missing)5901885Sraf aio_verify_queue(aio_req_t *head,
5911885Sraf aio_req_t *entry_present, aio_req_t *entry_missing)
5921885Sraf {
5931885Sraf aio_req_t *reqp;
5941885Sraf int found = 0;
5951885Sraf int present = 0;
5961885Sraf
5971885Sraf if ((reqp = head) != NULL) {
5981885Sraf do {
5991885Sraf ASSERT(reqp->aio_req_prev->aio_req_next == reqp);
6001885Sraf ASSERT(reqp->aio_req_next->aio_req_prev == reqp);
6011885Sraf if (entry_present == reqp)
6021885Sraf found++;
6031885Sraf if (entry_missing == reqp)
6041885Sraf present++;
6051885Sraf } while ((reqp = reqp->aio_req_next) != head);
6061885Sraf }
6071885Sraf ASSERT(entry_present == NULL || found == 1);
6081885Sraf ASSERT(entry_missing == NULL || present == 0);
6091885Sraf }
6101885Sraf #else
6111885Sraf #define aio_verify_queue(x, y, z)
6121885Sraf #endif
6131885Sraf
6141885Sraf /*
6151885Sraf * Put a request onto the tail of a queue.
6161885Sraf */
6171885Sraf void
aio_enq(aio_req_t ** qhead,aio_req_t * reqp,int qflg_new)6180Sstevel@tonic-gate aio_enq(aio_req_t **qhead, aio_req_t *reqp, int qflg_new)
6190Sstevel@tonic-gate {
6201885Sraf aio_req_t *head;
6211885Sraf aio_req_t *prev;
6221885Sraf
6231885Sraf aio_verify_queue(*qhead, NULL, reqp);
6241885Sraf
6251885Sraf if ((head = *qhead) == NULL) {
6260Sstevel@tonic-gate reqp->aio_req_next = reqp;
6270Sstevel@tonic-gate reqp->aio_req_prev = reqp;
6281885Sraf *qhead = reqp;
6290Sstevel@tonic-gate } else {
6301885Sraf reqp->aio_req_next = head;
6311885Sraf reqp->aio_req_prev = prev = head->aio_req_prev;
6321885Sraf prev->aio_req_next = reqp;
6331885Sraf head->aio_req_prev = reqp;
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate reqp->aio_req_flags |= qflg_new;
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate /*
6391885Sraf * Remove a request from its queue.
6400Sstevel@tonic-gate */
6410Sstevel@tonic-gate void
aio_deq(aio_req_t ** qhead,aio_req_t * reqp)6421885Sraf aio_deq(aio_req_t **qhead, aio_req_t *reqp)
6430Sstevel@tonic-gate {
6441885Sraf aio_verify_queue(*qhead, reqp, NULL);
6450Sstevel@tonic-gate
6461885Sraf if (reqp->aio_req_next == reqp) {
6471885Sraf *qhead = NULL;
6480Sstevel@tonic-gate } else {
6491885Sraf reqp->aio_req_prev->aio_req_next = reqp->aio_req_next;
6501885Sraf reqp->aio_req_next->aio_req_prev = reqp->aio_req_prev;
6511885Sraf if (*qhead == reqp)
6521885Sraf *qhead = reqp->aio_req_next;
6530Sstevel@tonic-gate }
6541885Sraf reqp->aio_req_next = NULL;
6550Sstevel@tonic-gate reqp->aio_req_prev = NULL;
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate * concatenate a specified queue with the cleanupq. the specified
6600Sstevel@tonic-gate * queue is put onto the tail of the cleanupq. all elements on the
6610Sstevel@tonic-gate * specified queue should have their aio_req_flags field cleared.
6620Sstevel@tonic-gate */
6630Sstevel@tonic-gate /*ARGSUSED*/
6640Sstevel@tonic-gate void
aio_cleanupq_concat(aio_t * aiop,aio_req_t * q2,int qflg)6650Sstevel@tonic-gate aio_cleanupq_concat(aio_t *aiop, aio_req_t *q2, int qflg)
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate aio_req_t *cleanupqhead, *q2tail;
6680Sstevel@tonic-gate aio_req_t *reqp = q2;
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate do {
6710Sstevel@tonic-gate ASSERT(reqp->aio_req_flags & qflg);
6720Sstevel@tonic-gate reqp->aio_req_flags &= ~qflg;
6730Sstevel@tonic-gate reqp->aio_req_flags |= AIO_CLEANUPQ;
6740Sstevel@tonic-gate } while ((reqp = reqp->aio_req_next) != q2);
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate cleanupqhead = aiop->aio_cleanupq;
6770Sstevel@tonic-gate if (cleanupqhead == NULL)
6780Sstevel@tonic-gate aiop->aio_cleanupq = q2;
6790Sstevel@tonic-gate else {
6800Sstevel@tonic-gate cleanupqhead->aio_req_prev->aio_req_next = q2;
6810Sstevel@tonic-gate q2tail = q2->aio_req_prev;
6820Sstevel@tonic-gate q2tail->aio_req_next = cleanupqhead;
6830Sstevel@tonic-gate q2->aio_req_prev = cleanupqhead->aio_req_prev;
6840Sstevel@tonic-gate cleanupqhead->aio_req_prev = q2tail;
6850Sstevel@tonic-gate }
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * cleanup aio requests that are on the per-process poll queue.
6900Sstevel@tonic-gate */
6910Sstevel@tonic-gate void
aio_cleanup(int flag)6920Sstevel@tonic-gate aio_cleanup(int flag)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate aio_t *aiop = curproc->p_aio;
6950Sstevel@tonic-gate aio_req_t *pollqhead, *cleanupqhead, *notifyqhead;
6960Sstevel@tonic-gate aio_req_t *cleanupport;
6970Sstevel@tonic-gate aio_req_t *portq = NULL;
6980Sstevel@tonic-gate void (*func)();
6990Sstevel@tonic-gate int signalled = 0;
7000Sstevel@tonic-gate int qflag = 0;
7010Sstevel@tonic-gate int exitflg;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate ASSERT(aiop != NULL);
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate if (flag == AIO_CLEANUP_EXIT)
7060Sstevel@tonic-gate exitflg = AIO_CLEANUP_EXIT;
7070Sstevel@tonic-gate else
7080Sstevel@tonic-gate exitflg = 0;
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate /*
7110Sstevel@tonic-gate * We need to get the aio_cleanupq_mutex because we are calling
7120Sstevel@tonic-gate * aio_cleanup_cleanupq()
7130Sstevel@tonic-gate */
7140Sstevel@tonic-gate mutex_enter(&aiop->aio_cleanupq_mutex);
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate * take all the requests off the cleanupq, the notifyq,
7170Sstevel@tonic-gate * and the pollq.
7180Sstevel@tonic-gate */
7190Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
7200Sstevel@tonic-gate if ((cleanupqhead = aiop->aio_cleanupq) != NULL) {
7210Sstevel@tonic-gate aiop->aio_cleanupq = NULL;
7220Sstevel@tonic-gate qflag++;
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate if ((notifyqhead = aiop->aio_notifyq) != NULL) {
7250Sstevel@tonic-gate aiop->aio_notifyq = NULL;
7260Sstevel@tonic-gate qflag++;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate if ((pollqhead = aiop->aio_pollq) != NULL) {
7290Sstevel@tonic-gate aiop->aio_pollq = NULL;
7300Sstevel@tonic-gate qflag++;
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate if (flag) {
7330Sstevel@tonic-gate if ((portq = aiop->aio_portq) != NULL)
7340Sstevel@tonic-gate qflag++;
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if ((cleanupport = aiop->aio_portcleanupq) != NULL) {
7370Sstevel@tonic-gate aiop->aio_portcleanupq = NULL;
7380Sstevel@tonic-gate qflag++;
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate * return immediately if cleanupq, pollq, and
7450Sstevel@tonic-gate * notifyq are all empty. someone else must have
7460Sstevel@tonic-gate * emptied them.
7470Sstevel@tonic-gate */
7480Sstevel@tonic-gate if (!qflag) {
7490Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex);
7500Sstevel@tonic-gate return;
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate /*
7540Sstevel@tonic-gate * do cleanup for the various queues.
7550Sstevel@tonic-gate */
7560Sstevel@tonic-gate if (cleanupqhead)
7579973SSurya.Prakki@Sun.COM signalled = aio_cleanup_cleanupq(aiop, cleanupqhead, exitflg);
7580Sstevel@tonic-gate mutex_exit(&aiop->aio_cleanupq_mutex);
7590Sstevel@tonic-gate if (notifyqhead)
7600Sstevel@tonic-gate signalled = aio_cleanup_notifyq(aiop, notifyqhead, exitflg);
7610Sstevel@tonic-gate if (pollqhead)
7620Sstevel@tonic-gate aio_cleanup_pollq(aiop, pollqhead, exitflg);
7630Sstevel@tonic-gate if (flag && (cleanupport || portq))
7640Sstevel@tonic-gate aio_cleanup_portq(aiop, cleanupport, exitflg);
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if (exitflg)
7670Sstevel@tonic-gate return;
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate /*
7700Sstevel@tonic-gate * If we have an active aio_cleanup_thread it's possible for
7710Sstevel@tonic-gate * this routine to push something on to the done queue after
7720Sstevel@tonic-gate * an aiowait/aiosuspend thread has already decided to block.
7730Sstevel@tonic-gate * This being the case, we need a cv_broadcast here to wake
7740Sstevel@tonic-gate * these threads up. It is simpler and cleaner to do this
7750Sstevel@tonic-gate * broadcast here than in the individual cleanup routines.
7760Sstevel@tonic-gate */
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
779*10719SRoger.Faulkner@Sun.COM /*
780*10719SRoger.Faulkner@Sun.COM * If there has never been an old solaris aio request
781*10719SRoger.Faulkner@Sun.COM * issued by this process, then do not send a SIGIO signal.
782*10719SRoger.Faulkner@Sun.COM */
783*10719SRoger.Faulkner@Sun.COM if (!(aiop->aio_flags & AIO_SOLARIS_REQ))
784*10719SRoger.Faulkner@Sun.COM signalled = 1;
7850Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv);
7860Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate /*
7890Sstevel@tonic-gate * Only if the process wasn't already signalled,
7900Sstevel@tonic-gate * determine if a SIGIO signal should be delievered.
7910Sstevel@tonic-gate */
7920Sstevel@tonic-gate if (!signalled &&
7931885Sraf (func = PTOU(curproc)->u_signal[SIGIO - 1]) != SIG_DFL &&
7940Sstevel@tonic-gate func != SIG_IGN)
7950Sstevel@tonic-gate psignal(curproc, SIGIO);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate /*
8000Sstevel@tonic-gate * Do cleanup for every element of the port cleanup queue.
8010Sstevel@tonic-gate */
8020Sstevel@tonic-gate static void
aio_cleanup_portq(aio_t * aiop,aio_req_t * cleanupq,int exitflag)8030Sstevel@tonic-gate aio_cleanup_portq(aio_t *aiop, aio_req_t *cleanupq, int exitflag)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate aio_req_t *reqp;
8060Sstevel@tonic-gate aio_req_t *next;
8070Sstevel@tonic-gate aio_req_t *headp;
8081885Sraf aio_lio_t *liop;
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate /* first check the portq */
8110Sstevel@tonic-gate if (exitflag || ((aiop->aio_flags & AIO_CLEANUP_PORT) == 0)) {
8120Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
8130Sstevel@tonic-gate if (aiop->aio_flags & AIO_CLEANUP)
8140Sstevel@tonic-gate aiop->aio_flags |= AIO_CLEANUP_PORT;
8150Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
8160Sstevel@tonic-gate
8171885Sraf /*
8181885Sraf * It is not allowed to hold locks during aphysio_unlock().
8191885Sraf * The aio_done() interrupt function will try to acquire
8201885Sraf * aio_mutex and aio_portq_mutex. Therefore we disconnect
8211885Sraf * the portq list from the aiop for the duration of the
8221885Sraf * aphysio_unlock() loop below.
8231885Sraf */
8240Sstevel@tonic-gate mutex_enter(&aiop->aio_portq_mutex);
8250Sstevel@tonic-gate headp = aiop->aio_portq;
8260Sstevel@tonic-gate aiop->aio_portq = NULL;
8270Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
8281885Sraf if ((reqp = headp) != NULL) {
8291885Sraf do {
8301885Sraf next = reqp->aio_req_next;
8311885Sraf aphysio_unlock(reqp);
8321885Sraf if (exitflag) {
8331885Sraf mutex_enter(&aiop->aio_mutex);
8341885Sraf aio_req_free(aiop, reqp);
8351885Sraf mutex_exit(&aiop->aio_mutex);
8361885Sraf }
8371885Sraf } while ((reqp = next) != headp);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate if (headp != NULL && exitflag == 0) {
8411885Sraf /* move unlocked requests back to the port queue */
8421885Sraf aio_req_t *newq;
8431885Sraf
8440Sstevel@tonic-gate mutex_enter(&aiop->aio_portq_mutex);
8451885Sraf if ((newq = aiop->aio_portq) != NULL) {
8461885Sraf aio_req_t *headprev = headp->aio_req_prev;
8471885Sraf aio_req_t *newqprev = newq->aio_req_prev;
8481885Sraf
8491885Sraf headp->aio_req_prev = newqprev;
8501885Sraf newq->aio_req_prev = headprev;
8511885Sraf headprev->aio_req_next = newq;
8521885Sraf newqprev->aio_req_next = headp;
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate aiop->aio_portq = headp;
8550Sstevel@tonic-gate cv_broadcast(&aiop->aio_portcv);
8560Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate /* now check the port cleanup queue */
8611885Sraf if ((reqp = cleanupq) == NULL)
8621885Sraf return;
8631885Sraf do {
8640Sstevel@tonic-gate next = reqp->aio_req_next;
8650Sstevel@tonic-gate aphysio_unlock(reqp);
8660Sstevel@tonic-gate if (exitflag) {
8670Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
8680Sstevel@tonic-gate aio_req_free(aiop, reqp);
8690Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
8700Sstevel@tonic-gate } else {
8710Sstevel@tonic-gate mutex_enter(&aiop->aio_portq_mutex);
8721885Sraf aio_enq(&aiop->aio_portq, reqp, 0);
8730Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
8741885Sraf port_send_event(reqp->aio_req_portkev);
8751885Sraf if ((liop = reqp->aio_req_lio) != NULL) {
8761885Sraf int send_event = 0;
8771885Sraf
8781885Sraf mutex_enter(&aiop->aio_mutex);
8791885Sraf ASSERT(liop->lio_refcnt > 0);
8801885Sraf if (--liop->lio_refcnt == 0) {
8811885Sraf if (liop->lio_port >= 0 &&
8821885Sraf liop->lio_portkev) {
8831885Sraf liop->lio_port = -1;
8841885Sraf send_event = 1;
8851885Sraf }
8861885Sraf }
8871885Sraf mutex_exit(&aiop->aio_mutex);
8881885Sraf if (send_event)
8891885Sraf port_send_event(liop->lio_portkev);
8901885Sraf }
8910Sstevel@tonic-gate }
8921885Sraf } while ((reqp = next) != cleanupq);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate /*
8960Sstevel@tonic-gate * Do cleanup for every element of the cleanupq.
8970Sstevel@tonic-gate */
8989973SSurya.Prakki@Sun.COM static int
aio_cleanup_cleanupq(aio_t * aiop,aio_req_t * qhead,int exitflg)8990Sstevel@tonic-gate aio_cleanup_cleanupq(aio_t *aiop, aio_req_t *qhead, int exitflg)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate aio_req_t *reqp, *next;
9029973SSurya.Prakki@Sun.COM int signalled = 0;
9031885Sraf
9040Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_cleanupq_mutex));
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate * Since aio_req_done() or aio_req_find() use the HASH list to find
9080Sstevel@tonic-gate * the required requests, they could potentially take away elements
9090Sstevel@tonic-gate * if they are already done (AIO_DONEQ is set).
9100Sstevel@tonic-gate * The aio_cleanupq_mutex protects the queue for the duration of the
9110Sstevel@tonic-gate * loop from aio_req_done() and aio_req_find().
9120Sstevel@tonic-gate */
9131885Sraf if ((reqp = qhead) == NULL)
9149973SSurya.Prakki@Sun.COM return (0);
9151885Sraf do {
9160Sstevel@tonic-gate ASSERT(reqp->aio_req_flags & AIO_CLEANUPQ);
9171885Sraf ASSERT(reqp->aio_req_portkev == NULL);
9180Sstevel@tonic-gate next = reqp->aio_req_next;
9190Sstevel@tonic-gate aphysio_unlock(reqp);
9200Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
9211885Sraf if (exitflg)
9220Sstevel@tonic-gate aio_req_free(aiop, reqp);
9231885Sraf else
9241885Sraf aio_enq(&aiop->aio_doneq, reqp, AIO_DONEQ);
92510620SSurya.Prakki@Sun.COM if (!exitflg) {
92610620SSurya.Prakki@Sun.COM if (reqp->aio_req_flags & AIO_SIGNALLED)
92710620SSurya.Prakki@Sun.COM signalled++;
92810620SSurya.Prakki@Sun.COM else
92910620SSurya.Prakki@Sun.COM reqp->aio_req_flags |= AIO_SIGNALLED;
93010620SSurya.Prakki@Sun.COM }
9310Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
9321885Sraf } while ((reqp = next) != qhead);
9339973SSurya.Prakki@Sun.COM return (signalled);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate * do cleanup for every element of the notify queue.
9380Sstevel@tonic-gate */
9390Sstevel@tonic-gate static int
aio_cleanup_notifyq(aio_t * aiop,aio_req_t * qhead,int exitflg)9400Sstevel@tonic-gate aio_cleanup_notifyq(aio_t *aiop, aio_req_t *qhead, int exitflg)
9410Sstevel@tonic-gate {
9420Sstevel@tonic-gate aio_req_t *reqp, *next;
9430Sstevel@tonic-gate aio_lio_t *liohead;
9440Sstevel@tonic-gate sigqueue_t *sigev, *lio_sigev = NULL;
9450Sstevel@tonic-gate int signalled = 0;
9460Sstevel@tonic-gate
9471885Sraf if ((reqp = qhead) == NULL)
9481885Sraf return (0);
9491885Sraf do {
9500Sstevel@tonic-gate ASSERT(reqp->aio_req_flags & AIO_NOTIFYQ);
9510Sstevel@tonic-gate next = reqp->aio_req_next;
9520Sstevel@tonic-gate aphysio_unlock(reqp);
9530Sstevel@tonic-gate if (exitflg) {
9540Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
9550Sstevel@tonic-gate aio_req_free(aiop, reqp);
9560Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
9571885Sraf } else {
9581885Sraf mutex_enter(&aiop->aio_mutex);
9591885Sraf aio_enq(&aiop->aio_doneq, reqp, AIO_DONEQ);
9601885Sraf sigev = reqp->aio_req_sigqp;
9611885Sraf reqp->aio_req_sigqp = NULL;
9621885Sraf if ((liohead = reqp->aio_req_lio) != NULL) {
9631885Sraf ASSERT(liohead->lio_refcnt > 0);
9641885Sraf if (--liohead->lio_refcnt == 0) {
9651885Sraf cv_signal(&liohead->lio_notify);
9661885Sraf lio_sigev = liohead->lio_sigqp;
9671885Sraf liohead->lio_sigqp = NULL;
9681885Sraf }
9691885Sraf }
9701885Sraf mutex_exit(&aiop->aio_mutex);
9711885Sraf if (sigev) {
9721885Sraf signalled++;
9731885Sraf aio_sigev_send(reqp->aio_req_buf.b_proc,
9741885Sraf sigev);
9751885Sraf }
9761885Sraf if (lio_sigev) {
9771885Sraf signalled++;
9781885Sraf aio_sigev_send(reqp->aio_req_buf.b_proc,
9791885Sraf lio_sigev);
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate }
9821885Sraf } while ((reqp = next) != qhead);
9831885Sraf
9840Sstevel@tonic-gate return (signalled);
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate /*
9880Sstevel@tonic-gate * Do cleanup for every element of the poll queue.
9890Sstevel@tonic-gate */
9900Sstevel@tonic-gate static void
aio_cleanup_pollq(aio_t * aiop,aio_req_t * qhead,int exitflg)9910Sstevel@tonic-gate aio_cleanup_pollq(aio_t *aiop, aio_req_t *qhead, int exitflg)
9920Sstevel@tonic-gate {
9930Sstevel@tonic-gate aio_req_t *reqp, *next;
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate /*
9960Sstevel@tonic-gate * As no other threads should be accessing the queue at this point,
9970Sstevel@tonic-gate * it isn't necessary to hold aio_mutex while we traverse its elements.
9980Sstevel@tonic-gate */
9991885Sraf if ((reqp = qhead) == NULL)
10001885Sraf return;
10011885Sraf do {
10020Sstevel@tonic-gate ASSERT(reqp->aio_req_flags & AIO_POLLQ);
10030Sstevel@tonic-gate next = reqp->aio_req_next;
10040Sstevel@tonic-gate aphysio_unlock(reqp);
10050Sstevel@tonic-gate if (exitflg) {
10060Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
10070Sstevel@tonic-gate aio_req_free(aiop, reqp);
10080Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
10091885Sraf } else {
10101885Sraf aio_copyout_result(reqp);
10111885Sraf mutex_enter(&aiop->aio_mutex);
10121885Sraf aio_enq(&aiop->aio_doneq, reqp, AIO_DONEQ);
10131885Sraf mutex_exit(&aiop->aio_mutex);
10140Sstevel@tonic-gate }
10151885Sraf } while ((reqp = next) != qhead);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate * called by exit(). waits for all outstanding kaio to finish
10200Sstevel@tonic-gate * before the kaio resources are freed.
10210Sstevel@tonic-gate */
10220Sstevel@tonic-gate void
aio_cleanup_exit(void)10230Sstevel@tonic-gate aio_cleanup_exit(void)
10240Sstevel@tonic-gate {
10250Sstevel@tonic-gate proc_t *p = curproc;
10260Sstevel@tonic-gate aio_t *aiop = p->p_aio;
10270Sstevel@tonic-gate aio_req_t *reqp, *next, *head;
10280Sstevel@tonic-gate aio_lio_t *nxtlio, *liop;
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate * wait for all outstanding kaio to complete. process
10320Sstevel@tonic-gate * is now single-threaded; no other kaio requests can
10330Sstevel@tonic-gate * happen once aio_pending is zero.
10340Sstevel@tonic-gate */
10350Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
10360Sstevel@tonic-gate aiop->aio_flags |= AIO_CLEANUP;
10370Sstevel@tonic-gate while ((aiop->aio_pending != 0) || (aiop->aio_flags & AIO_DONE_ACTIVE))
10380Sstevel@tonic-gate cv_wait(&aiop->aio_cleanupcv, &aiop->aio_mutex);
10390Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate /* cleanup the cleanup-thread queues. */
10420Sstevel@tonic-gate aio_cleanup(AIO_CLEANUP_EXIT);
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate /*
10450Sstevel@tonic-gate * Although this process is now single-threaded, we
10460Sstevel@tonic-gate * still need to protect ourselves against a race with
10470Sstevel@tonic-gate * aio_cleanup_dr_delete_memory().
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate mutex_enter(&p->p_lock);
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate * free up the done queue's resources.
10530Sstevel@tonic-gate */
10540Sstevel@tonic-gate if ((head = aiop->aio_doneq) != NULL) {
10551885Sraf aiop->aio_doneq = NULL;
10561885Sraf reqp = head;
10571885Sraf do {
10580Sstevel@tonic-gate next = reqp->aio_req_next;
10590Sstevel@tonic-gate aphysio_unlock(reqp);
10600Sstevel@tonic-gate kmem_free(reqp, sizeof (struct aio_req_t));
10611885Sraf } while ((reqp = next) != head);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate /*
10640Sstevel@tonic-gate * release aio request freelist.
10650Sstevel@tonic-gate */
10660Sstevel@tonic-gate for (reqp = aiop->aio_free; reqp != NULL; reqp = next) {
10670Sstevel@tonic-gate next = reqp->aio_req_next;
10680Sstevel@tonic-gate kmem_free(reqp, sizeof (struct aio_req_t));
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate /*
10720Sstevel@tonic-gate * release io list head freelist.
10730Sstevel@tonic-gate */
10740Sstevel@tonic-gate for (liop = aiop->aio_lio_free; liop != NULL; liop = nxtlio) {
10750Sstevel@tonic-gate nxtlio = liop->lio_next;
10760Sstevel@tonic-gate kmem_free(liop, sizeof (aio_lio_t));
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate if (aiop->aio_iocb)
10800Sstevel@tonic-gate kmem_free(aiop->aio_iocb, aiop->aio_iocbsz);
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate mutex_destroy(&aiop->aio_mutex);
10830Sstevel@tonic-gate mutex_destroy(&aiop->aio_portq_mutex);
10840Sstevel@tonic-gate mutex_destroy(&aiop->aio_cleanupq_mutex);
10850Sstevel@tonic-gate p->p_aio = NULL;
10860Sstevel@tonic-gate mutex_exit(&p->p_lock);
10870Sstevel@tonic-gate kmem_free(aiop, sizeof (struct aio));
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate /*
10910Sstevel@tonic-gate * copy out aio request's result to a user-level result_t buffer.
10920Sstevel@tonic-gate */
10930Sstevel@tonic-gate void
aio_copyout_result(aio_req_t * reqp)10940Sstevel@tonic-gate aio_copyout_result(aio_req_t *reqp)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate struct buf *bp;
10970Sstevel@tonic-gate struct iovec *iov;
10980Sstevel@tonic-gate void *resultp;
10990Sstevel@tonic-gate int error;
11000Sstevel@tonic-gate size_t retval;
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate if (reqp->aio_req_flags & AIO_COPYOUTDONE)
11030Sstevel@tonic-gate return;
11040Sstevel@tonic-gate
11050Sstevel@tonic-gate reqp->aio_req_flags |= AIO_COPYOUTDONE;
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate iov = reqp->aio_req_uio.uio_iov;
11080Sstevel@tonic-gate bp = &reqp->aio_req_buf;
11090Sstevel@tonic-gate /* "resultp" points to user-level result_t buffer */
11100Sstevel@tonic-gate resultp = (void *)reqp->aio_req_resultp;
11110Sstevel@tonic-gate if (bp->b_flags & B_ERROR) {
11120Sstevel@tonic-gate if (bp->b_error)
11130Sstevel@tonic-gate error = bp->b_error;
11140Sstevel@tonic-gate else
11150Sstevel@tonic-gate error = EIO;
11160Sstevel@tonic-gate retval = (size_t)-1;
11170Sstevel@tonic-gate } else {
11180Sstevel@tonic-gate error = 0;
11190Sstevel@tonic-gate retval = iov->iov_len - bp->b_resid;
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
11220Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
11230Sstevel@tonic-gate (void) sulword(&((aio_result_t *)resultp)->aio_return, retval);
11240Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_errno, error);
11250Sstevel@tonic-gate } else {
11260Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_return,
11270Sstevel@tonic-gate (int)retval);
11280Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_errno, error);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate #else
11310Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_return, retval);
11320Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_errno, error);
11330Sstevel@tonic-gate #endif
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate void
aio_copyout_result_port(struct iovec * iov,struct buf * bp,void * resultp)11380Sstevel@tonic-gate aio_copyout_result_port(struct iovec *iov, struct buf *bp, void *resultp)
11390Sstevel@tonic-gate {
11400Sstevel@tonic-gate int errno;
11410Sstevel@tonic-gate size_t retval;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate if (bp->b_flags & B_ERROR) {
11440Sstevel@tonic-gate if (bp->b_error)
11450Sstevel@tonic-gate errno = bp->b_error;
11460Sstevel@tonic-gate else
11470Sstevel@tonic-gate errno = EIO;
11480Sstevel@tonic-gate retval = (size_t)-1;
11490Sstevel@tonic-gate } else {
11500Sstevel@tonic-gate errno = 0;
11510Sstevel@tonic-gate retval = iov->iov_len - bp->b_resid;
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
11540Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
11550Sstevel@tonic-gate (void) sulword(&((aio_result_t *)resultp)->aio_return, retval);
11560Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_errno, errno);
11570Sstevel@tonic-gate } else {
11580Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_return,
11590Sstevel@tonic-gate (int)retval);
11600Sstevel@tonic-gate (void) suword32(&((aio_result32_t *)resultp)->aio_errno, errno);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate #else
11630Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_return, retval);
11640Sstevel@tonic-gate (void) suword32(&((aio_result_t *)resultp)->aio_errno, errno);
11650Sstevel@tonic-gate #endif
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate /*
11690Sstevel@tonic-gate * This function is used to remove a request from the done queue.
11700Sstevel@tonic-gate */
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate void
aio_req_remove_portq(aio_t * aiop,aio_req_t * reqp)11730Sstevel@tonic-gate aio_req_remove_portq(aio_t *aiop, aio_req_t *reqp)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate ASSERT(MUTEX_HELD(&aiop->aio_portq_mutex));
11760Sstevel@tonic-gate while (aiop->aio_portq == NULL) {
11770Sstevel@tonic-gate /*
11780Sstevel@tonic-gate * aio_portq is set to NULL when aio_cleanup_portq()
11790Sstevel@tonic-gate * is working with the event queue.
11800Sstevel@tonic-gate * The aio_cleanup_thread() uses aio_cleanup_portq()
11810Sstevel@tonic-gate * to unlock all AIO buffers with completed transactions.
11820Sstevel@tonic-gate * Wait here until aio_cleanup_portq() restores the
11830Sstevel@tonic-gate * list of completed transactions in aio_portq.
11840Sstevel@tonic-gate */
11850Sstevel@tonic-gate cv_wait(&aiop->aio_portcv, &aiop->aio_portq_mutex);
11860Sstevel@tonic-gate }
11871885Sraf aio_deq(&aiop->aio_portq, reqp);
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate /* ARGSUSED */
11910Sstevel@tonic-gate void
aio_close_port(void * arg,int port,pid_t pid,int lastclose)11920Sstevel@tonic-gate aio_close_port(void *arg, int port, pid_t pid, int lastclose)
11930Sstevel@tonic-gate {
11940Sstevel@tonic-gate aio_t *aiop;
11950Sstevel@tonic-gate aio_req_t *reqp;
11960Sstevel@tonic-gate aio_req_t *next;
11970Sstevel@tonic-gate aio_req_t *headp;
11980Sstevel@tonic-gate int counter;
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate if (arg == NULL)
12010Sstevel@tonic-gate aiop = curproc->p_aio;
12020Sstevel@tonic-gate else
12030Sstevel@tonic-gate aiop = (aio_t *)arg;
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate /*
12060Sstevel@tonic-gate * The PORT_SOURCE_AIO source is always associated with every new
12070Sstevel@tonic-gate * created port by default.
12080Sstevel@tonic-gate * If no asynchronous I/O transactions were associated with the port
12090Sstevel@tonic-gate * then the aiop pointer will still be set to NULL.
12100Sstevel@tonic-gate */
12110Sstevel@tonic-gate if (aiop == NULL)
12120Sstevel@tonic-gate return;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate /*
12150Sstevel@tonic-gate * Within a process event ports can be used to collect events other
12160Sstevel@tonic-gate * than PORT_SOURCE_AIO events. At the same time the process can submit
12170Sstevel@tonic-gate * asynchronous I/Os transactions which are not associated with the
12180Sstevel@tonic-gate * current port.
12190Sstevel@tonic-gate * The current process oriented model of AIO uses a sigle queue for
12200Sstevel@tonic-gate * pending events. On close the pending queue (queue of asynchronous
12210Sstevel@tonic-gate * I/O transactions using event port notification) must be scanned
12220Sstevel@tonic-gate * to detect and handle pending I/Os using the current port.
12230Sstevel@tonic-gate */
12240Sstevel@tonic-gate mutex_enter(&aiop->aio_portq_mutex);
12250Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
12261885Sraf counter = 0;
12271885Sraf if ((headp = aiop->aio_portpending) != NULL) {
12281885Sraf reqp = headp;
12291885Sraf do {
12301885Sraf if (reqp->aio_req_portkev &&
12311885Sraf reqp->aio_req_port == port) {
12321885Sraf reqp->aio_req_flags |= AIO_CLOSE_PORT;
12331885Sraf counter++;
12341885Sraf }
12351885Sraf } while ((reqp = reqp->aio_req_next) != headp);
12360Sstevel@tonic-gate }
12370Sstevel@tonic-gate if (counter == 0) {
12380Sstevel@tonic-gate /* no AIOs pending */
12390Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
12400Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
12410Sstevel@tonic-gate return;
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate aiop->aio_portpendcnt += counter;
124441Spraks mutex_exit(&aiop->aio_mutex);
12450Sstevel@tonic-gate while (aiop->aio_portpendcnt)
124641Spraks cv_wait(&aiop->aio_portcv, &aiop->aio_portq_mutex);
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * all pending AIOs are completed.
12500Sstevel@tonic-gate * check port doneq
12510Sstevel@tonic-gate */
12520Sstevel@tonic-gate headp = NULL;
12531885Sraf if ((reqp = aiop->aio_portq) != NULL) {
12541885Sraf do {
12551885Sraf next = reqp->aio_req_next;
12561885Sraf if (reqp->aio_req_port == port) {
12571885Sraf /* dequeue request and discard event */
12581885Sraf aio_req_remove_portq(aiop, reqp);
12591885Sraf port_free_event(reqp->aio_req_portkev);
12601885Sraf /* put request in temporary queue */
12611885Sraf reqp->aio_req_next = headp;
12621885Sraf headp = reqp;
12631885Sraf }
12641885Sraf } while ((reqp = next) != aiop->aio_portq);
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate mutex_exit(&aiop->aio_portq_mutex);
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /* headp points to the list of requests to be discarded */
12690Sstevel@tonic-gate for (reqp = headp; reqp != NULL; reqp = next) {
12700Sstevel@tonic-gate next = reqp->aio_req_next;
12710Sstevel@tonic-gate aphysio_unlock(reqp);
12720Sstevel@tonic-gate mutex_enter(&aiop->aio_mutex);
12730Sstevel@tonic-gate aio_req_free_port(aiop, reqp);
12740Sstevel@tonic-gate mutex_exit(&aiop->aio_mutex);
12750Sstevel@tonic-gate }
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate if (aiop->aio_flags & AIO_CLEANUP)
12780Sstevel@tonic-gate cv_broadcast(&aiop->aio_waitcv);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate * aio_cleanup_dr_delete_memory is used by dr's delete_memory_thread
1283304Spraks * to kick start the aio_cleanup_thread for the give process to do the
1284304Spraks * necessary cleanup.
1285304Spraks * This is needed so that delete_memory_thread can obtain writer locks
1286304Spraks * on pages that need to be relocated during a dr memory delete operation,
1287304Spraks * otherwise a deadly embrace may occur.
12880Sstevel@tonic-gate */
12890Sstevel@tonic-gate int
aio_cleanup_dr_delete_memory(proc_t * procp)12900Sstevel@tonic-gate aio_cleanup_dr_delete_memory(proc_t *procp)
12910Sstevel@tonic-gate {
12920Sstevel@tonic-gate struct aio *aiop = procp->p_aio;
1293304Spraks struct as *as = procp->p_as;
1294304Spraks int ret = 0;
12950Sstevel@tonic-gate
12960Sstevel@tonic-gate ASSERT(MUTEX_HELD(&procp->p_lock));
1297304Spraks
1298304Spraks mutex_enter(&as->a_contents);
1299304Spraks
1300304Spraks if (aiop != NULL) {
1301304Spraks aiop->aio_rqclnup = 1;
1302304Spraks cv_broadcast(&as->a_cv);
1303304Spraks ret = 1;
13040Sstevel@tonic-gate }
1305304Spraks mutex_exit(&as->a_contents);
1306304Spraks return (ret);
13070Sstevel@tonic-gate }
1308