19491SAnders.Persson@Sun.COM /*
29491SAnders.Persson@Sun.COM * CDDL HEADER START
39491SAnders.Persson@Sun.COM *
49491SAnders.Persson@Sun.COM * The contents of this file are subject to the terms of the
59491SAnders.Persson@Sun.COM * Common Development and Distribution License (the "License").
69491SAnders.Persson@Sun.COM * You may not use this file except in compliance with the License.
79491SAnders.Persson@Sun.COM *
89491SAnders.Persson@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99491SAnders.Persson@Sun.COM * or http://www.opensolaris.org/os/licensing.
109491SAnders.Persson@Sun.COM * See the License for the specific language governing permissions
119491SAnders.Persson@Sun.COM * and limitations under the License.
129491SAnders.Persson@Sun.COM *
139491SAnders.Persson@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149491SAnders.Persson@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159491SAnders.Persson@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169491SAnders.Persson@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179491SAnders.Persson@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189491SAnders.Persson@Sun.COM *
199491SAnders.Persson@Sun.COM * CDDL HEADER END
209491SAnders.Persson@Sun.COM */
219491SAnders.Persson@Sun.COM
229491SAnders.Persson@Sun.COM /*
23*12643SAnders.Persson@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
249491SAnders.Persson@Sun.COM */
259491SAnders.Persson@Sun.COM
269491SAnders.Persson@Sun.COM #include <sys/types.h>
279491SAnders.Persson@Sun.COM #include <sys/param.h>
289491SAnders.Persson@Sun.COM #include <sys/cmn_err.h>
299491SAnders.Persson@Sun.COM #include <sys/uio.h>
309491SAnders.Persson@Sun.COM #include <sys/stropts.h>
319491SAnders.Persson@Sun.COM #include <sys/strsun.h>
329491SAnders.Persson@Sun.COM #include <sys/systm.h>
339491SAnders.Persson@Sun.COM #include <sys/socketvar.h>
349491SAnders.Persson@Sun.COM #include <fs/sockfs/sodirect.h>
359491SAnders.Persson@Sun.COM
369491SAnders.Persson@Sun.COM /*
379491SAnders.Persson@Sun.COM * In support of on-board asynchronous DMA hardware (e.g. Intel I/OAT)
389491SAnders.Persson@Sun.COM * we use a consolidation private KAPI to allow the protocol to start
399491SAnders.Persson@Sun.COM * an asynchronous copyout to a user-land receive-side buffer (uioa)
409491SAnders.Persson@Sun.COM * when a blocking socket read (e.g. read, recv, ...) is pending.
419491SAnders.Persson@Sun.COM *
429491SAnders.Persson@Sun.COM * In some broad strokes, this is what happens. When recv is called,
439491SAnders.Persson@Sun.COM * we first determine whether it would be beneficial to use uioa, and
449491SAnders.Persson@Sun.COM * if so set up the required state (all done by sod_rcv_init()).
459491SAnders.Persson@Sun.COM * The protocol can only initiate asynchronous copyout if the receive
469491SAnders.Persson@Sun.COM * queue is empty, so the first thing we do is drain any previously
479491SAnders.Persson@Sun.COM * queued data (using sod_uioa_so_init()). Once the copyouts (if any)
489491SAnders.Persson@Sun.COM * have been scheduled we wait for the receive to be satisfied. During
499491SAnders.Persson@Sun.COM * that time any new mblks that are enqueued will be scheduled to be
509491SAnders.Persson@Sun.COM * copied out asynchronously (sod_uioa_mblk_init()). When the receive
519491SAnders.Persson@Sun.COM * has been satisfied we wait for all scheduled copyout operations to
529491SAnders.Persson@Sun.COM * complete before we return to the user (sod_rcv_done())
539491SAnders.Persson@Sun.COM */
549491SAnders.Persson@Sun.COM
559491SAnders.Persson@Sun.COM static struct kmem_cache *sock_sod_cache;
569491SAnders.Persson@Sun.COM
579491SAnders.Persson@Sun.COM /*
589491SAnders.Persson@Sun.COM * This function is called at the beginning of recvmsg().
599491SAnders.Persson@Sun.COM *
609491SAnders.Persson@Sun.COM * If I/OAT is enabled on this sonode, initialize the uioa state machine
619491SAnders.Persson@Sun.COM * with state UIOA_ALLOC.
629491SAnders.Persson@Sun.COM */
639491SAnders.Persson@Sun.COM uio_t *
sod_rcv_init(struct sonode * so,int flags,struct uio ** uiopp)649491SAnders.Persson@Sun.COM sod_rcv_init(struct sonode *so, int flags, struct uio **uiopp)
659491SAnders.Persson@Sun.COM {
669491SAnders.Persson@Sun.COM struct uio *suiop;
679491SAnders.Persson@Sun.COM struct uio *uiop;
689491SAnders.Persson@Sun.COM sodirect_t *sodp = so->so_direct;
699491SAnders.Persson@Sun.COM
709491SAnders.Persson@Sun.COM if (sodp == NULL)
719491SAnders.Persson@Sun.COM return (NULL);
729491SAnders.Persson@Sun.COM
739491SAnders.Persson@Sun.COM suiop = NULL;
749491SAnders.Persson@Sun.COM uiop = *uiopp;
759491SAnders.Persson@Sun.COM
769491SAnders.Persson@Sun.COM mutex_enter(&so->so_lock);
779491SAnders.Persson@Sun.COM if (uiop->uio_resid >= uioasync.mincnt &&
789491SAnders.Persson@Sun.COM sodp != NULL && sodp->sod_enabled &&
799491SAnders.Persson@Sun.COM uioasync.enabled && !(flags & MSG_PEEK) &&
80*12643SAnders.Persson@Sun.COM !so->so_proto_props.sopp_loopback && so->so_filter_active == 0 &&
819491SAnders.Persson@Sun.COM !(so->so_state & SS_CANTRCVMORE)) {
829491SAnders.Persson@Sun.COM /*
839491SAnders.Persson@Sun.COM * Big enough I/O for uioa min setup and an sodirect socket
849491SAnders.Persson@Sun.COM * and sodirect enabled and uioa enabled and I/O will be done
859491SAnders.Persson@Sun.COM * and not EOF so initialize the sodirect_t uioa_t with "uiop".
869491SAnders.Persson@Sun.COM */
879491SAnders.Persson@Sun.COM if (!uioainit(uiop, &sodp->sod_uioa)) {
889491SAnders.Persson@Sun.COM /*
899491SAnders.Persson@Sun.COM * Successful uioainit() so the uio_t part of the
909491SAnders.Persson@Sun.COM * uioa_t will be used for all uio_t work to follow,
919491SAnders.Persson@Sun.COM * we return the original "uiop" in "suiop".
929491SAnders.Persson@Sun.COM */
939491SAnders.Persson@Sun.COM suiop = uiop;
949491SAnders.Persson@Sun.COM *uiopp = (uio_t *)&sodp->sod_uioa;
959491SAnders.Persson@Sun.COM /*
969491SAnders.Persson@Sun.COM * Before returning to the caller the passed in uio_t
979491SAnders.Persson@Sun.COM * "uiop" will be updated via a call to uioafini()
989491SAnders.Persson@Sun.COM * below.
999491SAnders.Persson@Sun.COM *
1009491SAnders.Persson@Sun.COM * Note, the uioa.uioa_state isn't set to UIOA_ENABLED
1019491SAnders.Persson@Sun.COM * here as first we have to uioamove() any currently
1029491SAnders.Persson@Sun.COM * queued M_DATA mblk_t(s) so it will be done later.
1039491SAnders.Persson@Sun.COM */
1049491SAnders.Persson@Sun.COM }
1059491SAnders.Persson@Sun.COM }
1069491SAnders.Persson@Sun.COM mutex_exit(&so->so_lock);
1079491SAnders.Persson@Sun.COM
1089491SAnders.Persson@Sun.COM return (suiop);
1099491SAnders.Persson@Sun.COM }
1109491SAnders.Persson@Sun.COM
1119491SAnders.Persson@Sun.COM /*
1129491SAnders.Persson@Sun.COM * This function is called at the end of recvmsg(), it finializes all the I/OAT
1139491SAnders.Persson@Sun.COM * operations, and reset the uioa state to UIOA_ALLOC.
1149491SAnders.Persson@Sun.COM */
1159491SAnders.Persson@Sun.COM int
sod_rcv_done(struct sonode * so,struct uio * suiop,struct uio * uiop)1169491SAnders.Persson@Sun.COM sod_rcv_done(struct sonode *so, struct uio *suiop, struct uio *uiop)
1179491SAnders.Persson@Sun.COM {
1189491SAnders.Persson@Sun.COM int error = 0;
1199491SAnders.Persson@Sun.COM sodirect_t *sodp = so->so_direct;
1209491SAnders.Persson@Sun.COM mblk_t *mp;
1219491SAnders.Persson@Sun.COM
1229491SAnders.Persson@Sun.COM if (sodp == NULL) {
1239491SAnders.Persson@Sun.COM return (0);
1249491SAnders.Persson@Sun.COM }
1259491SAnders.Persson@Sun.COM
1269491SAnders.Persson@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock));
1279491SAnders.Persson@Sun.COM /* Finish any sodirect and uioa processing */
1289491SAnders.Persson@Sun.COM if (suiop != NULL) {
1299491SAnders.Persson@Sun.COM /* Finish any uioa_t processing */
1309491SAnders.Persson@Sun.COM
1319491SAnders.Persson@Sun.COM ASSERT(uiop == (uio_t *)&sodp->sod_uioa);
1329491SAnders.Persson@Sun.COM error = uioafini(suiop, (uioa_t *)uiop);
1339491SAnders.Persson@Sun.COM if ((mp = sodp->sod_uioafh) != NULL) {
1349491SAnders.Persson@Sun.COM sodp->sod_uioafh = NULL;
1359491SAnders.Persson@Sun.COM sodp->sod_uioaft = NULL;
1369491SAnders.Persson@Sun.COM freemsg(mp);
1379491SAnders.Persson@Sun.COM }
1389491SAnders.Persson@Sun.COM }
1399491SAnders.Persson@Sun.COM ASSERT(sodp->sod_uioafh == NULL);
1409491SAnders.Persson@Sun.COM
1419491SAnders.Persson@Sun.COM return (error);
1429491SAnders.Persson@Sun.COM }
1439491SAnders.Persson@Sun.COM
1449491SAnders.Persson@Sun.COM /*
1459491SAnders.Persson@Sun.COM * Schedule a uioamove() on a mblk. This is done as mblks are enqueued
1469491SAnders.Persson@Sun.COM * by the protocol on the socket's rcv queue.
1479491SAnders.Persson@Sun.COM *
1489491SAnders.Persson@Sun.COM * Caller must be holding so_lock.
1499491SAnders.Persson@Sun.COM */
1509491SAnders.Persson@Sun.COM void
sod_uioa_mblk_init(struct sodirect_s * sodp,mblk_t * mp,size_t msg_size)1519491SAnders.Persson@Sun.COM sod_uioa_mblk_init(struct sodirect_s *sodp, mblk_t *mp, size_t msg_size)
1529491SAnders.Persson@Sun.COM {
1539491SAnders.Persson@Sun.COM uioa_t *uioap = &sodp->sod_uioa;
1549491SAnders.Persson@Sun.COM mblk_t *mp1 = mp;
1559491SAnders.Persson@Sun.COM mblk_t *lmp = NULL;
1569491SAnders.Persson@Sun.COM
1579491SAnders.Persson@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
1589491SAnders.Persson@Sun.COM ASSERT(msg_size == msgdsize(mp));
1599491SAnders.Persson@Sun.COM
1609491SAnders.Persson@Sun.COM if (uioap->uioa_state & UIOA_ENABLED) {
1619491SAnders.Persson@Sun.COM /* Uioa is enabled */
1629491SAnders.Persson@Sun.COM
1639491SAnders.Persson@Sun.COM if (msg_size > uioap->uio_resid) {
1649491SAnders.Persson@Sun.COM /*
1659491SAnders.Persson@Sun.COM * There isn't enough uio space for the mblk_t chain
1669491SAnders.Persson@Sun.COM * so disable uioa such that this and any additional
1679491SAnders.Persson@Sun.COM * mblk_t data is handled by the socket and schedule
1689491SAnders.Persson@Sun.COM * the socket for wakeup to finish this uioa.
1699491SAnders.Persson@Sun.COM */
1709491SAnders.Persson@Sun.COM uioap->uioa_state &= UIOA_CLR;
1719491SAnders.Persson@Sun.COM uioap->uioa_state |= UIOA_FINI;
1729491SAnders.Persson@Sun.COM return;
1739491SAnders.Persson@Sun.COM }
1749491SAnders.Persson@Sun.COM do {
1759491SAnders.Persson@Sun.COM uint32_t len = MBLKL(mp1);
1769491SAnders.Persson@Sun.COM
1779491SAnders.Persson@Sun.COM if (!uioamove(mp1->b_rptr, len, UIO_READ, uioap)) {
1789491SAnders.Persson@Sun.COM /* Scheduled, mark dblk_t as such */
1799491SAnders.Persson@Sun.COM DB_FLAGS(mp1) |= DBLK_UIOA;
1809491SAnders.Persson@Sun.COM } else {
1819491SAnders.Persson@Sun.COM /* Error, turn off async processing */
1829491SAnders.Persson@Sun.COM uioap->uioa_state &= UIOA_CLR;
1839491SAnders.Persson@Sun.COM uioap->uioa_state |= UIOA_FINI;
1849491SAnders.Persson@Sun.COM break;
1859491SAnders.Persson@Sun.COM }
1869491SAnders.Persson@Sun.COM lmp = mp1;
1879491SAnders.Persson@Sun.COM } while ((mp1 = mp1->b_cont) != NULL);
1889491SAnders.Persson@Sun.COM
1899491SAnders.Persson@Sun.COM if (mp1 != NULL || uioap->uio_resid == 0) {
1909491SAnders.Persson@Sun.COM /* Break the mblk chain if neccessary. */
1919491SAnders.Persson@Sun.COM if (mp1 != NULL && lmp != NULL) {
1929491SAnders.Persson@Sun.COM mp->b_next = mp1;
1939491SAnders.Persson@Sun.COM lmp->b_cont = NULL;
1949491SAnders.Persson@Sun.COM }
1959491SAnders.Persson@Sun.COM }
1969491SAnders.Persson@Sun.COM }
1979491SAnders.Persson@Sun.COM }
1989491SAnders.Persson@Sun.COM
1999491SAnders.Persson@Sun.COM /*
2009491SAnders.Persson@Sun.COM * This function is called on a mblk that thas been successfully uioamoved().
2019491SAnders.Persson@Sun.COM */
2029491SAnders.Persson@Sun.COM void
sod_uioa_mblk_done(sodirect_t * sodp,mblk_t * bp)2039491SAnders.Persson@Sun.COM sod_uioa_mblk_done(sodirect_t *sodp, mblk_t *bp)
2049491SAnders.Persson@Sun.COM {
2059491SAnders.Persson@Sun.COM if (bp != NULL && (bp->b_datap->db_flags & DBLK_UIOA)) {
2069491SAnders.Persson@Sun.COM /*
2079491SAnders.Persson@Sun.COM * A uioa flaged mblk_t chain, already uio processed,
2089491SAnders.Persson@Sun.COM * add it to the sodirect uioa pending free list.
2099491SAnders.Persson@Sun.COM *
2109491SAnders.Persson@Sun.COM * Note, a b_cont chain headed by a DBLK_UIOA enable
2119491SAnders.Persson@Sun.COM * mblk_t must have all mblk_t(s) DBLK_UIOA enabled.
2129491SAnders.Persson@Sun.COM */
2139491SAnders.Persson@Sun.COM mblk_t *bpt = sodp->sod_uioaft;
2149491SAnders.Persson@Sun.COM
2159491SAnders.Persson@Sun.COM ASSERT(sodp != NULL);
2169491SAnders.Persson@Sun.COM
2179491SAnders.Persson@Sun.COM /*
2189491SAnders.Persson@Sun.COM * Add first mblk_t of "bp" chain to current sodirect uioa
2199491SAnders.Persson@Sun.COM * free list tail mblk_t, if any, else empty list so new head.
2209491SAnders.Persson@Sun.COM */
2219491SAnders.Persson@Sun.COM if (bpt == NULL)
2229491SAnders.Persson@Sun.COM sodp->sod_uioafh = bp;
2239491SAnders.Persson@Sun.COM else
2249491SAnders.Persson@Sun.COM bpt->b_cont = bp;
2259491SAnders.Persson@Sun.COM
2269491SAnders.Persson@Sun.COM /*
2279491SAnders.Persson@Sun.COM * Walk mblk_t "bp" chain to find tail and adjust rptr of
2289491SAnders.Persson@Sun.COM * each to reflect that uioamove() has consumed all data.
2299491SAnders.Persson@Sun.COM */
2309491SAnders.Persson@Sun.COM bpt = bp;
2319491SAnders.Persson@Sun.COM for (;;) {
2329491SAnders.Persson@Sun.COM ASSERT(bpt->b_datap->db_flags & DBLK_UIOA);
2339491SAnders.Persson@Sun.COM
2349491SAnders.Persson@Sun.COM bpt->b_rptr = bpt->b_wptr;
2359491SAnders.Persson@Sun.COM if (bpt->b_cont == NULL)
2369491SAnders.Persson@Sun.COM break;
2379491SAnders.Persson@Sun.COM bpt = bpt->b_cont;
2389491SAnders.Persson@Sun.COM }
2399491SAnders.Persson@Sun.COM /* New sodirect uioa free list tail */
2409491SAnders.Persson@Sun.COM sodp->sod_uioaft = bpt;
2419491SAnders.Persson@Sun.COM
2429491SAnders.Persson@Sun.COM /* Only dequeue once with data returned per uioa_t */
2439491SAnders.Persson@Sun.COM if (sodp->sod_uioa.uioa_state & UIOA_ENABLED) {
2449491SAnders.Persson@Sun.COM sodp->sod_uioa.uioa_state &= UIOA_CLR;
2459491SAnders.Persson@Sun.COM sodp->sod_uioa.uioa_state |= UIOA_FINI;
2469491SAnders.Persson@Sun.COM }
2479491SAnders.Persson@Sun.COM }
2489491SAnders.Persson@Sun.COM }
2499491SAnders.Persson@Sun.COM
2509491SAnders.Persson@Sun.COM /*
2519491SAnders.Persson@Sun.COM * When transit from UIOA_INIT state to UIOA_ENABLE state in recvmsg(), call
2529491SAnders.Persson@Sun.COM * this function on a non-STREAMS socket to schedule uioamove() on the data
2539491SAnders.Persson@Sun.COM * that has already queued in this socket.
2549491SAnders.Persson@Sun.COM */
2559491SAnders.Persson@Sun.COM void
sod_uioa_so_init(struct sonode * so,struct sodirect_s * sodp,struct uio * uiop)2569491SAnders.Persson@Sun.COM sod_uioa_so_init(struct sonode *so, struct sodirect_s *sodp, struct uio *uiop)
2579491SAnders.Persson@Sun.COM {
2589491SAnders.Persson@Sun.COM uioa_t *uioap = (uioa_t *)uiop;
2599491SAnders.Persson@Sun.COM mblk_t *lbp;
2609491SAnders.Persson@Sun.COM mblk_t *wbp;
2619491SAnders.Persson@Sun.COM mblk_t *bp;
2629491SAnders.Persson@Sun.COM int len;
2639491SAnders.Persson@Sun.COM int error;
2649491SAnders.Persson@Sun.COM boolean_t in_rcv_q = B_TRUE;
2659491SAnders.Persson@Sun.COM
2669491SAnders.Persson@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock));
2679491SAnders.Persson@Sun.COM ASSERT(&sodp->sod_uioa == uioap);
2689491SAnders.Persson@Sun.COM
2699491SAnders.Persson@Sun.COM /*
2709491SAnders.Persson@Sun.COM * Walk first b_cont chain in sod_q
2719491SAnders.Persson@Sun.COM * and schedule any M_DATA mblk_t's for uio asynchronous move.
2729491SAnders.Persson@Sun.COM */
2739491SAnders.Persson@Sun.COM bp = so->so_rcv_q_head;
2749491SAnders.Persson@Sun.COM
2759491SAnders.Persson@Sun.COM again:
2769491SAnders.Persson@Sun.COM /* Walk the chain */
2779491SAnders.Persson@Sun.COM lbp = NULL;
2789491SAnders.Persson@Sun.COM wbp = bp;
2799491SAnders.Persson@Sun.COM
2809491SAnders.Persson@Sun.COM do {
2819491SAnders.Persson@Sun.COM if (bp == NULL)
2829491SAnders.Persson@Sun.COM break;
2839491SAnders.Persson@Sun.COM
2849491SAnders.Persson@Sun.COM if (wbp->b_datap->db_type != M_DATA) {
2859491SAnders.Persson@Sun.COM /* Not M_DATA, no more uioa */
2869491SAnders.Persson@Sun.COM goto nouioa;
2879491SAnders.Persson@Sun.COM }
2889491SAnders.Persson@Sun.COM if ((len = wbp->b_wptr - wbp->b_rptr) > 0) {
2899491SAnders.Persson@Sun.COM /* Have a M_DATA mblk_t with data */
2909491SAnders.Persson@Sun.COM if (len > uioap->uio_resid || (so->so_oobmark > 0 &&
2919491SAnders.Persson@Sun.COM len + uioap->uioa_mbytes >= so->so_oobmark)) {
2929491SAnders.Persson@Sun.COM /* Not enough uio sapce, or beyond oobmark */
2939491SAnders.Persson@Sun.COM goto nouioa;
2949491SAnders.Persson@Sun.COM }
2959491SAnders.Persson@Sun.COM ASSERT(!(wbp->b_datap->db_flags & DBLK_UIOA));
2969491SAnders.Persson@Sun.COM error = uioamove(wbp->b_rptr, len,
2979491SAnders.Persson@Sun.COM UIO_READ, uioap);
2989491SAnders.Persson@Sun.COM if (!error) {
2999491SAnders.Persson@Sun.COM /* Scheduled, mark dblk_t as such */
3009491SAnders.Persson@Sun.COM wbp->b_datap->db_flags |= DBLK_UIOA;
3019491SAnders.Persson@Sun.COM } else {
3029491SAnders.Persson@Sun.COM /* Break the mblk chain */
3039491SAnders.Persson@Sun.COM goto nouioa;
3049491SAnders.Persson@Sun.COM }
3059491SAnders.Persson@Sun.COM }
3069491SAnders.Persson@Sun.COM /* Save last wbp processed */
3079491SAnders.Persson@Sun.COM lbp = wbp;
3089491SAnders.Persson@Sun.COM } while ((wbp = wbp->b_cont) != NULL);
3099491SAnders.Persson@Sun.COM
3109491SAnders.Persson@Sun.COM if (in_rcv_q && (bp == NULL || bp->b_next == NULL)) {
3119491SAnders.Persson@Sun.COM /*
3129491SAnders.Persson@Sun.COM * We get here only once to process the sonode dump area
3139491SAnders.Persson@Sun.COM * if so_rcv_q_head is NULL or all the mblks have been
3149491SAnders.Persson@Sun.COM * successfully uioamoved()ed.
3159491SAnders.Persson@Sun.COM */
3169491SAnders.Persson@Sun.COM in_rcv_q = B_FALSE;
3179491SAnders.Persson@Sun.COM
3189491SAnders.Persson@Sun.COM /* move to dump area */
3199491SAnders.Persson@Sun.COM bp = so->so_rcv_head;
3209491SAnders.Persson@Sun.COM goto again;
3219491SAnders.Persson@Sun.COM }
3229491SAnders.Persson@Sun.COM
3239491SAnders.Persson@Sun.COM return;
3249491SAnders.Persson@Sun.COM
3259491SAnders.Persson@Sun.COM nouioa:
3269491SAnders.Persson@Sun.COM /* No more uioa */
3279491SAnders.Persson@Sun.COM uioap->uioa_state &= UIOA_CLR;
3289491SAnders.Persson@Sun.COM uioap->uioa_state |= UIOA_FINI;
3299491SAnders.Persson@Sun.COM
3309491SAnders.Persson@Sun.COM /*
3319491SAnders.Persson@Sun.COM * If we processed 1 or more mblk_t(s) then we need to split the
3329491SAnders.Persson@Sun.COM * current mblk_t chain in 2 so that all the uioamove()ed mblk_t(s)
3339491SAnders.Persson@Sun.COM * are in the current chain and the rest are in the following new
3349491SAnders.Persson@Sun.COM * chain.
3359491SAnders.Persson@Sun.COM */
3369491SAnders.Persson@Sun.COM if (lbp != NULL) {
3379491SAnders.Persson@Sun.COM /* New end of current chain */
3389491SAnders.Persson@Sun.COM lbp->b_cont = NULL;
3399491SAnders.Persson@Sun.COM
3409491SAnders.Persson@Sun.COM /* Insert new chain wbp after bp */
3419491SAnders.Persson@Sun.COM if ((wbp->b_next = bp->b_next) == NULL) {
3429491SAnders.Persson@Sun.COM if (in_rcv_q)
3439491SAnders.Persson@Sun.COM so->so_rcv_q_last_head = wbp;
3449491SAnders.Persson@Sun.COM else
3459491SAnders.Persson@Sun.COM so->so_rcv_last_head = wbp;
3469491SAnders.Persson@Sun.COM }
3479491SAnders.Persson@Sun.COM bp->b_next = wbp;
3489491SAnders.Persson@Sun.COM bp->b_next->b_prev = bp->b_prev;
3499491SAnders.Persson@Sun.COM bp->b_prev = lbp;
3509491SAnders.Persson@Sun.COM }
3519491SAnders.Persson@Sun.COM }
3529491SAnders.Persson@Sun.COM
3539491SAnders.Persson@Sun.COM /*
3549491SAnders.Persson@Sun.COM * Initialize sodirect data structures on a socket.
3559491SAnders.Persson@Sun.COM */
3569491SAnders.Persson@Sun.COM void
sod_sock_init(struct sonode * so)3579491SAnders.Persson@Sun.COM sod_sock_init(struct sonode *so)
3589491SAnders.Persson@Sun.COM {
3599491SAnders.Persson@Sun.COM sodirect_t *sodp;
3609491SAnders.Persson@Sun.COM
3619491SAnders.Persson@Sun.COM ASSERT(so->so_direct == NULL);
3629491SAnders.Persson@Sun.COM
3639491SAnders.Persson@Sun.COM so->so_state |= SS_SODIRECT;
3649491SAnders.Persson@Sun.COM
3659491SAnders.Persson@Sun.COM sodp = kmem_cache_alloc(sock_sod_cache, KM_SLEEP);
3669491SAnders.Persson@Sun.COM sodp->sod_enabled = B_TRUE;
3679491SAnders.Persson@Sun.COM sodp->sod_uioafh = NULL;
3689491SAnders.Persson@Sun.COM sodp->sod_uioaft = NULL;
3699491SAnders.Persson@Sun.COM /*
3709491SAnders.Persson@Sun.COM * Remainder of the sod_uioa members are left uninitialized
3719491SAnders.Persson@Sun.COM * but will be initialized later by uioainit() before uioa
3729491SAnders.Persson@Sun.COM * is enabled.
3739491SAnders.Persson@Sun.COM */
3749491SAnders.Persson@Sun.COM sodp->sod_uioa.uioa_state = UIOA_ALLOC;
3759491SAnders.Persson@Sun.COM so->so_direct = sodp;
3769491SAnders.Persson@Sun.COM }
3779491SAnders.Persson@Sun.COM
3789491SAnders.Persson@Sun.COM void
sod_sock_fini(struct sonode * so)3799491SAnders.Persson@Sun.COM sod_sock_fini(struct sonode *so)
3809491SAnders.Persson@Sun.COM {
3819491SAnders.Persson@Sun.COM sodirect_t *sodp = so->so_direct;
3829491SAnders.Persson@Sun.COM
3839491SAnders.Persson@Sun.COM ASSERT(sodp->sod_uioafh == NULL);
3849491SAnders.Persson@Sun.COM
3859491SAnders.Persson@Sun.COM so->so_direct = NULL;
3869491SAnders.Persson@Sun.COM kmem_cache_free(sock_sod_cache, sodp);
3879491SAnders.Persson@Sun.COM }
3889491SAnders.Persson@Sun.COM
3899491SAnders.Persson@Sun.COM /*
3909491SAnders.Persson@Sun.COM * Init the sodirect kmem cache while sockfs is loading.
3919491SAnders.Persson@Sun.COM */
3929491SAnders.Persson@Sun.COM int
sod_init()3939491SAnders.Persson@Sun.COM sod_init()
3949491SAnders.Persson@Sun.COM {
3959491SAnders.Persson@Sun.COM /* Allocate sodirect_t kmem_cache */
3969491SAnders.Persson@Sun.COM sock_sod_cache = kmem_cache_create("sock_sod_cache",
3979491SAnders.Persson@Sun.COM sizeof (sodirect_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
3989491SAnders.Persson@Sun.COM
3999491SAnders.Persson@Sun.COM return (0);
4009491SAnders.Persson@Sun.COM }
4019491SAnders.Persson@Sun.COM
4029491SAnders.Persson@Sun.COM ssize_t
sod_uioa_mblk(struct sonode * so,mblk_t * mp)4039491SAnders.Persson@Sun.COM sod_uioa_mblk(struct sonode *so, mblk_t *mp)
4049491SAnders.Persson@Sun.COM {
4059491SAnders.Persson@Sun.COM sodirect_t *sodp = so->so_direct;
4069491SAnders.Persson@Sun.COM
4079491SAnders.Persson@Sun.COM ASSERT(sodp != NULL);
4089491SAnders.Persson@Sun.COM ASSERT(MUTEX_HELD(&so->so_lock));
4099491SAnders.Persson@Sun.COM
4109491SAnders.Persson@Sun.COM ASSERT(sodp->sod_enabled);
4119491SAnders.Persson@Sun.COM ASSERT(sodp->sod_uioa.uioa_state != (UIOA_ALLOC|UIOA_INIT));
4129491SAnders.Persson@Sun.COM
4139491SAnders.Persson@Sun.COM ASSERT(sodp->sod_uioa.uioa_state & (UIOA_ENABLED|UIOA_FINI));
4149491SAnders.Persson@Sun.COM
4159491SAnders.Persson@Sun.COM if (mp == NULL && so->so_rcv_q_head != NULL) {
4169491SAnders.Persson@Sun.COM mp = so->so_rcv_q_head;
4179491SAnders.Persson@Sun.COM ASSERT(mp->b_prev != NULL);
4189491SAnders.Persson@Sun.COM mp->b_prev = NULL;
4199491SAnders.Persson@Sun.COM so->so_rcv_q_head = mp->b_next;
4209491SAnders.Persson@Sun.COM if (so->so_rcv_q_head == NULL) {
4219491SAnders.Persson@Sun.COM so->so_rcv_q_last_head = NULL;
4229491SAnders.Persson@Sun.COM }
4239491SAnders.Persson@Sun.COM mp->b_next = NULL;
4249491SAnders.Persson@Sun.COM }
4259491SAnders.Persson@Sun.COM
4269491SAnders.Persson@Sun.COM sod_uioa_mblk_done(sodp, mp);
4279491SAnders.Persson@Sun.COM
4289491SAnders.Persson@Sun.COM if (so->so_rcv_q_head == NULL && so->so_rcv_head != NULL &&
4299491SAnders.Persson@Sun.COM DB_TYPE(so->so_rcv_head) == M_DATA &&
4309491SAnders.Persson@Sun.COM (DB_FLAGS(so->so_rcv_head) & DBLK_UIOA)) {
4319491SAnders.Persson@Sun.COM /* more arrived */
4329491SAnders.Persson@Sun.COM ASSERT(so->so_rcv_q_head == NULL);
4339491SAnders.Persson@Sun.COM mp = so->so_rcv_head;
4349491SAnders.Persson@Sun.COM so->so_rcv_head = mp->b_next;
4359491SAnders.Persson@Sun.COM if (so->so_rcv_head == NULL)
4369491SAnders.Persson@Sun.COM so->so_rcv_last_head = NULL;
4379491SAnders.Persson@Sun.COM mp->b_prev = mp->b_next = NULL;
4389491SAnders.Persson@Sun.COM sod_uioa_mblk_done(sodp, mp);
4399491SAnders.Persson@Sun.COM }
4409491SAnders.Persson@Sun.COM
4419491SAnders.Persson@Sun.COM #ifdef DEBUG
4429491SAnders.Persson@Sun.COM if (so->so_rcv_q_head != NULL) {
4439491SAnders.Persson@Sun.COM mblk_t *m = so->so_rcv_q_head;
4449491SAnders.Persson@Sun.COM while (m != NULL) {
4459491SAnders.Persson@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) {
4469491SAnders.Persson@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p"
4479491SAnders.Persson@Sun.COM " in so_rcv_q_head.\n", (void *)m);
4489491SAnders.Persson@Sun.COM }
4499491SAnders.Persson@Sun.COM m = m->b_next;
4509491SAnders.Persson@Sun.COM }
4519491SAnders.Persson@Sun.COM }
4529491SAnders.Persson@Sun.COM if (so->so_rcv_head != NULL) {
4539491SAnders.Persson@Sun.COM mblk_t *m = so->so_rcv_head;
4549491SAnders.Persson@Sun.COM while (m != NULL) {
4559491SAnders.Persson@Sun.COM if (DB_FLAGS(m) & DBLK_UIOA) {
4569491SAnders.Persson@Sun.COM cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p"
4579491SAnders.Persson@Sun.COM " in so_rcv_head.\n", (void *)m);
4589491SAnders.Persson@Sun.COM }
4599491SAnders.Persson@Sun.COM m = m->b_next;
4609491SAnders.Persson@Sun.COM }
4619491SAnders.Persson@Sun.COM }
4629491SAnders.Persson@Sun.COM #endif
4639491SAnders.Persson@Sun.COM return (sodp->sod_uioa.uioa_mbytes);
4649491SAnders.Persson@Sun.COM }
465