1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
22*897907ceSGordon Ross * Copyright 2011-2021 Tintri by DDN, Inc. All rights reserved.
232c2961f8Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24da6c28aaSamw * Use is subject to license terms.
25da6c28aaSamw */
26da6c28aaSamw
27da6c28aaSamw /*
28da6c28aaSamw * Copyright (c) 1982, 1986, 1988, 1991, 1993
29da6c28aaSamw * The Regents of the University of California. All rights reserved.
30da6c28aaSamw *
31da6c28aaSamw * Redistribution and use in source and binary forms, with or without
32da6c28aaSamw * modification, are permitted provided that the following conditions
33da6c28aaSamw * are met:
34da6c28aaSamw * 1. Redistributions of source code must retain the above copyright
35da6c28aaSamw * notice, this list of conditions and the following disclaimer.
36da6c28aaSamw * 2. Redistributions in binary form must reproduce the above copyright
37da6c28aaSamw * notice, this list of conditions and the following disclaimer in the
38da6c28aaSamw * documentation and/or other materials provided with the distribution.
39da6c28aaSamw * 3. All advertising materials mentioning features or use of this software
40da6c28aaSamw * must display the following acknowledgement:
41da6c28aaSamw * This product includes software developed by the University of
42da6c28aaSamw * California, Berkeley and its contributors.
43da6c28aaSamw * 4. Neither the name of the University nor the names of its contributors
44da6c28aaSamw * may be used to endorse or promote products derived from this software
45da6c28aaSamw * without specific prior written permission.
46da6c28aaSamw *
47da6c28aaSamw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48da6c28aaSamw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49da6c28aaSamw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50da6c28aaSamw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51da6c28aaSamw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52da6c28aaSamw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53da6c28aaSamw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54da6c28aaSamw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55da6c28aaSamw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56da6c28aaSamw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57da6c28aaSamw * SUCH DAMAGE.
58da6c28aaSamw *
59da6c28aaSamw */
60da6c28aaSamw
61bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
622c2961f8Sjose borrego #include <smbsrv/smb_kstat.h>
632c2961f8Sjose borrego
642c2961f8Sjose borrego static kmem_cache_t *smb_mbc_cache = NULL;
65a90cf9f2SGordon Ross static kmem_cache_t *smb_mbuf_cache = NULL;
66a90cf9f2SGordon Ross static kmem_cache_t *smb_mbufcl_cache = NULL;
672c2961f8Sjose borrego
68*897907ceSGordon Ross /* Perhaps move this to libfakekernel? */
69*897907ceSGordon Ross #ifdef _FAKE_KERNEL
70*897907ceSGordon Ross size_t kmem_max_cached = 0x20000; // UMEM_MAXBUF
71*897907ceSGordon Ross #endif
72*897907ceSGordon Ross
738622ec45SGordon Ross void
smb_mbc_init(void)742c2961f8Sjose borrego smb_mbc_init(void)
752c2961f8Sjose borrego {
768622ec45SGordon Ross if (smb_mbc_cache != NULL)
778622ec45SGordon Ross return;
788622ec45SGordon Ross smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
798622ec45SGordon Ross sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
80a90cf9f2SGordon Ross
81a90cf9f2SGordon Ross smb_mbuf_cache = kmem_cache_create("smb_mbuf_cache",
82a90cf9f2SGordon Ross sizeof (mbuf_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
83a90cf9f2SGordon Ross
84a90cf9f2SGordon Ross smb_mbufcl_cache = kmem_cache_create("smb_mbufcl_cache",
85a90cf9f2SGordon Ross MCLBYTES, 8, NULL, NULL, NULL, NULL, NULL, 0);
862c2961f8Sjose borrego }
872c2961f8Sjose borrego
882c2961f8Sjose borrego void
smb_mbc_fini(void)892c2961f8Sjose borrego smb_mbc_fini(void)
902c2961f8Sjose borrego {
912c2961f8Sjose borrego if (smb_mbc_cache != NULL) {
922c2961f8Sjose borrego kmem_cache_destroy(smb_mbc_cache);
932c2961f8Sjose borrego smb_mbc_cache = NULL;
942c2961f8Sjose borrego }
95a90cf9f2SGordon Ross if (smb_mbuf_cache != NULL) {
96a90cf9f2SGordon Ross kmem_cache_destroy(smb_mbuf_cache);
97a90cf9f2SGordon Ross smb_mbuf_cache = NULL;
98a90cf9f2SGordon Ross }
99a90cf9f2SGordon Ross if (smb_mbufcl_cache != NULL) {
100a90cf9f2SGordon Ross kmem_cache_destroy(smb_mbufcl_cache);
101a90cf9f2SGordon Ross smb_mbufcl_cache = NULL;
102a90cf9f2SGordon Ross }
1032c2961f8Sjose borrego }
1042c2961f8Sjose borrego
1052c2961f8Sjose borrego mbuf_chain_t *
smb_mbc_alloc(uint32_t max_bytes)1062c2961f8Sjose borrego smb_mbc_alloc(uint32_t max_bytes)
1072c2961f8Sjose borrego {
1082c2961f8Sjose borrego mbuf_chain_t *mbc;
1092c2961f8Sjose borrego mbuf_t *m;
1102c2961f8Sjose borrego
1112c2961f8Sjose borrego mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
1122c2961f8Sjose borrego bzero(mbc, sizeof (*mbc));
1132c2961f8Sjose borrego mbc->mbc_magic = SMB_MBC_MAGIC;
1142c2961f8Sjose borrego
1152c2961f8Sjose borrego if (max_bytes != 0) {
1162c2961f8Sjose borrego MGET(m, M_WAIT, MT_DATA);
1172c2961f8Sjose borrego m->m_len = 0;
1182c2961f8Sjose borrego mbc->chain = m;
1192c2961f8Sjose borrego if (max_bytes > MINCLSIZE)
1202c2961f8Sjose borrego MCLGET(m, M_WAIT);
1212c2961f8Sjose borrego }
1222c2961f8Sjose borrego mbc->max_bytes = max_bytes;
1232c2961f8Sjose borrego return (mbc);
1242c2961f8Sjose borrego }
1252c2961f8Sjose borrego
1262c2961f8Sjose borrego void
smb_mbc_free(mbuf_chain_t * mbc)1272c2961f8Sjose borrego smb_mbc_free(mbuf_chain_t *mbc)
1282c2961f8Sjose borrego {
1292c2961f8Sjose borrego SMB_MBC_VALID(mbc);
1302c2961f8Sjose borrego
1312c2961f8Sjose borrego m_freem(mbc->chain);
1322c2961f8Sjose borrego mbc->chain = NULL;
1332c2961f8Sjose borrego mbc->mbc_magic = 0;
1342c2961f8Sjose borrego kmem_cache_free(smb_mbc_cache, mbc);
1352c2961f8Sjose borrego }
136da6c28aaSamw
137da6c28aaSamw /*
138da6c28aaSamw * smb_mbuf_get
139da6c28aaSamw *
140da6c28aaSamw * Allocate mbufs to hold the amount of data specified.
141da6c28aaSamw * A pointer to the head of the mbuf list is returned.
142da6c28aaSamw */
143da6c28aaSamw struct mbuf *
smb_mbuf_get(uchar_t * buf,int nbytes)144da6c28aaSamw smb_mbuf_get(uchar_t *buf, int nbytes)
145da6c28aaSamw {
146da6c28aaSamw struct mbuf *mhead = 0;
147da6c28aaSamw struct mbuf *m = 0;
148da6c28aaSamw int count;
149da6c28aaSamw int offset = 0;
150da6c28aaSamw
151da6c28aaSamw while (nbytes) {
152da6c28aaSamw count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
153da6c28aaSamw nbytes -= count;
154da6c28aaSamw
155da6c28aaSamw if (mhead == 0) {
156da6c28aaSamw MGET(mhead, M_WAIT, MT_DATA);
157da6c28aaSamw m = mhead;
158da6c28aaSamw } else {
159da6c28aaSamw MGET(m->m_next, M_WAIT, MT_DATA);
160da6c28aaSamw m = m->m_next;
161da6c28aaSamw }
162da6c28aaSamw
163da6c28aaSamw if (count > MLEN) {
164da6c28aaSamw MCLGET(m, M_WAIT);
165da6c28aaSamw }
166da6c28aaSamw
167da6c28aaSamw m->m_len = count;
168da6c28aaSamw bcopy(buf + offset, m->m_data, count);
169da6c28aaSamw offset += count;
170da6c28aaSamw }
171da6c28aaSamw return (mhead);
172da6c28aaSamw }
173da6c28aaSamw
174*897907ceSGordon Ross /*
175*897907ceSGordon Ross * Build an mbuf with external storage
176*897907ceSGordon Ross * Like esballoca()
177*897907ceSGordon Ross */
178*897907ceSGordon Ross mbuf_t *
smb_mbuf_alloc_ext(caddr_t buf,int len,m_ext_free_t ff,void * arg)179*897907ceSGordon Ross smb_mbuf_alloc_ext(caddr_t buf, int len, m_ext_free_t ff, void *arg)
180a90cf9f2SGordon Ross {
181*897907ceSGordon Ross mbuf_t *m = 0;
182*897907ceSGordon Ross
183*897907ceSGordon Ross MGET(m, M_WAIT, MT_DATA);
184*897907ceSGordon Ross
185*897907ceSGordon Ross /* Like MCLGET(), but external buf. */
186*897907ceSGordon Ross m->m_ext.ext_buf = buf;
187*897907ceSGordon Ross m->m_data = m->m_ext.ext_buf;
188*897907ceSGordon Ross m->m_flags |= M_EXT;
189*897907ceSGordon Ross m->m_ext.ext_size = len;
190*897907ceSGordon Ross m->m_ext.ext_free = ff;
191*897907ceSGordon Ross m->m_ext.ext_arg1 = arg;
192*897907ceSGordon Ross
193*897907ceSGordon Ross m->m_len = len;
194*897907ceSGordon Ross
195*897907ceSGordon Ross return (m);
196*897907ceSGordon Ross }
197*897907ceSGordon Ross
198*897907ceSGordon Ross static void
smb_mbuf_kmem_free(mbuf_t * m)199*897907ceSGordon Ross smb_mbuf_kmem_free(mbuf_t *m)
200*897907ceSGordon Ross {
201*897907ceSGordon Ross ASSERT((m->m_flags & M_EXT) != 0);
202*897907ceSGordon Ross
203*897907ceSGordon Ross kmem_free(m->m_ext.ext_buf, m->m_ext.ext_size);
204*897907ceSGordon Ross /* Caller sets m->m_ext.ext_buf = NULL */
205*897907ceSGordon Ross }
206*897907ceSGordon Ross
207*897907ceSGordon Ross /*
208*897907ceSGordon Ross * Allocate one mbuf with contiguous (external) storage
209*897907ceSGordon Ross * obtained via kmem_alloc. Most places should be using
210*897907ceSGordon Ross * smb_mbuf_alloc_chain below.
211*897907ceSGordon Ross */
212*897907ceSGordon Ross mbuf_t *
smb_mbuf_alloc_kmem(int len)213*897907ceSGordon Ross smb_mbuf_alloc_kmem(int len)
214*897907ceSGordon Ross {
215*897907ceSGordon Ross mbuf_t *m;
216*897907ceSGordon Ross caddr_t buf;
217*897907ceSGordon Ross
218*897907ceSGordon Ross VERIFY(len > 0);
219*897907ceSGordon Ross #ifdef DEBUG
220*897907ceSGordon Ross if (len > kmem_max_cached) {
221*897907ceSGordon Ross debug_enter("fix caller");
222*897907ceSGordon Ross }
223*897907ceSGordon Ross #endif
224*897907ceSGordon Ross
225*897907ceSGordon Ross buf = kmem_alloc(len, KM_SLEEP);
226*897907ceSGordon Ross m = smb_mbuf_alloc_ext(buf, len, smb_mbuf_kmem_free, NULL);
227*897907ceSGordon Ross
228*897907ceSGordon Ross return (m);
229*897907ceSGordon Ross }
230*897907ceSGordon Ross
231*897907ceSGordon Ross /*
232*897907ceSGordon Ross * smb_mbuf_alloc_chain
233*897907ceSGordon Ross *
234*897907ceSGordon Ross * Allocate mbufs to hold the amount of data specified.
235*897907ceSGordon Ross * A pointer to the head of the mbuf chain is returned.
236*897907ceSGordon Ross *
237*897907ceSGordon Ross * For large messages, put the large mbufs at the tail, starting with
238*897907ceSGordon Ross * kmem_max_cached messages (128K) and then a shorter (eg MCLBYTES)
239*897907ceSGordon Ross * message at the front where we're more likely to need to copy.
240*897907ceSGordon Ross *
241*897907ceSGordon Ross * Must limit this to kmem_max_cached, to avoid contention with
242*897907ceSGordon Ross * allocating from kmem_oversize_arena.
243*897907ceSGordon Ross */
244*897907ceSGordon Ross struct mbuf *
smb_mbuf_alloc_chain(int nbytes)245*897907ceSGordon Ross smb_mbuf_alloc_chain(int nbytes)
246*897907ceSGordon Ross {
247*897907ceSGordon Ross struct mbuf *mhead = NULL;
248*897907ceSGordon Ross struct mbuf *m;
249*897907ceSGordon Ross int len; /* m_len for current mbuf */
250*897907ceSGordon Ross
251*897907ceSGordon Ross ASSERT(nbytes > 0);
252*897907ceSGordon Ross
253*897907ceSGordon Ross while (nbytes >= kmem_max_cached) {
254*897907ceSGordon Ross len = kmem_max_cached;
255*897907ceSGordon Ross m = smb_mbuf_alloc_kmem(len);
256*897907ceSGordon Ross
257*897907ceSGordon Ross /* prepend to chain at mhead */
258*897907ceSGordon Ross m->m_next = mhead;
259*897907ceSGordon Ross mhead = m;
260*897907ceSGordon Ross
261*897907ceSGordon Ross nbytes -= len;
262*897907ceSGordon Ross }
263*897907ceSGordon Ross
264*897907ceSGordon Ross if (nbytes > MCLBYTES) {
265*897907ceSGordon Ross len = nbytes;
266*897907ceSGordon Ross m = smb_mbuf_alloc_kmem(len);
267*897907ceSGordon Ross
268*897907ceSGordon Ross /* prepend to chain at mhead */
269*897907ceSGordon Ross m->m_next = mhead;
270*897907ceSGordon Ross mhead = m;
271*897907ceSGordon Ross
272*897907ceSGordon Ross nbytes -= len;
273*897907ceSGordon Ross } else if (nbytes > 0) {
274*897907ceSGordon Ross ASSERT(nbytes <= MCLBYTES);
275*897907ceSGordon Ross len = nbytes;
276*897907ceSGordon Ross MGET(m, M_WAIT, MT_DATA);
277*897907ceSGordon Ross if (len > MLEN) {
278*897907ceSGordon Ross MCLGET(m, M_WAIT);
279*897907ceSGordon Ross }
280*897907ceSGordon Ross m->m_len = len;
281*897907ceSGordon Ross
282*897907ceSGordon Ross /* prepend to chain at mhead */
283*897907ceSGordon Ross m->m_next = mhead;
284*897907ceSGordon Ross mhead = m;
285*897907ceSGordon Ross
286*897907ceSGordon Ross nbytes -= len;
287*897907ceSGordon Ross }
288*897907ceSGordon Ross
289*897907ceSGordon Ross return (mhead);
290a90cf9f2SGordon Ross }
291a90cf9f2SGordon Ross
292da6c28aaSamw /*
293a90cf9f2SGordon Ross * Allocate enough mbufs to accommodate the residual count in uio,
294*897907ceSGordon Ross * and setup the uio_iov to point to them. Note that uio->uio_iov
295*897907ceSGordon Ross * is allocated by the call and has MAX_IOVEC elements. Currently
296*897907ceSGordon Ross * the uio passed is always part of an smb_vdb_t and starts with
297*897907ceSGordon Ross * uio->uio_iovcnt = MAX_IOVEC;
298a90cf9f2SGordon Ross *
299a90cf9f2SGordon Ross * This is used by the various SMB read code paths. That code is
300*897907ceSGordon Ross * going to do a disk read into this buffer, so we'd like the
301*897907ceSGordon Ross * segments to be large. See smb_mbuf_alloc_chain().
302da6c28aaSamw */
303da6c28aaSamw struct mbuf *
smb_mbuf_allocate(struct uio * uio)304da6c28aaSamw smb_mbuf_allocate(struct uio *uio)
305da6c28aaSamw {
306*897907ceSGordon Ross mbuf_t *mhead;
307*897907ceSGordon Ross int rc;
308a90cf9f2SGordon Ross
309*897907ceSGordon Ross ASSERT(uio->uio_resid > 0);
310*897907ceSGordon Ross ASSERT(uio->uio_iovcnt == MAX_IOVEC);
311da6c28aaSamw
312*897907ceSGordon Ross mhead = smb_mbuf_alloc_chain(uio->uio_resid);
313a90cf9f2SGordon Ross
314*897907ceSGordon Ross rc = smb_mbuf_mkuio(mhead, uio);
315*897907ceSGordon Ross VERIFY(rc == 0);
316*897907ceSGordon Ross
317*897907ceSGordon Ross return (mhead);
318*897907ceSGordon Ross }
319*897907ceSGordon Ross
320*897907ceSGordon Ross /*
321*897907ceSGordon Ross * Build an iovec for an mbuf chain.
322*897907ceSGordon Ross *
323*897907ceSGordon Ross * The resulting iovec covers uio_resid length in the chain,
324*897907ceSGordon Ross * which could be shorter than the mbuf chain total length.
325*897907ceSGordon Ross *
326*897907ceSGordon Ross * uio->uio_iovcnt is allocated size on entry, used size on return.
327*897907ceSGordon Ross * Errors if iovec too small or mbuf chain too short.
328*897907ceSGordon Ross */
329*897907ceSGordon Ross int
smb_mbuf_mkuio(mbuf_t * m,uio_t * uio)330*897907ceSGordon Ross smb_mbuf_mkuio(mbuf_t *m, uio_t *uio)
331*897907ceSGordon Ross {
332*897907ceSGordon Ross iovec_t *iov;
333*897907ceSGordon Ross ssize_t off = 0;
334*897907ceSGordon Ross int iovcnt = 0;
335*897907ceSGordon Ross int tlen;
336*897907ceSGordon Ross
337*897907ceSGordon Ross iov = uio->uio_iov;
338*897907ceSGordon Ross while (off < uio->uio_resid) {
339*897907ceSGordon Ross if (m == NULL)
340*897907ceSGordon Ross return (EFAULT);
341*897907ceSGordon Ross if (iovcnt >= uio->uio_iovcnt)
342*897907ceSGordon Ross return (E2BIG);
343*897907ceSGordon Ross tlen = m->m_len;
344*897907ceSGordon Ross if ((off + tlen) > uio->uio_resid)
345*897907ceSGordon Ross tlen = (int)(uio->uio_resid - off);
346*897907ceSGordon Ross iov->iov_base = m->m_data;
347*897907ceSGordon Ross iov->iov_len = tlen;
348*897907ceSGordon Ross off += tlen;
349*897907ceSGordon Ross m = m->m_next;
350*897907ceSGordon Ross iovcnt++;
351*897907ceSGordon Ross iov++;
352*897907ceSGordon Ross }
353*897907ceSGordon Ross uio->uio_iovcnt = iovcnt;
354*897907ceSGordon Ross
355*897907ceSGordon Ross return (0);
356da6c28aaSamw }
357da6c28aaSamw
358da6c28aaSamw /*
359da6c28aaSamw * Trim an mbuf chain to nbytes.
360da6c28aaSamw */
361da6c28aaSamw void
smb_mbuf_trim(struct mbuf * mhead,int nbytes)362da6c28aaSamw smb_mbuf_trim(struct mbuf *mhead, int nbytes)
363da6c28aaSamw {
364da6c28aaSamw struct mbuf *m = mhead;
365da6c28aaSamw
366da6c28aaSamw while (m != 0) {
367da6c28aaSamw if (nbytes <= m->m_len) {
368da6c28aaSamw m->m_len = nbytes;
369da6c28aaSamw if (m->m_next != 0) {
370da6c28aaSamw m_freem(m->m_next);
371da6c28aaSamw m->m_next = 0;
372da6c28aaSamw }
373da6c28aaSamw break;
374da6c28aaSamw }
375da6c28aaSamw nbytes -= m->m_len;
376da6c28aaSamw m = m->m_next;
377da6c28aaSamw }
378da6c28aaSamw }
379da6c28aaSamw
380da6c28aaSamw int
MBC_LENGTH(struct mbuf_chain * MBC)381da6c28aaSamw MBC_LENGTH(struct mbuf_chain *MBC)
382da6c28aaSamw {
383da6c28aaSamw struct mbuf *m = (MBC)->chain;
384da6c28aaSamw int used = 0;
385da6c28aaSamw
386da6c28aaSamw while (m != 0) {
387da6c28aaSamw used += m->m_len;
388da6c28aaSamw m = m->m_next;
389da6c28aaSamw }
390da6c28aaSamw return (used);
391da6c28aaSamw }
392da6c28aaSamw
3933ad684d6Sjb int
MBC_MAXBYTES(struct mbuf_chain * MBC)3943ad684d6Sjb MBC_MAXBYTES(struct mbuf_chain *MBC)
3953ad684d6Sjb {
3963ad684d6Sjb return (MBC->max_bytes);
3973ad684d6Sjb }
3983ad684d6Sjb
399da6c28aaSamw void
MBC_SETUP(struct mbuf_chain * MBC,uint32_t max_bytes)400da6c28aaSamw MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
401da6c28aaSamw {
402da6c28aaSamw bzero((MBC), sizeof (struct mbuf_chain));
4037f3ef643SGordon Ross (MBC)->max_bytes = max_bytes;
404da6c28aaSamw }
405da6c28aaSamw
406*897907ceSGordon Ross /*
407*897907ceSGordon Ross * Initialize an mbuf chain and allocate the first message (if max_bytes
408*897907ceSGordon Ross * is specified). Leave some prepend space at the head.
409*897907ceSGordon Ross */
410da6c28aaSamw void
MBC_INIT(struct mbuf_chain * MBC,uint32_t max_bytes)411da6c28aaSamw MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
412da6c28aaSamw {
413da6c28aaSamw struct mbuf *m;
414da6c28aaSamw
415da6c28aaSamw bzero((MBC), sizeof (struct mbuf_chain));
416da6c28aaSamw
417da6c28aaSamw if (max_bytes != 0) {
418da6c28aaSamw MGET(m, M_WAIT, MT_DATA);
419da6c28aaSamw m->m_len = 0;
420da6c28aaSamw (MBC)->chain = m;
421da6c28aaSamw if (max_bytes > MINCLSIZE)
422da6c28aaSamw MCLGET(m, M_WAIT);
423*897907ceSGordon Ross m->m_data += MH_PREPEND_SPACE;
424da6c28aaSamw }
425da6c28aaSamw (MBC)->max_bytes = max_bytes;
426da6c28aaSamw }
427da6c28aaSamw
428da6c28aaSamw void
MBC_FLUSH(struct mbuf_chain * MBC)429da6c28aaSamw MBC_FLUSH(struct mbuf_chain *MBC)
430da6c28aaSamw {
431da6c28aaSamw extern void m_freem(struct mbuf *);
432da6c28aaSamw struct mbuf *m;
433da6c28aaSamw
434da6c28aaSamw while ((m = (MBC)->chain) != 0) {
435da6c28aaSamw (MBC)->chain = m->m_nextpkt;
436da6c28aaSamw m->m_nextpkt = 0;
437da6c28aaSamw m_freem(m);
438da6c28aaSamw }
439da6c28aaSamw MBC_SETUP(MBC, (MBC)->max_bytes);
440da6c28aaSamw }
441da6c28aaSamw
442da6c28aaSamw void
MBC_ATTACH_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)443da6c28aaSamw MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
444da6c28aaSamw {
445da6c28aaSamw if (MBC->chain != 0)
446da6c28aaSamw MBC_FLUSH(MBC);
447da6c28aaSamw
448da6c28aaSamw (MBC)->chain_offset = 0;
449da6c28aaSamw (MBC)->chain = (MBUF);
450da6c28aaSamw }
451da6c28aaSamw
452da6c28aaSamw void
MBC_APPEND_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)453da6c28aaSamw MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
454da6c28aaSamw {
455da6c28aaSamw struct mbuf *m;
456da6c28aaSamw
457da6c28aaSamw if ((MBC)->chain == 0) {
458da6c28aaSamw (MBC)->chain = (MBUF);
459da6c28aaSamw } else {
460da6c28aaSamw m = (MBC)->chain;
461da6c28aaSamw while (m->m_next != 0)
462da6c28aaSamw m = m->m_next;
463da6c28aaSamw m->m_next = (MBUF);
464da6c28aaSamw }
465da6c28aaSamw }
466da6c28aaSamw
467*897907ceSGordon Ross static void /*ARGSUSED*/
mclrefnoop(mbuf_t * m)468*897907ceSGordon Ross mclrefnoop(mbuf_t *m)
469a90cf9f2SGordon Ross {
470a90cf9f2SGordon Ross }
471da6c28aaSamw
472da6c28aaSamw void
MBC_ATTACH_BUF(struct mbuf_chain * MBC,unsigned char * BUF,int LEN)473da6c28aaSamw MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
474da6c28aaSamw {
475da6c28aaSamw MGET((MBC)->chain, M_WAIT, MT_DATA);
476da6c28aaSamw (MBC)->chain_offset = 0;
477da6c28aaSamw (MBC)->chain->m_flags |= M_EXT;
478da6c28aaSamw (MBC)->chain->m_data = (caddr_t)(BUF);
479da6c28aaSamw (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
480da6c28aaSamw (MBC)->chain->m_len = (LEN);
481da6c28aaSamw (MBC)->chain->m_ext.ext_size = (LEN);
482*897907ceSGordon Ross (MBC)->chain->m_ext.ext_free = mclrefnoop;
483da6c28aaSamw (MBC)->max_bytes = (LEN);
484da6c28aaSamw }
485da6c28aaSamw
486da6c28aaSamw
487da6c28aaSamw int
MBC_SHADOW_CHAIN(struct mbuf_chain * submbc,struct mbuf_chain * mbc,int off,int len)488a90cf9f2SGordon Ross MBC_SHADOW_CHAIN(struct mbuf_chain *submbc, struct mbuf_chain *mbc,
489a90cf9f2SGordon Ross int off, int len)
490da6c28aaSamw {
491a90cf9f2SGordon Ross int x = off + len;
492a90cf9f2SGordon Ross
493a90cf9f2SGordon Ross if (off < 0 || len < 0 || x < 0 ||
494a90cf9f2SGordon Ross off > mbc->max_bytes || x > mbc->max_bytes)
495da6c28aaSamw return (EMSGSIZE);
496da6c28aaSamw
497a90cf9f2SGordon Ross *submbc = *mbc;
498a90cf9f2SGordon Ross submbc->chain_offset = off;
499a90cf9f2SGordon Ross submbc->max_bytes = x;
500a90cf9f2SGordon Ross submbc->shadow_of = mbc;
501da6c28aaSamw return (0);
502da6c28aaSamw }
503da6c28aaSamw
504*897907ceSGordon Ross /*
505*897907ceSGordon Ross * Trim req_len bytes from the message,
506*897907ceSGordon Ross * from head if > 0, else from tail.
507*897907ceSGordon Ross */
508*897907ceSGordon Ross void
m_adjust(struct mbuf * mp,int req_len)509*897907ceSGordon Ross m_adjust(struct mbuf *mp, int req_len)
510*897907ceSGordon Ross {
511*897907ceSGordon Ross int len = req_len;
512*897907ceSGordon Ross struct mbuf *m;
513*897907ceSGordon Ross
514*897907ceSGordon Ross if ((m = mp) == NULL)
515*897907ceSGordon Ross return;
516*897907ceSGordon Ross
517*897907ceSGordon Ross /*
518*897907ceSGordon Ross * We don't use the trim-from-tail case.
519*897907ceSGordon Ross * Using smb_mbuf_trim() for that.
520*897907ceSGordon Ross */
521*897907ceSGordon Ross VERIFY(len >= 0);
522*897907ceSGordon Ross
523*897907ceSGordon Ross /*
524*897907ceSGordon Ross * Trim from head.
525*897907ceSGordon Ross */
526*897907ceSGordon Ross while (m != NULL && len > 0) {
527*897907ceSGordon Ross if (m->m_len <= len) {
528*897907ceSGordon Ross len -= m->m_len;
529*897907ceSGordon Ross m->m_len = 0;
530*897907ceSGordon Ross m = m->m_next;
531*897907ceSGordon Ross } else {
532*897907ceSGordon Ross m->m_len -= len;
533*897907ceSGordon Ross m->m_data += len;
534*897907ceSGordon Ross len = 0;
535*897907ceSGordon Ross }
536*897907ceSGordon Ross }
537*897907ceSGordon Ross }
538*897907ceSGordon Ross
539*897907ceSGordon Ross /*
540*897907ceSGordon Ross * Arrange to prepend space of size plen to mbuf m. If a new mbuf must be
541*897907ceSGordon Ross * allocated, how specifies whether to wait. If the allocation fails, the
542*897907ceSGordon Ross * original mbuf chain is freed and m is set to NULL.
543*897907ceSGordon Ross * BSD had a macro: M_PREPEND(m, plen, how)
544*897907ceSGordon Ross */
545*897907ceSGordon Ross
546*897907ceSGordon Ross struct mbuf *
m_prepend(struct mbuf * m,int plen,int how)547*897907ceSGordon Ross m_prepend(struct mbuf *m, int plen, int how)
548*897907ceSGordon Ross {
549*897907ceSGordon Ross struct mbuf *mn;
550*897907ceSGordon Ross
551*897907ceSGordon Ross if (M_LEADINGSPACE(m) >= plen) {
552*897907ceSGordon Ross m->m_data -= plen;
553*897907ceSGordon Ross m->m_len += plen;
554*897907ceSGordon Ross return (m);
555*897907ceSGordon Ross }
556*897907ceSGordon Ross if (m->m_flags & M_PKTHDR) {
557*897907ceSGordon Ross MGETHDR(mn, how, m->m_type);
558*897907ceSGordon Ross } else {
559*897907ceSGordon Ross MGET(mn, how, m->m_type);
560*897907ceSGordon Ross }
561*897907ceSGordon Ross VERIFY(mn != NULL);
562*897907ceSGordon Ross if (m->m_flags & M_PKTHDR) {
563*897907ceSGordon Ross // BSD: m_move_pkthdr(mn, m);
564*897907ceSGordon Ross // We don't use any pkthdr stuff.
565*897907ceSGordon Ross mn->m_pkthdr.len += plen;
566*897907ceSGordon Ross }
567*897907ceSGordon Ross mn->m_next = m;
568*897907ceSGordon Ross m = mn;
569*897907ceSGordon Ross if (plen < M_SIZE(m))
570*897907ceSGordon Ross M_ALIGN(m, plen);
571*897907ceSGordon Ross m->m_len = plen;
572*897907ceSGordon Ross DTRACE_PROBE1(prepend_allocated, struct mbuf *, m);
573*897907ceSGordon Ross return (m);
574*897907ceSGordon Ross }
575*897907ceSGordon Ross
576da6c28aaSamw /*
577da6c28aaSamw * Free a single mbuf structure. Calls m->m_ext.ext_ref() to free any
578da6c28aaSamw * associated external buffers if present (indicated by m->m_flags & M_EXT)
579da6c28aaSamw */
580da6c28aaSamw struct mbuf *
m_free(struct mbuf * m)581da6c28aaSamw m_free(struct mbuf *m)
582da6c28aaSamw {
583da6c28aaSamw struct mbuf *n;
584da6c28aaSamw
585da6c28aaSamw MFREE(m, n);
586da6c28aaSamw return (n);
587da6c28aaSamw }
588da6c28aaSamw
589da6c28aaSamw /*
590da6c28aaSamw * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free.
591da6c28aaSamw */
592da6c28aaSamw void
m_freem(struct mbuf * m)593da6c28aaSamw m_freem(struct mbuf *m)
594da6c28aaSamw {
595da6c28aaSamw struct mbuf *n;
596da6c28aaSamw
597da6c28aaSamw if (m == NULL)
598da6c28aaSamw return;
599da6c28aaSamw /*
600da6c28aaSamw * Lint doesn't like the m = n assignment at the close of the loop
601da6c28aaSamw * but it is correct. MFREE assigns n = (m)->m_next so the loop
602da6c28aaSamw * is effectively assigning m = (m)->m_next then exiting when
603da6c28aaSamw * m == NULL
604da6c28aaSamw */
605da6c28aaSamw do {
606da6c28aaSamw MFREE(m, n);
607da6c28aaSamw } while ((m = n) != 0);
608da6c28aaSamw }
609da6c28aaSamw
610da6c28aaSamw /*
611da6c28aaSamw * Mbuffer utility routines.
612da6c28aaSamw */
613da6c28aaSamw
614a90cf9f2SGordon Ross mbuf_t *
smb_mbuf_alloc(void)615a90cf9f2SGordon Ross smb_mbuf_alloc(void)
616da6c28aaSamw {
617a90cf9f2SGordon Ross mbuf_t *m;
618a90cf9f2SGordon Ross
619a90cf9f2SGordon Ross m = kmem_cache_alloc(smb_mbuf_cache, KM_SLEEP);
620a90cf9f2SGordon Ross bzero(m, sizeof (*m));
621a90cf9f2SGordon Ross return (m);
622da6c28aaSamw }
623da6c28aaSamw
624a90cf9f2SGordon Ross void
smb_mbuf_free(mbuf_t * m)625a90cf9f2SGordon Ross smb_mbuf_free(mbuf_t *m)
626a90cf9f2SGordon Ross {
627a90cf9f2SGordon Ross kmem_cache_free(smb_mbuf_cache, m);
628a90cf9f2SGordon Ross }
629a90cf9f2SGordon Ross
630a90cf9f2SGordon Ross void *
smb_mbufcl_alloc(void)631a90cf9f2SGordon Ross smb_mbufcl_alloc(void)
632a90cf9f2SGordon Ross {
633a90cf9f2SGordon Ross void *p;
634a90cf9f2SGordon Ross
635a90cf9f2SGordon Ross p = kmem_cache_alloc(smb_mbufcl_cache, KM_SLEEP);
636a90cf9f2SGordon Ross bzero(p, MCLBYTES);
637a90cf9f2SGordon Ross return (p);
638a90cf9f2SGordon Ross }
639a90cf9f2SGordon Ross
640a90cf9f2SGordon Ross void
smb_mbufcl_free(mbuf_t * m)641*897907ceSGordon Ross smb_mbufcl_free(mbuf_t *m)
642a90cf9f2SGordon Ross {
643*897907ceSGordon Ross ASSERT((m->m_flags & M_EXT) != 0);
644*897907ceSGordon Ross ASSERT(m->m_ext.ext_size == MCLBYTES);
645*897907ceSGordon Ross
646*897907ceSGordon Ross kmem_cache_free(smb_mbufcl_cache, m->m_ext.ext_buf);
647*897907ceSGordon Ross /* Caller sets m->m_ext.ext_buf = NULL */
648a90cf9f2SGordon Ross }
649a90cf9f2SGordon Ross
650a90cf9f2SGordon Ross int
smb_mbufcl_ref(void * p,uint_t sz,int incr)651a90cf9f2SGordon Ross smb_mbufcl_ref(void *p, uint_t sz, int incr)
652da6c28aaSamw {
653a90cf9f2SGordon Ross ASSERT3S(sz, ==, MCLBYTES);
654a90cf9f2SGordon Ross if (incr < 0)
655a90cf9f2SGordon Ross kmem_cache_free(smb_mbufcl_cache, p);
656da6c28aaSamw return (0);
657da6c28aaSamw }
658