1 /* 2 * Copyright (c) 1982 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)uipc_mbuf.c 6.7 (Berkeley) 09/05/85 7 */ 8 9 #include "../machine/pte.h" 10 11 #include "param.h" 12 #include "dir.h" 13 #include "user.h" 14 #include "proc.h" 15 #include "cmap.h" 16 #include "map.h" 17 #include "mbuf.h" 18 #include "vm.h" 19 #include "kernel.h" 20 21 mbinit() 22 { 23 int s; 24 25 s = splimp(); 26 if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0) 27 goto bad; 28 if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0) 29 goto bad; 30 splx(s); 31 return; 32 bad: 33 panic("mbinit"); 34 } 35 36 /* 37 * Must be called at splimp. 38 */ 39 caddr_t 40 m_clalloc(ncl, how, canwait) 41 register int ncl; 42 int how; 43 { 44 int npg, mbx; 45 register struct mbuf *m; 46 register int i; 47 48 npg = ncl * CLSIZE; 49 mbx = rmalloc(mbmap, (long)npg); 50 if (mbx == 0) { 51 if (canwait == M_WAIT) 52 panic("out of mbuf map"); 53 return (0); 54 } 55 m = cltom(mbx / CLSIZE); 56 if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) { 57 rmfree(mbmap, (long)npg, (long)mbx); 58 return (0); 59 } 60 vmaccess(&Mbmap[mbx], (caddr_t)m, npg); 61 switch (how) { 62 63 case MPG_CLUSTERS: 64 for (i = 0; i < ncl; i++) { 65 m->m_off = 0; 66 m->m_next = mclfree; 67 mclfree = m; 68 m += CLBYTES / sizeof (*m); 69 mbstat.m_clfree++; 70 } 71 mbstat.m_clusters += ncl; 72 break; 73 74 case MPG_MBUFS: 75 for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) { 76 m->m_off = 0; 77 m->m_type = MT_DATA; 78 mbstat.m_mtypes[MT_DATA]++; 79 mbstat.m_mbufs++; 80 (void) m_free(m); 81 m++; 82 } 83 break; 84 } 85 return ((caddr_t)m); 86 } 87 88 m_pgfree(addr, n) 89 caddr_t addr; 90 int n; 91 { 92 93 #ifdef lint 94 addr = addr; n = n; 95 #endif 96 } 97 98 /* 99 * Must be called at splimp. 100 */ 101 m_expand(canwait) 102 int canwait; 103 { 104 105 if (m_clalloc(1, MPG_MBUFS, canwait) == 0) 106 goto steal; 107 return (1); 108 steal: 109 /* should ask protocols to free code */ 110 return (0); 111 } 112 113 /* NEED SOME WAY TO RELEASE SPACE */ 114 115 /* 116 * Space allocation routines. 117 * These are also available as macros 118 * for critical paths. 119 */ 120 struct mbuf * 121 m_get(canwait, type) 122 int canwait, type; 123 { 124 register struct mbuf *m; 125 126 MGET(m, canwait, type); 127 return (m); 128 } 129 130 struct mbuf * 131 m_getclr(canwait, type) 132 int canwait, type; 133 { 134 register struct mbuf *m; 135 136 MGET(m, canwait, type); 137 if (m == 0) 138 return (0); 139 bzero(mtod(m, caddr_t), MLEN); 140 return (m); 141 } 142 143 struct mbuf * 144 m_free(m) 145 struct mbuf *m; 146 { 147 register struct mbuf *n; 148 149 MFREE(m, n); 150 return (n); 151 } 152 153 /* 154 * Get more mbufs; called from MGET macro if mfree list is empty. 155 * Must be called at splimp. 156 */ 157 /*ARGSUSED*/ 158 struct mbuf * 159 m_more(canwait, type) 160 int canwait, type; 161 { 162 register struct mbuf *m; 163 164 while (m_expand(canwait) == 0) { 165 if (canwait == M_WAIT) { 166 m_want++; 167 sleep((caddr_t)&mfree, PZERO - 1); 168 } else { 169 mbstat.m_drops++; 170 return (NULL); 171 } 172 } 173 #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 174 MGET(m, canwait, type); 175 #undef m_more 176 return (m); 177 } 178 179 m_freem(m) 180 register struct mbuf *m; 181 { 182 register struct mbuf *n; 183 register int s; 184 185 if (m == NULL) 186 return; 187 s = splimp(); 188 do { 189 MFREE(m, n); 190 } while (m = n); 191 splx(s); 192 } 193 194 /* 195 * Mbuffer utility routines. 196 */ 197 198 /* 199 * Make a copy of an mbuf chain starting "off" bytes from the beginning, 200 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 201 * Should get M_WAIT/M_DONTWAIT from caller. 202 */ 203 struct mbuf * 204 m_copy(m, off, len) 205 register struct mbuf *m; 206 int off; 207 register int len; 208 { 209 register struct mbuf *n, **np; 210 struct mbuf *top, *p; 211 212 if (len == 0) 213 return (0); 214 if (off < 0 || len < 0) 215 panic("m_copy"); 216 while (off > 0) { 217 if (m == 0) 218 panic("m_copy"); 219 if (off < m->m_len) 220 break; 221 off -= m->m_len; 222 m = m->m_next; 223 } 224 np = ⊤ 225 top = 0; 226 while (len > 0) { 227 if (m == 0) { 228 if (len != M_COPYALL) 229 panic("m_copy"); 230 break; 231 } 232 MGET(n, M_DONTWAIT, m->m_type); 233 *np = n; 234 if (n == 0) 235 goto nospace; 236 n->m_len = MIN(len, m->m_len - off); 237 if (m->m_off > MMAXOFF) { 238 p = mtod(m, struct mbuf *); 239 n->m_off = ((int)p - (int)n) + off; 240 mclrefcnt[mtocl(p)]++; 241 } else 242 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 243 (unsigned)n->m_len); 244 if (len != M_COPYALL) 245 len -= n->m_len; 246 off = 0; 247 m = m->m_next; 248 np = &n->m_next; 249 } 250 return (top); 251 nospace: 252 m_freem(top); 253 return (0); 254 } 255 256 m_cat(m, n) 257 register struct mbuf *m, *n; 258 { 259 while (m->m_next) 260 m = m->m_next; 261 while (n) { 262 if (m->m_off >= MMAXOFF || 263 m->m_off + m->m_len + n->m_len > MMAXOFF) { 264 /* just join the two chains */ 265 m->m_next = n; 266 return; 267 } 268 /* splat the data from one into the other */ 269 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 270 (u_int)n->m_len); 271 m->m_len += n->m_len; 272 n = m_free(n); 273 } 274 } 275 276 m_adj(mp, len) 277 struct mbuf *mp; 278 register int len; 279 { 280 register struct mbuf *m, *n; 281 282 if ((m = mp) == NULL) 283 return; 284 if (len >= 0) { 285 while (m != NULL && len > 0) { 286 if (m->m_len <= len) { 287 len -= m->m_len; 288 m->m_len = 0; 289 m = m->m_next; 290 } else { 291 m->m_len -= len; 292 m->m_off += len; 293 break; 294 } 295 } 296 } else { 297 /* a 2 pass algorithm might be better */ 298 len = -len; 299 while (len > 0 && m->m_len != 0) { 300 while (m != NULL && m->m_len != 0) { 301 n = m; 302 m = m->m_next; 303 } 304 if (n->m_len <= len) { 305 len -= n->m_len; 306 n->m_len = 0; 307 m = mp; 308 } else { 309 n->m_len -= len; 310 break; 311 } 312 } 313 } 314 } 315 316 /* 317 * Rearange an mbuf chain so that len bytes are contiguous 318 * and in the data area of an mbuf (so that mtod and dtom 319 * will work for a structure of size len). 320 * Returns the resulting mbuf chain on success, 321 * frees it and returns null on failure. 322 */ 323 struct mbuf * 324 m_pullup(m0, len) 325 struct mbuf *m0; 326 int len; 327 { 328 register struct mbuf *m, *n; 329 int count; 330 331 n = m0; 332 if (len > MLEN) 333 goto bad; 334 MGET(m, M_DONTWAIT, n->m_type); 335 if (m == 0) 336 goto bad; 337 m->m_len = 0; 338 do { 339 count = MIN(n->m_len, len); 340 bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 341 (unsigned)count); 342 len -= count; 343 m->m_len += count; 344 n->m_len -= count; 345 if (n->m_len) 346 n->m_off += count; 347 else 348 n = m_free(n); 349 } while (len && n); 350 if (len) { 351 (void) m_free(m); 352 goto bad; 353 } 354 m->m_next = n; 355 return (m); 356 bad: 357 m_freem(n); 358 return (0); 359 } 360