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