don't use intermediate .o
[unix-history] / usr / src / sys / kern / uipc_mbuf.c
CommitLineData
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
24mbinit()
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;
40bad:
41 panic("mbinit");
42}
43
9c59be2b
MK
44/*
45 * Must be called at splimp.
46 */
6d0e638a 47/* ARGSUSED */
7c733634 48caddr_t
9c59be2b 49m_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
101m_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 */
114m_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 144struct mbuf *
cce93e4b
SL
145m_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 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
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 182struct mbuf *
cce93e4b
SL
183m_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 204m_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
228struct mbuf *
229m_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 = &top;
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);
276nospace:
2b4b57cd
BJ
277 m_freem(top);
278 return (0);
d80cae33
BJ
279}
280
8f3e7457
BJ
281m_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
301m_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 368struct mbuf *
fcd25562
MK
369m_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);
408bad:
82bff71e 409 m_freem(n);
7c733634
BJ
410 return (0);
411}