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