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