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.4.1.3 (Berkeley) 02/15/89 18 */ 19 20 #include "../machine/pte.h" 21 22 #include "param.h" 23 #include "dir.h" 24 #include "user.h" 25 #include "proc.h" 26 #include "cmap.h" 27 #include "map.h" 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 35 mbinit() 36 { 37 int s; 38 39 #if CLBYTES < 4096 40 #define NCL_INIT (4096/CLBYTES) 41 #else 42 #define NCL_INIT 1 43 #endif 44 s = splimp(); 45 if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0) 46 goto bad; 47 if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0) 48 goto bad; 49 splx(s); 50 return; 51 bad: 52 panic("mbinit"); 53 } 54 55 /* 56 * Must be called at splimp. 57 */ 58 /* ARGSUSED */ 59 caddr_t 60 m_clalloc(ncl, how, canwait) 61 register int ncl; 62 int how; 63 { 64 int npg, mbx; 65 register struct mbuf *m; 66 register int i; 67 static int logged; 68 69 npg = ncl * CLSIZE; 70 mbx = rmalloc(mbmap, (long)npg); 71 if (mbx == 0) { 72 if (logged == 0) { 73 logged++; 74 log(LOG_ERR, "mbuf map full\n"); 75 } 76 return (0); 77 } 78 m = cltom(mbx * NBPG / MCLBYTES); 79 if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 80 rmfree(mbmap, (long)npg, (long)mbx); 81 return (0); 82 } 83 vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 84 switch (how) { 85 86 case MPG_CLUSTERS: 87 ncl = ncl * CLBYTES / MCLBYTES; 88 for (i = 0; i < ncl; i++) { 89 m->m_off = 0; 90 m->m_next = mclfree; 91 mclfree = m; 92 m += MCLBYTES / sizeof (*m); 93 mbstat.m_clfree++; 94 } 95 mbstat.m_clusters += ncl; 96 break; 97 98 case MPG_MBUFS: 99 for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 100 m->m_off = 0; 101 m->m_type = MT_DATA; 102 mbstat.m_mtypes[MT_DATA]++; 103 mbstat.m_mbufs++; 104 (void) m_free(m); 105 m++; 106 } 107 break; 108 109 case MPG_SPACE: 110 mbstat.m_space++; 111 break; 112 } 113 return ((caddr_t)m); 114 } 115 116 /* 117 * Must be called at splimp. 118 */ 119 m_expand(canwait) 120 int canwait; 121 { 122 register struct domain *dp; 123 register struct protosw *pr; 124 int tries; 125 126 for (tries = 0;; ) { 127 if (m_clalloc(1, MPG_MBUFS, canwait)) 128 return (1); 129 if (canwait == 0 || tries++) 130 return (0); 131 132 /* ask protocols to free space */ 133 for (dp = domains; dp; dp = dp->dom_next) 134 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 135 pr++) 136 if (pr->pr_drain) 137 (*pr->pr_drain)(); 138 mbstat.m_drain++; 139 } 140 } 141 142 /* NEED SOME WAY TO RELEASE SPACE */ 143 144 /* 145 * Space allocation routines. 146 * These are also available as macros 147 * for critical paths. 148 */ 149 struct mbuf * 150 m_get(canwait, type) 151 int canwait, type; 152 { 153 register struct mbuf *m; 154 155 MGET(m, canwait, type); 156 return (m); 157 } 158 159 struct mbuf * 160 m_getclr(canwait, type) 161 int canwait, type; 162 { 163 register struct mbuf *m; 164 165 MGET(m, canwait, type); 166 if (m == 0) 167 return (0); 168 bzero(mtod(m, caddr_t), MLEN); 169 return (m); 170 } 171 172 struct mbuf * 173 m_free(m) 174 struct mbuf *m; 175 { 176 register struct mbuf *n; 177 178 MFREE(m, n); 179 return (n); 180 } 181 182 /* 183 * Get more mbufs; called from MGET macro if mfree list is empty. 184 * Must be called at splimp. 185 */ 186 /*ARGSUSED*/ 187 struct mbuf * 188 m_more(canwait, type) 189 int canwait, type; 190 { 191 register struct mbuf *m; 192 193 while (m_expand(canwait) == 0) { 194 if (canwait == M_WAIT) { 195 mbstat.m_wait++; 196 m_want++; 197 sleep((caddr_t)&mfree, PZERO - 1); 198 if (mfree) 199 break; 200 } else { 201 mbstat.m_drops++; 202 return (NULL); 203 } 204 } 205 #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 206 MGET(m, canwait, type); 207 #undef m_more 208 return (m); 209 } 210 211 m_freem(m) 212 register struct mbuf *m; 213 { 214 register struct mbuf *n; 215 register int s; 216 217 if (m == NULL) 218 return; 219 s = splimp(); 220 do { 221 MFREE(m, n); 222 } while (m = n); 223 splx(s); 224 } 225 226 /* 227 * Mbuffer utility routines. 228 */ 229 230 /* 231 /* 232 * Make a copy of an mbuf chain starting "off" bytes from the beginning, 233 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 234 * Should get M_WAIT/M_DONTWAIT from caller. 235 */ 236 struct mbuf * 237 m_copy(m, off, len) 238 register struct mbuf *m; 239 int off; 240 register int len; 241 { 242 register struct mbuf *n, **np; 243 struct mbuf *top, *p; 244 245 if (len == 0) 246 return (0); 247 if (off < 0 || len < 0) 248 panic("m_copy"); 249 while (off > 0) { 250 if (m == 0) 251 panic("m_copy"); 252 if (off < m->m_len) 253 break; 254 off -= m->m_len; 255 m = m->m_next; 256 } 257 np = ⊤ 258 top = 0; 259 while (len > 0) { 260 if (m == 0) { 261 if (len != M_COPYALL) 262 panic("m_copy"); 263 break; 264 } 265 MGET(n, M_DONTWAIT, m->m_type); 266 *np = n; 267 if (n == 0) 268 goto nospace; 269 n->m_len = MIN(len, m->m_len - off); 270 if (m->m_off > MMAXOFF) { 271 p = mtod(m, struct mbuf *); 272 n->m_off = ((int)p - (int)n) + off; 273 mclrefcnt[mtocl(p)]++; 274 } else 275 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 276 (unsigned)n->m_len); 277 if (len != M_COPYALL) 278 len -= n->m_len; 279 off = 0; 280 m = m->m_next; 281 np = &n->m_next; 282 } 283 return (top); 284 nospace: 285 m_freem(top); 286 return (0); 287 } 288 289 /* 290 * Copy data from an mbuf chain starting "off" bytes from the beginning, 291 * continuing for "len" bytes, into the indicated buffer. 292 */ 293 m_copydata(m, off, len, cp) 294 register struct mbuf *m; 295 register int off; 296 register int len; 297 caddr_t cp; 298 { 299 register unsigned count; 300 301 if (off < 0 || len < 0) 302 panic("m_copydata"); 303 while (off > 0) { 304 if (m == 0) 305 panic("m_copydata"); 306 if (off < m->m_len) 307 break; 308 off -= m->m_len; 309 m = m->m_next; 310 } 311 while (len > 0) { 312 if (m == 0) 313 panic("m_copydata"); 314 count = MIN(m->m_len - off, len); 315 bcopy(mtod(m, caddr_t) + off, cp, count); 316 len -= count; 317 cp += count; 318 off = 0; 319 m = m->m_next; 320 } 321 } 322 323 m_cat(m, n) 324 register struct mbuf *m, *n; 325 { 326 while (m->m_next) 327 m = m->m_next; 328 while (n) { 329 if (m->m_off >= MMAXOFF || 330 m->m_off + m->m_len + n->m_len > MMAXOFF) { 331 /* just join the two chains */ 332 m->m_next = n; 333 return; 334 } 335 /* splat the data from one into the other */ 336 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 337 (u_int)n->m_len); 338 m->m_len += n->m_len; 339 n = m_free(n); 340 } 341 } 342 343 m_adj(mp, len) 344 struct mbuf *mp; 345 register int len; 346 { 347 register struct mbuf *m; 348 register count; 349 350 if ((m = mp) == NULL) 351 return; 352 if (len >= 0) { 353 while (m != NULL && len > 0) { 354 if (m->m_len <= len) { 355 len -= m->m_len; 356 m->m_len = 0; 357 m = m->m_next; 358 } else { 359 m->m_len -= len; 360 m->m_off += len; 361 break; 362 } 363 } 364 } else { 365 /* 366 * Trim from tail. Scan the mbuf chain, 367 * calculating its length and finding the last mbuf. 368 * If the adjustment only affects this mbuf, then just 369 * adjust and return. Otherwise, rescan and truncate 370 * after the remaining size. 371 */ 372 len = -len; 373 count = 0; 374 for (;;) { 375 count += m->m_len; 376 if (m->m_next == (struct mbuf *)0) 377 break; 378 m = m->m_next; 379 } 380 if (m->m_len >= len) { 381 m->m_len -= len; 382 return; 383 } 384 count -= len; 385 /* 386 * Correct length for chain is "count". 387 * Find the mbuf with last data, adjust its length, 388 * and toss data from remaining mbufs on chain. 389 */ 390 for (m = mp; m; m = m->m_next) { 391 if (m->m_len >= count) { 392 m->m_len = count; 393 break; 394 } 395 count -= m->m_len; 396 } 397 while (m = m->m_next) 398 m->m_len = 0; 399 } 400 } 401 402 /* 403 * Rearange an mbuf chain so that len bytes are contiguous 404 * and in the data area of an mbuf (so that mtod and dtom 405 * will work for a structure of size len). Returns the resulting 406 * mbuf chain on success, frees it and returns null on failure. 407 * If there is room, it will add up to MPULL_EXTRA bytes to the 408 * contiguous region in an attempt to avoid being called next time. 409 */ 410 struct mbuf * 411 m_pullup(n, len) 412 register struct mbuf *n; 413 int len; 414 { 415 register struct mbuf *m; 416 register int count; 417 int space; 418 419 if (n->m_off + len <= MMAXOFF && n->m_next) { 420 m = n; 421 n = n->m_next; 422 len -= m->m_len; 423 } else { 424 if (len > MLEN) 425 goto bad; 426 MGET(m, M_DONTWAIT, n->m_type); 427 if (m == 0) 428 goto bad; 429 m->m_len = 0; 430 } 431 space = MMAXOFF - m->m_off; 432 do { 433 count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 434 bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 435 (unsigned)count); 436 len -= count; 437 m->m_len += count; 438 n->m_len -= count; 439 if (n->m_len) 440 n->m_off += count; 441 else 442 n = m_free(n); 443 } while (len > 0 && n); 444 if (len > 0) { 445 (void) m_free(m); 446 goto bad; 447 } 448 m->m_next = n; 449 return (m); 450 bad: 451 m_freem(n); 452 return (0); 453 } 454