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