1bbc000e5SAnders Persson /*
2bbc000e5SAnders Persson  * CDDL HEADER START
3bbc000e5SAnders Persson  *
4bbc000e5SAnders Persson  * The contents of this file are subject to the terms of the
5bbc000e5SAnders Persson  * Common Development and Distribution License (the "License").
6bbc000e5SAnders Persson  * You may not use this file except in compliance with the License.
7bbc000e5SAnders Persson  *
8bbc000e5SAnders Persson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9bbc000e5SAnders Persson  * or http://www.opensolaris.org/os/licensing.
10bbc000e5SAnders Persson  * See the License for the specific language governing permissions
11bbc000e5SAnders Persson  * and limitations under the License.
12bbc000e5SAnders Persson  *
13bbc000e5SAnders Persson  * When distributing Covered Code, include this CDDL HEADER in each
14bbc000e5SAnders Persson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15bbc000e5SAnders Persson  * If applicable, add the following below this CDDL HEADER, with the
16bbc000e5SAnders Persson  * fields enclosed by brackets "[]" replaced with your own identifying
17bbc000e5SAnders Persson  * information: Portions Copyright [yyyy] [name of copyright owner]
18bbc000e5SAnders Persson  *
19bbc000e5SAnders Persson  * CDDL HEADER END
20bbc000e5SAnders Persson  */
21bbc000e5SAnders Persson 
22bbc000e5SAnders Persson /*
23*3e95bd4aSAnders Persson  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24bbc000e5SAnders Persson  */
25bbc000e5SAnders Persson 
26bbc000e5SAnders Persson #include <sys/types.h>
27bbc000e5SAnders Persson #include <sys/param.h>
28bbc000e5SAnders Persson #include <sys/cmn_err.h>
29bbc000e5SAnders Persson #include <sys/uio.h>
30bbc000e5SAnders Persson #include <sys/stropts.h>
31bbc000e5SAnders Persson #include <sys/strsun.h>
32bbc000e5SAnders Persson #include <sys/systm.h>
33bbc000e5SAnders Persson #include <sys/socketvar.h>
34bbc000e5SAnders Persson #include <fs/sockfs/sodirect.h>
35bbc000e5SAnders Persson 
36bbc000e5SAnders Persson /*
37bbc000e5SAnders Persson  * In support of on-board asynchronous DMA hardware (e.g. Intel I/OAT)
38bbc000e5SAnders Persson  * we use a consolidation private KAPI to allow the protocol to start
39bbc000e5SAnders Persson  * an asynchronous copyout to a user-land receive-side buffer (uioa)
40bbc000e5SAnders Persson  * when a blocking socket read (e.g. read, recv, ...) is pending.
41bbc000e5SAnders Persson  *
42bbc000e5SAnders Persson  * In some broad strokes, this is what happens. When recv is called,
43bbc000e5SAnders Persson  * we first determine whether it would be beneficial to use uioa, and
44bbc000e5SAnders Persson  * if so set up the required state (all done by sod_rcv_init()).
45bbc000e5SAnders Persson  * The protocol can only initiate asynchronous copyout if the receive
46bbc000e5SAnders Persson  * queue is empty, so the first thing we do is drain any previously
47bbc000e5SAnders Persson  * queued data (using sod_uioa_so_init()). Once the copyouts (if any)
48bbc000e5SAnders Persson  * have been scheduled we wait for the receive to be satisfied. During
49bbc000e5SAnders Persson  * that time any new mblks that are enqueued will be scheduled to be
50bbc000e5SAnders Persson  * copied out asynchronously (sod_uioa_mblk_init()). When the receive
51bbc000e5SAnders Persson  * has been satisfied we wait for all scheduled copyout operations to
52bbc000e5SAnders Persson  * complete before we return to the user (sod_rcv_done())
53bbc000e5SAnders Persson  */
54bbc000e5SAnders Persson 
55bbc000e5SAnders Persson static struct kmem_cache *sock_sod_cache;
56bbc000e5SAnders Persson 
57bbc000e5SAnders Persson /*
58bbc000e5SAnders Persson  * This function is called at the beginning of recvmsg().
59bbc000e5SAnders Persson  *
60bbc000e5SAnders Persson  * If I/OAT is enabled on this sonode, initialize the uioa state machine
61bbc000e5SAnders Persson  * with state UIOA_ALLOC.
62bbc000e5SAnders Persson  */
63bbc000e5SAnders Persson uio_t *
sod_rcv_init(struct sonode * so,int flags,struct uio ** uiopp)64bbc000e5SAnders Persson sod_rcv_init(struct sonode *so, int flags, struct uio **uiopp)
65bbc000e5SAnders Persson {
66bbc000e5SAnders Persson 	struct uio *suiop;
67bbc000e5SAnders Persson 	struct uio *uiop;
68bbc000e5SAnders Persson 	sodirect_t *sodp = so->so_direct;
69bbc000e5SAnders Persson 
70bbc000e5SAnders Persson 	if (sodp == NULL)
71bbc000e5SAnders Persson 		return (NULL);
72bbc000e5SAnders Persson 
73bbc000e5SAnders Persson 	suiop = NULL;
74bbc000e5SAnders Persson 	uiop = *uiopp;
75bbc000e5SAnders Persson 
76bbc000e5SAnders Persson 	mutex_enter(&so->so_lock);
77bbc000e5SAnders Persson 	if (uiop->uio_resid >= uioasync.mincnt &&
78bbc000e5SAnders Persson 	    sodp != NULL && sodp->sod_enabled &&
79bbc000e5SAnders Persson 	    uioasync.enabled && !(flags & MSG_PEEK) &&
80*3e95bd4aSAnders Persson 	    !so->so_proto_props.sopp_loopback && so->so_filter_active == 0 &&
81bbc000e5SAnders Persson 	    !(so->so_state & SS_CANTRCVMORE)) {
82bbc000e5SAnders Persson 		/*
83bbc000e5SAnders Persson 		 * Big enough I/O for uioa min setup and an sodirect socket
84bbc000e5SAnders Persson 		 * and sodirect enabled and uioa enabled and I/O will be done
85bbc000e5SAnders Persson 		 * and not EOF so initialize the sodirect_t uioa_t with "uiop".
86bbc000e5SAnders Persson 		 */
87bbc000e5SAnders Persson 		if (!uioainit(uiop, &sodp->sod_uioa)) {
88bbc000e5SAnders Persson 			/*
89bbc000e5SAnders Persson 			 * Successful uioainit() so the uio_t part of the
90bbc000e5SAnders Persson 			 * uioa_t will be used for all uio_t work to follow,
91bbc000e5SAnders Persson 			 * we return the original "uiop" in "suiop".
92bbc000e5SAnders Persson 			 */
93bbc000e5SAnders Persson 			suiop = uiop;
94bbc000e5SAnders Persson 			*uiopp = (uio_t *)&sodp->sod_uioa;
95bbc000e5SAnders Persson 			/*
96bbc000e5SAnders Persson 			 * Before returning to the caller the passed in uio_t
97bbc000e5SAnders Persson 			 * "uiop" will be updated via a call to uioafini()
98bbc000e5SAnders Persson 			 * below.
99bbc000e5SAnders Persson 			 *
100bbc000e5SAnders Persson 			 * Note, the uioa.uioa_state isn't set to UIOA_ENABLED
101bbc000e5SAnders Persson 			 * here as first we have to uioamove() any currently
102bbc000e5SAnders Persson 			 * queued M_DATA mblk_t(s) so it will be done later.
103bbc000e5SAnders Persson 			 */
104bbc000e5SAnders Persson 		}
105bbc000e5SAnders Persson 	}
106bbc000e5SAnders Persson 	mutex_exit(&so->so_lock);
107bbc000e5SAnders Persson 
108bbc000e5SAnders Persson 	return (suiop);
109bbc000e5SAnders Persson }
110bbc000e5SAnders Persson 
111bbc000e5SAnders Persson /*
112bbc000e5SAnders Persson  * This function is called at the end of recvmsg(), it finializes all the I/OAT
113bbc000e5SAnders Persson  * operations, and reset the uioa state to UIOA_ALLOC.
114bbc000e5SAnders Persson  */
115bbc000e5SAnders Persson int
sod_rcv_done(struct sonode * so,struct uio * suiop,struct uio * uiop)116bbc000e5SAnders Persson sod_rcv_done(struct sonode *so, struct uio *suiop, struct uio *uiop)
117bbc000e5SAnders Persson {
118bbc000e5SAnders Persson 	int error = 0;
119bbc000e5SAnders Persson 	sodirect_t *sodp = so->so_direct;
120bbc000e5SAnders Persson 	mblk_t *mp;
121bbc000e5SAnders Persson 
122bbc000e5SAnders Persson 	if (sodp == NULL) {
123bbc000e5SAnders Persson 		return (0);
124bbc000e5SAnders Persson 	}
125bbc000e5SAnders Persson 
126bbc000e5SAnders Persson 	ASSERT(MUTEX_HELD(&so->so_lock));
127bbc000e5SAnders Persson 	/* Finish any sodirect and uioa processing */
128bbc000e5SAnders Persson 	if (suiop != NULL) {
129bbc000e5SAnders Persson 		/* Finish any uioa_t processing */
130bbc000e5SAnders Persson 
131bbc000e5SAnders Persson 		ASSERT(uiop == (uio_t *)&sodp->sod_uioa);
132bbc000e5SAnders Persson 		error = uioafini(suiop, (uioa_t *)uiop);
133bbc000e5SAnders Persson 		if ((mp = sodp->sod_uioafh) != NULL) {
134bbc000e5SAnders Persson 			sodp->sod_uioafh = NULL;
135bbc000e5SAnders Persson 			sodp->sod_uioaft = NULL;
136bbc000e5SAnders Persson 			freemsg(mp);
137bbc000e5SAnders Persson 		}
138bbc000e5SAnders Persson 	}
139bbc000e5SAnders Persson 	ASSERT(sodp->sod_uioafh == NULL);
140bbc000e5SAnders Persson 
141bbc000e5SAnders Persson 	return (error);
142bbc000e5SAnders Persson }
143bbc000e5SAnders Persson 
144bbc000e5SAnders Persson /*
145bbc000e5SAnders Persson  * Schedule a uioamove() on a mblk. This is done as mblks are enqueued
146bbc000e5SAnders Persson  * by the protocol on the socket's rcv queue.
147bbc000e5SAnders Persson  *
148bbc000e5SAnders Persson  * Caller must be holding so_lock.
149bbc000e5SAnders Persson  */
150bbc000e5SAnders Persson void
sod_uioa_mblk_init(struct sodirect_s * sodp,mblk_t * mp,size_t msg_size)151bbc000e5SAnders Persson sod_uioa_mblk_init(struct sodirect_s *sodp, mblk_t *mp, size_t msg_size)
152bbc000e5SAnders Persson {
153bbc000e5SAnders Persson 	uioa_t *uioap = &sodp->sod_uioa;
154bbc000e5SAnders Persson 	mblk_t *mp1 = mp;
155bbc000e5SAnders Persson 	mblk_t *lmp = NULL;
156bbc000e5SAnders Persson 
157bbc000e5SAnders Persson 	ASSERT(DB_TYPE(mp) == M_DATA);
158bbc000e5SAnders Persson 	ASSERT(msg_size == msgdsize(mp));
159bbc000e5SAnders Persson 
160bbc000e5SAnders Persson 	if (uioap->uioa_state & UIOA_ENABLED) {
161bbc000e5SAnders Persson 		/* Uioa is enabled */
162bbc000e5SAnders Persson 
163bbc000e5SAnders Persson 		if (msg_size > uioap->uio_resid) {
164bbc000e5SAnders Persson 			/*
165bbc000e5SAnders Persson 			 * There isn't enough uio space for the mblk_t chain
166bbc000e5SAnders Persson 			 * so disable uioa such that this and any additional
167bbc000e5SAnders Persson 			 * mblk_t data is handled by the socket and schedule
168bbc000e5SAnders Persson 			 * the socket for wakeup to finish this uioa.
169bbc000e5SAnders Persson 			 */
170bbc000e5SAnders Persson 			uioap->uioa_state &= UIOA_CLR;
171bbc000e5SAnders Persson 			uioap->uioa_state |= UIOA_FINI;
172bbc000e5SAnders Persson 			return;
173bbc000e5SAnders Persson 		}
174bbc000e5SAnders Persson 		do {
175bbc000e5SAnders Persson 			uint32_t	len = MBLKL(mp1);
176bbc000e5SAnders Persson 
177bbc000e5SAnders Persson 			if (!uioamove(mp1->b_rptr, len, UIO_READ, uioap)) {
178bbc000e5SAnders Persson 				/* Scheduled, mark dblk_t as such */
179bbc000e5SAnders Persson 				DB_FLAGS(mp1) |= DBLK_UIOA;
180bbc000e5SAnders Persson 			} else {
181bbc000e5SAnders Persson 				/* Error, turn off async processing */
182bbc000e5SAnders Persson 				uioap->uioa_state &= UIOA_CLR;
183bbc000e5SAnders Persson 				uioap->uioa_state |= UIOA_FINI;
184bbc000e5SAnders Persson 				break;
185bbc000e5SAnders Persson 			}
186bbc000e5SAnders Persson 			lmp = mp1;
187bbc000e5SAnders Persson 		} while ((mp1 = mp1->b_cont) != NULL);
188bbc000e5SAnders Persson 
189bbc000e5SAnders Persson 		if (mp1 != NULL || uioap->uio_resid == 0) {
190bbc000e5SAnders Persson 			/* Break the mblk chain if neccessary. */
191bbc000e5SAnders Persson 			if (mp1 != NULL && lmp != NULL) {
192bbc000e5SAnders Persson 				mp->b_next = mp1;
193bbc000e5SAnders Persson 				lmp->b_cont = NULL;
194bbc000e5SAnders Persson 			}
195bbc000e5SAnders Persson 		}
196bbc000e5SAnders Persson 	}
197bbc000e5SAnders Persson }
198bbc000e5SAnders Persson 
199bbc000e5SAnders Persson /*
200bbc000e5SAnders Persson  * This function is called on a mblk that thas been successfully uioamoved().
201bbc000e5SAnders Persson  */
202bbc000e5SAnders Persson void
sod_uioa_mblk_done(sodirect_t * sodp,mblk_t * bp)203bbc000e5SAnders Persson sod_uioa_mblk_done(sodirect_t *sodp, mblk_t *bp)
204bbc000e5SAnders Persson {
205bbc000e5SAnders Persson 	if (bp != NULL && (bp->b_datap->db_flags & DBLK_UIOA)) {
206bbc000e5SAnders Persson 		/*
207bbc000e5SAnders Persson 		 * A uioa flaged mblk_t chain, already uio processed,
208bbc000e5SAnders Persson 		 * add it to the sodirect uioa pending free list.
209bbc000e5SAnders Persson 		 *
210bbc000e5SAnders Persson 		 * Note, a b_cont chain headed by a DBLK_UIOA enable
211bbc000e5SAnders Persson 		 * mblk_t must have all mblk_t(s) DBLK_UIOA enabled.
212bbc000e5SAnders Persson 		 */
213bbc000e5SAnders Persson 		mblk_t	*bpt = sodp->sod_uioaft;
214bbc000e5SAnders Persson 
215bbc000e5SAnders Persson 		ASSERT(sodp != NULL);
216bbc000e5SAnders Persson 
217bbc000e5SAnders Persson 		/*
218bbc000e5SAnders Persson 		 * Add first mblk_t of "bp" chain to current sodirect uioa
219bbc000e5SAnders Persson 		 * free list tail mblk_t, if any, else empty list so new head.
220bbc000e5SAnders Persson 		 */
221bbc000e5SAnders Persson 		if (bpt == NULL)
222bbc000e5SAnders Persson 			sodp->sod_uioafh = bp;
223bbc000e5SAnders Persson 		else
224bbc000e5SAnders Persson 			bpt->b_cont = bp;
225bbc000e5SAnders Persson 
226bbc000e5SAnders Persson 		/*
227bbc000e5SAnders Persson 		 * Walk mblk_t "bp" chain to find tail and adjust rptr of
228bbc000e5SAnders Persson 		 * each to reflect that uioamove() has consumed all data.
229bbc000e5SAnders Persson 		 */
230bbc000e5SAnders Persson 		bpt = bp;
231bbc000e5SAnders Persson 		for (;;) {
232bbc000e5SAnders Persson 			ASSERT(bpt->b_datap->db_flags & DBLK_UIOA);
233bbc000e5SAnders Persson 
234bbc000e5SAnders Persson 			bpt->b_rptr = bpt->b_wptr;
235bbc000e5SAnders Persson 			if (bpt->b_cont == NULL)
236bbc000e5SAnders Persson 				break;
237bbc000e5SAnders Persson 			bpt = bpt->b_cont;
238bbc000e5SAnders Persson 		}
239bbc000e5SAnders Persson 		/* New sodirect uioa free list tail */
240bbc000e5SAnders Persson 		sodp->sod_uioaft = bpt;
241bbc000e5SAnders Persson 
242bbc000e5SAnders Persson 		/* Only dequeue once with data returned per uioa_t */
243bbc000e5SAnders Persson 		if (sodp->sod_uioa.uioa_state & UIOA_ENABLED) {
244bbc000e5SAnders Persson 			sodp->sod_uioa.uioa_state &= UIOA_CLR;
245bbc000e5SAnders Persson 			sodp->sod_uioa.uioa_state |= UIOA_FINI;
246bbc000e5SAnders Persson 		}
247bbc000e5SAnders Persson 	}
248bbc000e5SAnders Persson }
249bbc000e5SAnders Persson 
250bbc000e5SAnders Persson /*
251bbc000e5SAnders Persson  * When transit from UIOA_INIT state to UIOA_ENABLE state in recvmsg(), call
252bbc000e5SAnders Persson  * this function on a non-STREAMS socket to schedule uioamove() on the data
253bbc000e5SAnders Persson  * that has already queued in this socket.
254bbc000e5SAnders Persson  */
255bbc000e5SAnders Persson void
sod_uioa_so_init(struct sonode * so,struct sodirect_s * sodp,struct uio * uiop)256bbc000e5SAnders Persson sod_uioa_so_init(struct sonode *so, struct sodirect_s *sodp, struct uio *uiop)
257bbc000e5SAnders Persson {
258bbc000e5SAnders Persson 	uioa_t	*uioap = (uioa_t *)uiop;
259bbc000e5SAnders Persson 	mblk_t	*lbp;
260bbc000e5SAnders Persson 	mblk_t	*wbp;
261bbc000e5SAnders Persson 	mblk_t	*bp;
262bbc000e5SAnders Persson 	int	len;
263bbc000e5SAnders Persson 	int	error;
264bbc000e5SAnders Persson 	boolean_t in_rcv_q = B_TRUE;
265bbc000e5SAnders Persson 
266bbc000e5SAnders Persson 	ASSERT(MUTEX_HELD(&so->so_lock));
267bbc000e5SAnders Persson 	ASSERT(&sodp->sod_uioa == uioap);
268bbc000e5SAnders Persson 
269bbc000e5SAnders Persson 	/*
270bbc000e5SAnders Persson 	 * Walk first b_cont chain in sod_q
271bbc000e5SAnders Persson 	 * and schedule any M_DATA mblk_t's for uio asynchronous move.
272bbc000e5SAnders Persson 	 */
273bbc000e5SAnders Persson 	bp = so->so_rcv_q_head;
274bbc000e5SAnders Persson 
275bbc000e5SAnders Persson again:
276bbc000e5SAnders Persson 	/* Walk the chain */
277bbc000e5SAnders Persson 	lbp = NULL;
278bbc000e5SAnders Persson 	wbp = bp;
279bbc000e5SAnders Persson 
280bbc000e5SAnders Persson 	do {
281bbc000e5SAnders Persson 		if (bp == NULL)
282bbc000e5SAnders Persson 			break;
283bbc000e5SAnders Persson 
284bbc000e5SAnders Persson 		if (wbp->b_datap->db_type != M_DATA) {
285bbc000e5SAnders Persson 			/* Not M_DATA, no more uioa */
286bbc000e5SAnders Persson 			goto nouioa;
287bbc000e5SAnders Persson 		}
288bbc000e5SAnders Persson 		if ((len = wbp->b_wptr - wbp->b_rptr) > 0) {
289bbc000e5SAnders Persson 			/* Have a M_DATA mblk_t with data */
290bbc000e5SAnders Persson 			if (len > uioap->uio_resid || (so->so_oobmark > 0 &&
291bbc000e5SAnders Persson 			    len + uioap->uioa_mbytes >= so->so_oobmark)) {
292bbc000e5SAnders Persson 				/* Not enough uio sapce, or beyond oobmark */
293bbc000e5SAnders Persson 				goto nouioa;
294bbc000e5SAnders Persson 			}
295bbc000e5SAnders Persson 			ASSERT(!(wbp->b_datap->db_flags & DBLK_UIOA));
296bbc000e5SAnders Persson 			error = uioamove(wbp->b_rptr, len,
297bbc000e5SAnders Persson 			    UIO_READ, uioap);
298bbc000e5SAnders Persson 			if (!error) {
299bbc000e5SAnders Persson 				/* Scheduled, mark dblk_t as such */
300bbc000e5SAnders Persson 				wbp->b_datap->db_flags |= DBLK_UIOA;
301bbc000e5SAnders Persson 			} else {
302bbc000e5SAnders Persson 				/* Break the mblk chain */
303bbc000e5SAnders Persson 				goto nouioa;
304bbc000e5SAnders Persson 			}
305bbc000e5SAnders Persson 		}
306bbc000e5SAnders Persson 		/* Save last wbp processed */
307bbc000e5SAnders Persson 		lbp = wbp;
308bbc000e5SAnders Persson 	} while ((wbp = wbp->b_cont) != NULL);
309bbc000e5SAnders Persson 
310bbc000e5SAnders Persson 	if (in_rcv_q && (bp == NULL || bp->b_next == NULL)) {
311bbc000e5SAnders Persson 		/*
312bbc000e5SAnders Persson 		 * We get here only once to process the sonode dump area
313bbc000e5SAnders Persson 		 * if so_rcv_q_head is NULL or all the mblks have been
314bbc000e5SAnders Persson 		 * successfully uioamoved()ed.
315bbc000e5SAnders Persson 		 */
316bbc000e5SAnders Persson 		in_rcv_q = B_FALSE;
317bbc000e5SAnders Persson 
318bbc000e5SAnders Persson 		/* move to dump area */
319bbc000e5SAnders Persson 		bp = so->so_rcv_head;
320bbc000e5SAnders Persson 		goto again;
321bbc000e5SAnders Persson 	}
322bbc000e5SAnders Persson 
323bbc000e5SAnders Persson 	return;
324bbc000e5SAnders Persson 
325bbc000e5SAnders Persson nouioa:
326bbc000e5SAnders Persson 	/* No more uioa */
327bbc000e5SAnders Persson 	uioap->uioa_state &= UIOA_CLR;
328bbc000e5SAnders Persson 	uioap->uioa_state |= UIOA_FINI;
329bbc000e5SAnders Persson 
330bbc000e5SAnders Persson 	/*
331bbc000e5SAnders Persson 	 * If we processed 1 or more mblk_t(s) then we need to split the
332bbc000e5SAnders Persson 	 * current mblk_t chain in 2 so that all the uioamove()ed mblk_t(s)
333bbc000e5SAnders Persson 	 * are in the current chain and the rest are in the following new
334bbc000e5SAnders Persson 	 * chain.
335bbc000e5SAnders Persson 	 */
336bbc000e5SAnders Persson 	if (lbp != NULL) {
337bbc000e5SAnders Persson 		/* New end of current chain */
338bbc000e5SAnders Persson 		lbp->b_cont = NULL;
339bbc000e5SAnders Persson 
340bbc000e5SAnders Persson 		/* Insert new chain wbp after bp */
341bbc000e5SAnders Persson 		if ((wbp->b_next = bp->b_next) == NULL) {
342bbc000e5SAnders Persson 			if (in_rcv_q)
343bbc000e5SAnders Persson 				so->so_rcv_q_last_head = wbp;
344bbc000e5SAnders Persson 			else
345bbc000e5SAnders Persson 				so->so_rcv_last_head = wbp;
346bbc000e5SAnders Persson 		}
347bbc000e5SAnders Persson 		bp->b_next = wbp;
348bbc000e5SAnders Persson 		bp->b_next->b_prev = bp->b_prev;
349bbc000e5SAnders Persson 		bp->b_prev = lbp;
350bbc000e5SAnders Persson 	}
351bbc000e5SAnders Persson }
352bbc000e5SAnders Persson 
353bbc000e5SAnders Persson /*
354bbc000e5SAnders Persson  * Initialize sodirect data structures on a socket.
355bbc000e5SAnders Persson  */
356bbc000e5SAnders Persson void
sod_sock_init(struct sonode * so)357bbc000e5SAnders Persson sod_sock_init(struct sonode *so)
358bbc000e5SAnders Persson {
359bbc000e5SAnders Persson 	sodirect_t	*sodp;
360bbc000e5SAnders Persson 
361bbc000e5SAnders Persson 	ASSERT(so->so_direct == NULL);
362bbc000e5SAnders Persson 
363bbc000e5SAnders Persson 	so->so_state |= SS_SODIRECT;
364bbc000e5SAnders Persson 
365bbc000e5SAnders Persson 	sodp = kmem_cache_alloc(sock_sod_cache, KM_SLEEP);
366bbc000e5SAnders Persson 	sodp->sod_enabled = B_TRUE;
367bbc000e5SAnders Persson 	sodp->sod_uioafh = NULL;
368bbc000e5SAnders Persson 	sodp->sod_uioaft = NULL;
369bbc000e5SAnders Persson 	/*
370bbc000e5SAnders Persson 	 * Remainder of the sod_uioa members are left uninitialized
371bbc000e5SAnders Persson 	 * but will be initialized later by uioainit() before uioa
372bbc000e5SAnders Persson 	 * is enabled.
373bbc000e5SAnders Persson 	 */
374bbc000e5SAnders Persson 	sodp->sod_uioa.uioa_state = UIOA_ALLOC;
375bbc000e5SAnders Persson 	so->so_direct = sodp;
376bbc000e5SAnders Persson }
377bbc000e5SAnders Persson 
378bbc000e5SAnders Persson void
sod_sock_fini(struct sonode * so)379bbc000e5SAnders Persson sod_sock_fini(struct sonode *so)
380bbc000e5SAnders Persson {
381bbc000e5SAnders Persson 	sodirect_t *sodp = so->so_direct;
382bbc000e5SAnders Persson 
383bbc000e5SAnders Persson 	ASSERT(sodp->sod_uioafh == NULL);
384bbc000e5SAnders Persson 
385bbc000e5SAnders Persson 	so->so_direct = NULL;
386bbc000e5SAnders Persson 	kmem_cache_free(sock_sod_cache, sodp);
387bbc000e5SAnders Persson }
388bbc000e5SAnders Persson 
389bbc000e5SAnders Persson /*
390bbc000e5SAnders Persson  * Init the sodirect kmem cache while sockfs is loading.
391bbc000e5SAnders Persson  */
392bbc000e5SAnders Persson int
sod_init()393bbc000e5SAnders Persson sod_init()
394bbc000e5SAnders Persson {
395bbc000e5SAnders Persson 	/* Allocate sodirect_t kmem_cache */
396bbc000e5SAnders Persson 	sock_sod_cache = kmem_cache_create("sock_sod_cache",
397bbc000e5SAnders Persson 	    sizeof (sodirect_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
398bbc000e5SAnders Persson 
399bbc000e5SAnders Persson 	return (0);
400bbc000e5SAnders Persson }
401bbc000e5SAnders Persson 
402bbc000e5SAnders Persson ssize_t
sod_uioa_mblk(struct sonode * so,mblk_t * mp)403bbc000e5SAnders Persson sod_uioa_mblk(struct sonode *so, mblk_t *mp)
404bbc000e5SAnders Persson {
405bbc000e5SAnders Persson 	sodirect_t *sodp = so->so_direct;
406bbc000e5SAnders Persson 
407bbc000e5SAnders Persson 	ASSERT(sodp != NULL);
408bbc000e5SAnders Persson 	ASSERT(MUTEX_HELD(&so->so_lock));
409bbc000e5SAnders Persson 
410bbc000e5SAnders Persson 	ASSERT(sodp->sod_enabled);
411bbc000e5SAnders Persson 	ASSERT(sodp->sod_uioa.uioa_state != (UIOA_ALLOC|UIOA_INIT));
412bbc000e5SAnders Persson 
413bbc000e5SAnders Persson 	ASSERT(sodp->sod_uioa.uioa_state & (UIOA_ENABLED|UIOA_FINI));
414bbc000e5SAnders Persson 
415bbc000e5SAnders Persson 	if (mp == NULL && so->so_rcv_q_head != NULL) {
416bbc000e5SAnders Persson 		mp = so->so_rcv_q_head;
417bbc000e5SAnders Persson 		ASSERT(mp->b_prev != NULL);
418bbc000e5SAnders Persson 		mp->b_prev = NULL;
419bbc000e5SAnders Persson 		so->so_rcv_q_head = mp->b_next;
420bbc000e5SAnders Persson 		if (so->so_rcv_q_head == NULL) {
421bbc000e5SAnders Persson 			so->so_rcv_q_last_head = NULL;
422bbc000e5SAnders Persson 		}
423bbc000e5SAnders Persson 		mp->b_next = NULL;
424bbc000e5SAnders Persson 	}
425bbc000e5SAnders Persson 
426bbc000e5SAnders Persson 	sod_uioa_mblk_done(sodp, mp);
427bbc000e5SAnders Persson 
428bbc000e5SAnders Persson 	if (so->so_rcv_q_head == NULL && so->so_rcv_head != NULL &&
429bbc000e5SAnders Persson 	    DB_TYPE(so->so_rcv_head) == M_DATA &&
430bbc000e5SAnders Persson 	    (DB_FLAGS(so->so_rcv_head) & DBLK_UIOA)) {
431bbc000e5SAnders Persson 		/* more arrived */
432bbc000e5SAnders Persson 		ASSERT(so->so_rcv_q_head == NULL);
433bbc000e5SAnders Persson 		mp = so->so_rcv_head;
434bbc000e5SAnders Persson 		so->so_rcv_head = mp->b_next;
435bbc000e5SAnders Persson 		if (so->so_rcv_head == NULL)
436bbc000e5SAnders Persson 			so->so_rcv_last_head = NULL;
437bbc000e5SAnders Persson 		mp->b_prev = mp->b_next = NULL;
438bbc000e5SAnders Persson 		sod_uioa_mblk_done(sodp, mp);
439bbc000e5SAnders Persson 	}
440bbc000e5SAnders Persson 
441bbc000e5SAnders Persson #ifdef DEBUG
442bbc000e5SAnders Persson 	if (so->so_rcv_q_head != NULL) {
443bbc000e5SAnders Persson 		mblk_t *m = so->so_rcv_q_head;
444bbc000e5SAnders Persson 		while (m != NULL) {
445bbc000e5SAnders Persson 			if (DB_FLAGS(m) & DBLK_UIOA) {
446bbc000e5SAnders Persson 				cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p"
447bbc000e5SAnders Persson 				    " in so_rcv_q_head.\n", (void *)m);
448bbc000e5SAnders Persson 			}
449bbc000e5SAnders Persson 			m = m->b_next;
450bbc000e5SAnders Persson 		}
451bbc000e5SAnders Persson 	}
452bbc000e5SAnders Persson 	if (so->so_rcv_head != NULL) {
453bbc000e5SAnders Persson 		mblk_t *m = so->so_rcv_head;
454bbc000e5SAnders Persson 		while (m != NULL) {
455bbc000e5SAnders Persson 			if (DB_FLAGS(m) & DBLK_UIOA) {
456bbc000e5SAnders Persson 				cmn_err(CE_PANIC, "Unexpected I/OAT mblk %p"
457bbc000e5SAnders Persson 				    " in so_rcv_head.\n", (void *)m);
458bbc000e5SAnders Persson 			}
459bbc000e5SAnders Persson 			m = m->b_next;
460bbc000e5SAnders Persson 		}
461bbc000e5SAnders Persson 	}
462bbc000e5SAnders Persson #endif
463bbc000e5SAnders Persson 	return (sodp->sod_uioa.uioa_mbytes);
464bbc000e5SAnders Persson }
465