zfs: allow large block/gzip/raidz for boot pools
[unleashed.git] / usr / src / uts / common / fs / smbsrv / smb_mbuf_util.c
blob86d37c8adbb7f66ef59fa853187e328a72031ccd
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 1982, 1986, 1988, 1991, 1993
29 * The Regents of the University of California. All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
61 #include <smbsrv/smb_kproto.h>
62 #include <smbsrv/smb_kstat.h>
64 static kmem_cache_t *smb_mbc_cache = NULL;
65 static kmem_cache_t *smb_mbuf_cache = NULL;
66 static kmem_cache_t *smb_mbufcl_cache = NULL;
68 void
69 smb_mbc_init(void)
71 if (smb_mbc_cache != NULL)
72 return;
73 smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
74 sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
76 smb_mbuf_cache = kmem_cache_create("smb_mbuf_cache",
77 sizeof (mbuf_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
79 smb_mbufcl_cache = kmem_cache_create("smb_mbufcl_cache",
80 MCLBYTES, 8, NULL, NULL, NULL, NULL, NULL, 0);
83 void
84 smb_mbc_fini(void)
86 if (smb_mbc_cache != NULL) {
87 kmem_cache_destroy(smb_mbc_cache);
88 smb_mbc_cache = NULL;
90 if (smb_mbuf_cache != NULL) {
91 kmem_cache_destroy(smb_mbuf_cache);
92 smb_mbuf_cache = NULL;
94 if (smb_mbufcl_cache != NULL) {
95 kmem_cache_destroy(smb_mbufcl_cache);
96 smb_mbufcl_cache = NULL;
100 mbuf_chain_t *
101 smb_mbc_alloc(uint32_t max_bytes)
103 mbuf_chain_t *mbc;
104 mbuf_t *m;
106 mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
107 bzero(mbc, sizeof (*mbc));
108 mbc->mbc_magic = SMB_MBC_MAGIC;
110 if (max_bytes != 0) {
111 MGET(m, M_WAIT, MT_DATA);
112 m->m_len = 0;
113 mbc->chain = m;
114 if (max_bytes > MINCLSIZE)
115 MCLGET(m, M_WAIT);
117 mbc->max_bytes = max_bytes;
118 return (mbc);
121 void
122 smb_mbc_free(mbuf_chain_t *mbc)
124 SMB_MBC_VALID(mbc);
126 m_freem(mbc->chain);
127 mbc->chain = NULL;
128 mbc->mbc_magic = 0;
129 kmem_cache_free(smb_mbc_cache, mbc);
133 * smb_mbuf_get
135 * Allocate mbufs to hold the amount of data specified.
136 * A pointer to the head of the mbuf list is returned.
138 struct mbuf *
139 smb_mbuf_get(uchar_t *buf, int nbytes)
141 struct mbuf *mhead = 0;
142 struct mbuf *m = 0;
143 int count;
144 int offset = 0;
146 while (nbytes) {
147 count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
148 nbytes -= count;
150 if (mhead == 0) {
151 MGET(mhead, M_WAIT, MT_DATA);
152 m = mhead;
153 } else {
154 MGET(m->m_next, M_WAIT, MT_DATA);
155 m = m->m_next;
158 if (count > MLEN) {
159 MCLGET(m, M_WAIT);
162 m->m_len = count;
163 bcopy(buf + offset, m->m_data, count);
164 offset += count;
166 return (mhead);
169 static int
170 smb_mbuf_kmem_ref(void *p, uint_t sz, int incr)
172 if (incr < 0)
173 kmem_free(p, sz);
174 return (0);
178 * Allocate enough mbufs to accommodate the residual count in uio,
179 * and setup the uio_iov to point to them.
181 * This is used by the various SMB read code paths. That code is
182 * going to do a disk read into this buffer, so we'd like it to be
183 * large and contiguous. Use an external (M_EXT) buffer.
185 struct mbuf *
186 smb_mbuf_allocate(struct uio *uio)
188 mbuf_t *m = 0;
189 int len = uio->uio_resid;
191 MGET(m, M_WAIT, MT_DATA);
192 if (len > MCLBYTES) {
193 /* Like MCLGET(), but bigger buf. */
194 m->m_ext.ext_buf = kmem_zalloc(len, KM_SLEEP);
195 m->m_data = m->m_ext.ext_buf;
196 m->m_flags |= M_EXT;
197 m->m_ext.ext_size = len;
198 m->m_ext.ext_ref = smb_mbuf_kmem_ref;
199 } else if (len > MLEN) {
200 /* Use the kmem cache. */
201 MCLGET(m, M_WAIT);
203 m->m_len = len;
205 uio->uio_iov->iov_base = m->m_data;
206 uio->uio_iov->iov_len = m->m_len;
207 uio->uio_iovcnt = 1;
209 return (m);
213 * Trim an mbuf chain to nbytes.
215 void
216 smb_mbuf_trim(struct mbuf *mhead, int nbytes)
218 struct mbuf *m = mhead;
220 while (m != 0) {
221 if (nbytes <= m->m_len) {
222 m->m_len = nbytes;
223 if (m->m_next != 0) {
224 m_freem(m->m_next);
225 m->m_next = 0;
227 break;
229 nbytes -= m->m_len;
230 m = m->m_next;
235 MBC_LENGTH(struct mbuf_chain *MBC)
237 struct mbuf *m = (MBC)->chain;
238 int used = 0;
240 while (m != 0) {
241 used += m->m_len;
242 m = m->m_next;
244 return (used);
248 MBC_MAXBYTES(struct mbuf_chain *MBC)
250 return (MBC->max_bytes);
253 void
254 MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
256 bzero((MBC), sizeof (struct mbuf_chain));
257 (MBC)->max_bytes = max_bytes;
260 void
261 MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
263 struct mbuf *m;
265 bzero((MBC), sizeof (struct mbuf_chain));
267 if (max_bytes != 0) {
268 MGET(m, M_WAIT, MT_DATA);
269 m->m_len = 0;
270 (MBC)->chain = m;
271 if (max_bytes > MINCLSIZE)
272 MCLGET(m, M_WAIT);
274 (MBC)->max_bytes = max_bytes;
277 void
278 MBC_FLUSH(struct mbuf_chain *MBC)
280 extern void m_freem(struct mbuf *);
281 struct mbuf *m;
283 while ((m = (MBC)->chain) != 0) {
284 (MBC)->chain = m->m_nextpkt;
285 m->m_nextpkt = 0;
286 m_freem(m);
288 MBC_SETUP(MBC, (MBC)->max_bytes);
291 void
292 MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
294 if (MBC->chain != 0)
295 MBC_FLUSH(MBC);
297 (MBC)->chain_offset = 0;
298 (MBC)->chain = (MBUF);
301 void
302 MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
304 struct mbuf *m;
306 if ((MBC)->chain == 0) {
307 (MBC)->chain = (MBUF);
308 } else {
309 m = (MBC)->chain;
310 while (m->m_next != 0)
311 m = m->m_next;
312 m->m_next = (MBUF);
316 static int /*ARGSUSED*/
317 mclrefnoop(caddr_t p, int size, int adj)
319 return (0);
322 void
323 MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
325 MGET((MBC)->chain, M_WAIT, MT_DATA);
326 (MBC)->chain_offset = 0;
327 (MBC)->chain->m_flags |= M_EXT;
328 (MBC)->chain->m_data = (caddr_t)(BUF);
329 (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
330 (MBC)->chain->m_len = (LEN);
331 (MBC)->chain->m_ext.ext_size = (LEN);
332 (MBC)->chain->m_ext.ext_ref = mclrefnoop;
333 (MBC)->max_bytes = (LEN);
338 MBC_SHADOW_CHAIN(struct mbuf_chain *submbc, struct mbuf_chain *mbc,
339 int off, int len)
341 int x = off + len;
343 if (off < 0 || len < 0 || x < 0 ||
344 off > mbc->max_bytes || x > mbc->max_bytes)
345 return (EMSGSIZE);
347 *submbc = *mbc;
348 submbc->chain_offset = off;
349 submbc->max_bytes = x;
350 submbc->shadow_of = mbc;
351 return (0);
355 * Free a single mbuf structure. Calls m->m_ext.ext_ref() to free any
356 * associated external buffers if present (indicated by m->m_flags & M_EXT)
358 struct mbuf *
359 m_free(struct mbuf *m)
361 struct mbuf *n;
363 MFREE(m, n);
364 return (n);
368 * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free.
370 void
371 m_freem(struct mbuf *m)
373 struct mbuf *n;
375 if (m == NULL)
376 return;
378 * Lint doesn't like the m = n assignment at the close of the loop
379 * but it is correct. MFREE assigns n = (m)->m_next so the loop
380 * is effectively assigning m = (m)->m_next then exiting when
381 * m == NULL
383 do {
384 MFREE(m, n);
385 } while ((m = n) != 0);
389 * Mbuffer utility routines.
392 mbuf_t *
393 smb_mbuf_alloc(void)
395 mbuf_t *m;
397 m = kmem_cache_alloc(smb_mbuf_cache, KM_SLEEP);
398 bzero(m, sizeof (*m));
399 return (m);
402 void
403 smb_mbuf_free(mbuf_t *m)
405 kmem_cache_free(smb_mbuf_cache, m);
408 void *
409 smb_mbufcl_alloc(void)
411 void *p;
413 p = kmem_cache_alloc(smb_mbufcl_cache, KM_SLEEP);
414 bzero(p, MCLBYTES);
415 return (p);
418 void
419 smb_mbufcl_free(void *p)
421 kmem_cache_free(smb_mbufcl_cache, p);
425 smb_mbufcl_ref(void *p, uint_t sz, int incr)
427 ASSERT3S(sz, ==, MCLBYTES);
428 if (incr < 0)
429 kmem_cache_free(smb_mbufcl_cache, p);
430 return (0);