1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 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. 25 */ 26 27 /* 28 * Copyright (c) 1982, 1986, 1988, 1991, 1993 29 * The Regents of the University of California. All rights reserved. 30 * 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. 46 * 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. 58 * 59 */ 60 61 #include <smbsrv/smb_kproto.h> 62 #include <smbsrv/smb_kstat.h> 63 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; 67 68 void 69 smb_mbc_init(void) 70 { 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); 75 76 smb_mbuf_cache = kmem_cache_create("smb_mbuf_cache", 77 sizeof (mbuf_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 78 79 smb_mbufcl_cache = kmem_cache_create("smb_mbufcl_cache", 80 MCLBYTES, 8, NULL, NULL, NULL, NULL, NULL, 0); 81 } 82 83 void 84 smb_mbc_fini(void) 85 { 86 if (smb_mbc_cache != NULL) { 87 kmem_cache_destroy(smb_mbc_cache); 88 smb_mbc_cache = NULL; 89 } 90 if (smb_mbuf_cache != NULL) { 91 kmem_cache_destroy(smb_mbuf_cache); 92 smb_mbuf_cache = NULL; 93 } 94 if (smb_mbufcl_cache != NULL) { 95 kmem_cache_destroy(smb_mbufcl_cache); 96 smb_mbufcl_cache = NULL; 97 } 98 } 99 100 mbuf_chain_t * 101 smb_mbc_alloc(uint32_t max_bytes) 102 { 103 mbuf_chain_t *mbc; 104 mbuf_t *m; 105 106 mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP); 107 bzero(mbc, sizeof (*mbc)); 108 mbc->mbc_magic = SMB_MBC_MAGIC; 109 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); 116 } 117 mbc->max_bytes = max_bytes; 118 return (mbc); 119 } 120 121 void 122 smb_mbc_free(mbuf_chain_t *mbc) 123 { 124 SMB_MBC_VALID(mbc); 125 126 m_freem(mbc->chain); 127 mbc->chain = NULL; 128 mbc->mbc_magic = 0; 129 kmem_cache_free(smb_mbc_cache, mbc); 130 } 131 132 /* 133 * smb_mbuf_get 134 * 135 * Allocate mbufs to hold the amount of data specified. 136 * A pointer to the head of the mbuf list is returned. 137 */ 138 struct mbuf * 139 smb_mbuf_get(uchar_t *buf, int nbytes) 140 { 141 struct mbuf *mhead = 0; 142 struct mbuf *m = 0; 143 int count; 144 int offset = 0; 145 146 while (nbytes) { 147 count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes; 148 nbytes -= count; 149 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; 156 } 157 158 if (count > MLEN) { 159 MCLGET(m, M_WAIT); 160 } 161 162 m->m_len = count; 163 bcopy(buf + offset, m->m_data, count); 164 offset += count; 165 } 166 return (mhead); 167 } 168 169 static int 170 smb_mbuf_kmem_ref(void *p, uint_t sz, int incr) 171 { 172 if (incr < 0) 173 kmem_free(p, sz); 174 return (0); 175 } 176 177 /* 178 * Allocate enough mbufs to accommodate the residual count in uio, 179 * and setup the uio_iov to point to them. 180 * 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. 184 */ 185 struct mbuf * 186 smb_mbuf_allocate(struct uio *uio) 187 { 188 mbuf_t *m = 0; 189 int len = uio->uio_resid; 190 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); 202 } 203 m->m_len = len; 204 205 uio->uio_iov->iov_base = m->m_data; 206 uio->uio_iov->iov_len = m->m_len; 207 uio->uio_iovcnt = 1; 208 209 return (m); 210 } 211 212 /* 213 * Trim an mbuf chain to nbytes. 214 */ 215 void 216 smb_mbuf_trim(struct mbuf *mhead, int nbytes) 217 { 218 struct mbuf *m = mhead; 219 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; 226 } 227 break; 228 } 229 nbytes -= m->m_len; 230 m = m->m_next; 231 } 232 } 233 234 int 235 MBC_LENGTH(struct mbuf_chain *MBC) 236 { 237 struct mbuf *m = (MBC)->chain; 238 int used = 0; 239 240 while (m != 0) { 241 used += m->m_len; 242 m = m->m_next; 243 } 244 return (used); 245 } 246 247 int 248 MBC_MAXBYTES(struct mbuf_chain *MBC) 249 { 250 return (MBC->max_bytes); 251 } 252 253 void 254 MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes) 255 { 256 bzero((MBC), sizeof (struct mbuf_chain)); 257 (MBC)->max_bytes = max_bytes; 258 } 259 260 void 261 MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes) 262 { 263 struct mbuf *m; 264 265 bzero((MBC), sizeof (struct mbuf_chain)); 266 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); 273 } 274 (MBC)->max_bytes = max_bytes; 275 } 276 277 void 278 MBC_FLUSH(struct mbuf_chain *MBC) 279 { 280 extern void m_freem(struct mbuf *); 281 struct mbuf *m; 282 283 while ((m = (MBC)->chain) != 0) { 284 (MBC)->chain = m->m_nextpkt; 285 m->m_nextpkt = 0; 286 m_freem(m); 287 } 288 MBC_SETUP(MBC, (MBC)->max_bytes); 289 } 290 291 void 292 MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF) 293 { 294 if (MBC->chain != 0) 295 MBC_FLUSH(MBC); 296 297 (MBC)->chain_offset = 0; 298 (MBC)->chain = (MBUF); 299 } 300 301 void 302 MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF) 303 { 304 struct mbuf *m; 305 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); 313 } 314 } 315 316 static int /*ARGSUSED*/ 317 mclrefnoop(caddr_t p, int size, int adj) 318 { 319 return (0); 320 } 321 322 void 323 MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN) 324 { 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); 334 } 335 336 337 int 338 MBC_SHADOW_CHAIN(struct mbuf_chain *submbc, struct mbuf_chain *mbc, 339 int off, int len) 340 { 341 int x = off + len; 342 343 if (off < 0 || len < 0 || x < 0 || 344 off > mbc->max_bytes || x > mbc->max_bytes) 345 return (EMSGSIZE); 346 347 *submbc = *mbc; 348 submbc->chain_offset = off; 349 submbc->max_bytes = x; 350 submbc->shadow_of = mbc; 351 return (0); 352 } 353 354 /* 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) 357 */ 358 struct mbuf * 359 m_free(struct mbuf *m) 360 { 361 struct mbuf *n; 362 363 MFREE(m, n); 364 return (n); 365 } 366 367 /* 368 * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free. 369 */ 370 void 371 m_freem(struct mbuf *m) 372 { 373 struct mbuf *n; 374 375 if (m == NULL) 376 return; 377 /* 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 382 */ 383 do { 384 MFREE(m, n); 385 } while ((m = n) != 0); 386 } 387 388 /* 389 * Mbuffer utility routines. 390 */ 391 392 mbuf_t * 393 smb_mbuf_alloc(void) 394 { 395 mbuf_t *m; 396 397 m = kmem_cache_alloc(smb_mbuf_cache, KM_SLEEP); 398 bzero(m, sizeof (*m)); 399 return (m); 400 } 401 402 void 403 smb_mbuf_free(mbuf_t *m) 404 { 405 kmem_cache_free(smb_mbuf_cache, m); 406 } 407 408 void * 409 smb_mbufcl_alloc(void) 410 { 411 void *p; 412 413 p = kmem_cache_alloc(smb_mbufcl_cache, KM_SLEEP); 414 bzero(p, MCLBYTES); 415 return (p); 416 } 417 418 void 419 smb_mbufcl_free(void *p) 420 { 421 kmem_cache_free(smb_mbufcl_cache, p); 422 } 423 424 int 425 smb_mbufcl_ref(void *p, uint_t sz, int incr) 426 { 427 ASSERT3S(sz, ==, MCLBYTES); 428 if (incr < 0) 429 kmem_cache_free(smb_mbufcl_cache, p); 430 return (0); 431 } 432