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