1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)uipc_mbuf.c 7.12 (Berkeley) 09/26/89 18 */ 19 20 #include "param.h" 21 #include "dir.h" 22 #include "user.h" 23 #include "proc.h" 24 #include "cmap.h" 25 #include "malloc.h" 26 #include "map.h" 27 #define MBTYPES 28 #include "mbuf.h" 29 #include "vm.h" 30 #include "kernel.h" 31 #include "syslog.h" 32 #include "domain.h" 33 #include "protosw.h" 34 #include "machine/pte.h" 35 36 mbinit() 37 { 38 int s; 39 40 #if MCLBYTES < 4096 41 #define NCL_INIT (4096/MCLBYTES) 42 #else 43 #define NCL_INIT 1 44 #endif 45 s = splimp(); 46 if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) 47 goto bad; 48 splx(s); 49 return; 50 bad: 51 panic("mbinit"); 52 } 53 54 /* 55 * Allocate some number of mbuf clusters 56 * and place on cluster free list. 57 * Must be called at splimp. 58 */ 59 /* ARGSUSED */ 60 m_clalloc(ncl, canwait) 61 register int ncl; 62 { 63 int npg, mbx; 64 register caddr_t p; 65 register int i; 66 static int logged; 67 68 npg = ncl * CLSIZE; 69 mbx = rmalloc(mbmap, (long)npg); 70 if (mbx == 0) { 71 if (logged == 0) { 72 logged++; 73 log(LOG_ERR, "mbuf map full\n"); 74 } 75 return (0); 76 } 77 p = cltom(mbx * NBPG / MCLBYTES); 78 if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 79 rmfree(mbmap, (long)npg, (long)mbx); 80 return (0); 81 } 82 vmaccess(&Mbmap[mbx], p, npg); 83 ncl = ncl * CLBYTES / MCLBYTES; 84 for (i = 0; i < ncl; i++) { 85 ((union mcluster *)p)->mcl_next = mclfree; 86 mclfree = (union mcluster *)p; 87 p += MCLBYTES; 88 mbstat.m_clfree++; 89 } 90 mbstat.m_clusters += ncl; 91 return (1); 92 } 93 94 /* 95 * When MGET failes, ask protocols to free space when short of memory, 96 * then re-attempt to allocate an mbuf. 97 */ 98 struct mbuf * 99 m_retry(i, t) 100 int i, t; 101 { 102 register struct mbuf *m; 103 104 m_reclaim(); 105 #define m_retry(i, t) (struct mbuf *)0 106 MGET(m, i, t); 107 #undef m_retry 108 return (m); 109 } 110 111 /* 112 * As above; retry an MGETHDR. 113 */ 114 struct mbuf * 115 m_retryhdr(i, t) 116 int i, t; 117 { 118 register struct mbuf *m; 119 120 m_reclaim(); 121 #define m_retryhdr(i, t) (struct mbuf *)0 122 MGETHDR(m, i, t); 123 #undef m_retryhdr 124 return (m); 125 } 126 127 m_reclaim() 128 { 129 register struct domain *dp; 130 register struct protosw *pr; 131 int s = splimp(); 132 133 for (dp = domains; dp; dp = dp->dom_next) 134 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 135 if (pr->pr_drain) 136 (*pr->pr_drain)(); 137 splx(s); 138 mbstat.m_drain++; 139 } 140 141 /* 142 * Space allocation routines. 143 * These are also available as macros 144 * for critical paths. 145 */ 146 struct mbuf * 147 m_get(canwait, type) 148 int canwait, type; 149 { 150 register struct mbuf *m; 151 152 MGET(m, canwait, type); 153 return (m); 154 } 155 156 struct mbuf * 157 m_gethdr(canwait, type) 158 int canwait, type; 159 { 160 register struct mbuf *m; 161 162 MGETHDR(m, canwait, type); 163 return (m); 164 } 165 166 struct mbuf * 167 m_getclr(canwait, type) 168 int canwait, type; 169 { 170 register struct mbuf *m; 171 172 MGET(m, canwait, type); 173 if (m == 0) 174 return (0); 175 bzero(mtod(m, caddr_t), MLEN); 176 return (m); 177 } 178 179 struct mbuf * 180 m_free(m) 181 struct mbuf *m; 182 { 183 register struct mbuf *n; 184 185 MFREE(m, n); 186 return (n); 187 } 188 189 m_freem(m) 190 register struct mbuf *m; 191 { 192 register struct mbuf *n; 193 194 if (m == NULL) 195 return; 196 do { 197 MFREE(m, n); 198 } while (m = n); 199 } 200 201 /* 202 * Mbuffer utility routines. 203 */ 204 205 /* 206 * Lesser-used path for M_PREPEND: 207 * allocate new mbuf to prepend to chain, 208 * copy junk along. 209 */ 210 struct mbuf * 211 m_prepend(m, len, how) 212 register struct mbuf *m; 213 int len, how; 214 { 215 struct mbuf *mn; 216 217 MGET(mn, how, m->m_type); 218 if (mn == (struct mbuf *)NULL) { 219 m_freem(m); 220 return ((struct mbuf *)NULL); 221 } 222 if (m->m_flags & M_PKTHDR) { 223 M_COPY_PKTHDR(mn, m); 224 m->m_flags &= ~M_PKTHDR; 225 } 226 mn->m_next = m; 227 m = mn; 228 if (len < MHLEN) 229 MH_ALIGN(m, len); 230 m->m_len = len; 231 return (m); 232 } 233 234 /* 235 /* 236 * Make a copy of an mbuf chain starting "off0" bytes from the beginning, 237 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 238 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. 239 */ 240 struct mbuf * 241 m_copym(m, off0, len, wait) 242 register struct mbuf *m; 243 int off0, wait; 244 register int len; 245 { 246 register struct mbuf *n, **np; 247 register int off = off0; 248 struct mbuf *top; 249 int copyhdr = 0; 250 251 if (off < 0 || len < 0) 252 panic("m_copym"); 253 if (off == 0 && m->m_flags & M_PKTHDR) 254 copyhdr = 1; 255 while (off > 0) { 256 if (m == 0) 257 panic("m_copym"); 258 if (off < m->m_len) 259 break; 260 off -= m->m_len; 261 m = m->m_next; 262 } 263 np = ⊤ 264 top = 0; 265 while (len > 0) { 266 if (m == 0) { 267 if (len != M_COPYALL) 268 panic("m_copym"); 269 break; 270 } 271 MGET(n, wait, m->m_type); 272 *np = n; 273 if (n == 0) 274 goto nospace; 275 if (copyhdr) { 276 M_COPY_PKTHDR(n, m); 277 if (len == M_COPYALL) 278 n->m_pkthdr.len -= off0; 279 else 280 n->m_pkthdr.len = len; 281 copyhdr = 0; 282 } 283 n->m_len = MIN(len, m->m_len - off); 284 if (m->m_flags & M_EXT) { 285 n->m_data = m->m_data + off; 286 mclrefcnt[mtocl(m->m_ext.ext_buf)]++; 287 n->m_ext = m->m_ext; 288 n->m_flags |= M_EXT; 289 } else 290 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 291 (unsigned)n->m_len); 292 if (len != M_COPYALL) 293 len -= n->m_len; 294 off = 0; 295 m = m->m_next; 296 np = &n->m_next; 297 } 298 return (top); 299 nospace: 300 m_freem(top); 301 return (0); 302 } 303 304 /* 305 * Copy data from an mbuf chain starting "off" bytes from the beginning, 306 * continuing for "len" bytes, into the indicated buffer. 307 */ 308 m_copydata(m, off, len, cp) 309 register struct mbuf *m; 310 register int off; 311 register int len; 312 caddr_t cp; 313 { 314 register unsigned count; 315 316 if (off < 0 || len < 0) 317 panic("m_copydata"); 318 while (off > 0) { 319 if (m == 0) 320 panic("m_copydata"); 321 if (off < m->m_len) 322 break; 323 off -= m->m_len; 324 m = m->m_next; 325 } 326 while (len > 0) { 327 if (m == 0) 328 panic("m_copydata"); 329 count = MIN(m->m_len - off, len); 330 bcopy(mtod(m, caddr_t) + off, cp, count); 331 len -= count; 332 cp += count; 333 off = 0; 334 m = m->m_next; 335 } 336 } 337 338 /* 339 * Concatenate mbuf chain n to m. 340 * Both chains must be of the same type (e.g. MT_DATA). 341 * Any m_pkthdr is not updated. 342 */ 343 m_cat(m, n) 344 register struct mbuf *m, *n; 345 { 346 while (m->m_next) 347 m = m->m_next; 348 while (n) { 349 if (m->m_flags & M_EXT || 350 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { 351 /* just join the two chains */ 352 m->m_next = n; 353 return; 354 } 355 /* splat the data from one into the other */ 356 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 357 (u_int)n->m_len); 358 m->m_len += n->m_len; 359 n = m_free(n); 360 } 361 } 362 363 m_adj(mp, req_len) 364 struct mbuf *mp; 365 { 366 register int len = req_len; 367 register struct mbuf *m; 368 register count; 369 370 if ((m = mp) == NULL) 371 return; 372 if (len >= 0) { 373 /* 374 * Trim from head. 375 */ 376 while (m != NULL && len > 0) { 377 if (m->m_len <= len) { 378 len -= m->m_len; 379 m->m_len = 0; 380 m = m->m_next; 381 } else { 382 m->m_len -= len; 383 m->m_data += len; 384 len = 0; 385 } 386 } 387 m = mp; 388 if (mp->m_flags & M_PKTHDR) 389 m->m_pkthdr.len -= (req_len - len); 390 } else { 391 /* 392 * Trim from tail. Scan the mbuf chain, 393 * calculating its length and finding the last mbuf. 394 * If the adjustment only affects this mbuf, then just 395 * adjust and return. Otherwise, rescan and truncate 396 * after the remaining size. 397 */ 398 len = -len; 399 count = 0; 400 for (;;) { 401 count += m->m_len; 402 if (m->m_next == (struct mbuf *)0) 403 break; 404 m = m->m_next; 405 } 406 if (m->m_len >= len) { 407 m->m_len -= len; 408 if ((mp = m)->m_flags & M_PKTHDR) 409 m->m_pkthdr.len -= len; 410 return; 411 } 412 count -= len; 413 if (count < 0) 414 count = 0; 415 /* 416 * Correct length for chain is "count". 417 * Find the mbuf with last data, adjust its length, 418 * and toss data from remaining mbufs on chain. 419 */ 420 m = mp; 421 if (m->m_flags & M_PKTHDR) 422 m->m_pkthdr.len = count; 423 for (; m; m = m->m_next) { 424 if (m->m_len >= count) { 425 m->m_len = count; 426 break; 427 } 428 count -= m->m_len; 429 } 430 while (m = m->m_next) 431 m->m_len = 0; 432 } 433 } 434 435 /* 436 * Rearange an mbuf chain so that len bytes are contiguous 437 * and in the data area of an mbuf (so that mtod and dtom 438 * will work for a structure of size len). Returns the resulting 439 * mbuf chain on success, frees it and returns null on failure. 440 * If there is room, it will add up to max_protohdr-len extra bytes to the 441 * contiguous region in an attempt to avoid being called next time. 442 */ 443 struct mbuf * 444 m_pullup(n, len) 445 register struct mbuf *n; 446 int len; 447 { 448 register struct mbuf *m; 449 register int count; 450 int space; 451 452 /* 453 * If first mbuf has no cluster, and has room for len bytes 454 * without shifting current data, pullup into it, 455 * otherwise allocate a new mbuf to prepend to the chain. 456 */ 457 if ((n->m_flags & M_EXT) == 0 && 458 n->m_data + len < &n->m_dat[MLEN] && n->m_next) { 459 if (n->m_len >= len) 460 return (n); 461 m = n; 462 n = n->m_next; 463 len -= m->m_len; 464 } else { 465 if (len > MHLEN) 466 goto bad; 467 MGET(m, M_DONTWAIT, n->m_type); 468 if (m == 0) 469 goto bad; 470 m->m_len = 0; 471 if (n->m_flags & M_PKTHDR) 472 M_COPY_PKTHDR(m, n); 473 } 474 space = &m->m_dat[MLEN] - (m->m_data + m->m_len); 475 do { 476 count = min(min(max(len, max_protohdr), space), n->m_len); 477 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 478 (unsigned)count); 479 len -= count; 480 m->m_len += count; 481 n->m_len -= count; 482 space -= count; 483 if (n->m_len) 484 n->m_data += count; 485 else 486 n = m_free(n); 487 } while (len > 0 && n); 488 if (len > 0) { 489 (void) m_free(m); 490 goto bad; 491 } 492 m->m_next = n; 493 return (m); 494 bad: 495 m_freem(n); 496 return (0); 497 } 498