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