lint, add comments on %r
[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 *
a2ec3cef 11 * @(#)uipc_mbuf.c 7.8 (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);
a2ec3cef
MK
198 if (mfree)
199 break;
9c59be2b
MK
200 } else {
201 mbstat.m_drops++;
202 return (NULL);
203 }
d80cae33 204 }
cce93e4b
SL
205#define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
206 MGET(m, canwait, type);
3995e6f7 207#undef m_more
d80cae33
BJ
208 return (m);
209}
210
8f3e7457 211m_freem(m)
d80cae33
BJ
212 register struct mbuf *m;
213{
214 register struct mbuf *n;
2b4b57cd 215 register int s;
d80cae33 216
d80cae33 217 if (m == NULL)
ae921915 218 return;
dad64fdf 219 s = splimp();
d80cae33 220 do {
8f3e7457 221 MFREE(m, n);
d80cae33
BJ
222 } while (m = n);
223 splx(s);
2b4b57cd
BJ
224}
225
7c733634
BJ
226/*
227 * Mbuffer utility routines.
228 */
9c59be2b 229
39efebb8 230/*
9c59be2b
MK
231/*
232 * Make a copy of an mbuf chain starting "off" bytes from the beginning,
233 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
234 * Should get M_WAIT/M_DONTWAIT from caller.
235 */
2b4b57cd
BJ
236struct mbuf *
237m_copy(m, off, len)
238 register struct mbuf *m;
239 int off;
240 register int len;
241{
242 register struct mbuf *n, **np;
243 struct mbuf *top, *p;
2b4b57cd
BJ
244
245 if (len == 0)
246 return (0);
247 if (off < 0 || len < 0)
248 panic("m_copy");
249 while (off > 0) {
250 if (m == 0)
251 panic("m_copy");
252 if (off < m->m_len)
253 break;
254 off -= m->m_len;
255 m = m->m_next;
256 }
257 np = &top;
258 top = 0;
259 while (len > 0) {
842ff042
BJ
260 if (m == 0) {
261 if (len != M_COPYALL)
262 panic("m_copy");
263 break;
264 }
9c59be2b 265 MGET(n, M_DONTWAIT, m->m_type);
2b4b57cd
BJ
266 *np = n;
267 if (n == 0)
268 goto nospace;
2b4b57cd
BJ
269 n->m_len = MIN(len, m->m_len - off);
270 if (m->m_off > MMAXOFF) {
271 p = mtod(m, struct mbuf *);
272 n->m_off = ((int)p - (int)n) + off;
0ef33f87 273 mclrefcnt[mtocl(p)]++;
970108c7 274 } else
2b4b57cd
BJ
275 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
276 (unsigned)n->m_len);
842ff042
BJ
277 if (len != M_COPYALL)
278 len -= n->m_len;
2b4b57cd
BJ
279 off = 0;
280 m = m->m_next;
281 np = &n->m_next;
282 }
283 return (top);
284nospace:
2b4b57cd
BJ
285 m_freem(top);
286 return (0);
d80cae33
BJ
287}
288
39efebb8
MK
289/*
290 * Copy data from an mbuf chain starting "off" bytes from the beginning,
291 * continuing for "len" bytes, into the indicated buffer.
292 */
39efebb8
MK
293m_copydata(m, off, len, cp)
294 register struct mbuf *m;
a2ec3cef 295 register int off;
39efebb8 296 register int len;
a2ec3cef 297 caddr_t cp;
39efebb8
MK
298{
299 register unsigned count;
300
301 if (off < 0 || len < 0)
302 panic("m_copydata");
303 while (off > 0) {
304 if (m == 0)
305 panic("m_copydata");
306 if (off < m->m_len)
307 break;
308 off -= m->m_len;
309 m = m->m_next;
310 }
311 while (len > 0) {
312 if (m == 0)
313 panic("m_copydata");
a2ec3cef 314 count = MIN(m->m_len - off, len);
39efebb8
MK
315 bcopy(mtod(m, caddr_t) + off, cp, count);
316 len -= count;
a2ec3cef 317 cp += count;
39efebb8
MK
318 off = 0;
319 m = m->m_next;
320 }
321}
322
8f3e7457
BJ
323m_cat(m, n)
324 register struct mbuf *m, *n;
325{
8f3e7457
BJ
326 while (m->m_next)
327 m = m->m_next;
e495e1cc
BJ
328 while (n) {
329 if (m->m_off >= MMAXOFF ||
330 m->m_off + m->m_len + n->m_len > MMAXOFF) {
331 /* just join the two chains */
8f3e7457 332 m->m_next = n;
e495e1cc 333 return;
8f3e7457 334 }
e495e1cc
BJ
335 /* splat the data from one into the other */
336 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
337 (u_int)n->m_len);
338 m->m_len += n->m_len;
339 n = m_free(n);
340 }
8f3e7457
BJ
341}
342
d80cae33
BJ
343m_adj(mp, len)
344 struct mbuf *mp;
ae921915 345 register int len;
d80cae33 346{
fcd25562
MK
347 register struct mbuf *m;
348 register count;
d80cae33 349
d80cae33
BJ
350 if ((m = mp) == NULL)
351 return;
6d19f7ef 352 if (len >= 0) {
d80cae33 353 while (m != NULL && len > 0) {
6d19f7ef 354 if (m->m_len <= len) {
d80cae33
BJ
355 len -= m->m_len;
356 m->m_len = 0;
357 m = m->m_next;
6d19f7ef 358 } else {
d80cae33
BJ
359 m->m_len -= len;
360 m->m_off += len;
361 break;
362 }
363 }
6d19f7ef 364 } else {
fcd25562
MK
365 /*
366 * Trim from tail. Scan the mbuf chain,
367 * calculating its length and finding the last mbuf.
368 * If the adjustment only affects this mbuf, then just
369 * adjust and return. Otherwise, rescan and truncate
370 * after the remaining size.
371 */
d80cae33 372 len = -len;
fcd25562
MK
373 count = 0;
374 for (;;) {
375 count += m->m_len;
376 if (m->m_next == (struct mbuf *)0)
377 break;
378 m = m->m_next;
379 }
380 if (m->m_len >= len) {
381 m->m_len -= len;
382 return;
383 }
384 count -= len;
385 /*
386 * Correct length for chain is "count".
387 * Find the mbuf with last data, adjust its length,
388 * and toss data from remaining mbufs on chain.
389 */
390 for (m = mp; m; m = m->m_next) {
391 if (m->m_len >= count) {
392 m->m_len = count;
d80cae33
BJ
393 break;
394 }
fcd25562 395 count -= m->m_len;
d80cae33 396 }
fcd25562
MK
397 while (m = m->m_next)
398 m->m_len = 0;
d80cae33
BJ
399 }
400}
7c733634 401
864d7180
MK
402/*
403 * Rearange an mbuf chain so that len bytes are contiguous
404 * and in the data area of an mbuf (so that mtod and dtom
fcd25562
MK
405 * will work for a structure of size len). Returns the resulting
406 * mbuf chain on success, frees it and returns null on failure.
407 * If there is room, it will add up to MPULL_EXTRA bytes to the
408 * contiguous region in an attempt to avoid being called next time.
864d7180 409 */
10103653 410struct mbuf *
fcd25562
MK
411m_pullup(n, len)
412 register struct mbuf *n;
7c733634
BJ
413 int len;
414{
fcd25562
MK
415 register struct mbuf *m;
416 register int count;
417 int space;
7c733634 418
fcd25562
MK
419 if (n->m_off + len <= MMAXOFF && n->m_next) {
420 m = n;
421 n = n->m_next;
422 len -= m->m_len;
423 } else {
424 if (len > MLEN)
425 goto bad;
426 MGET(m, M_DONTWAIT, n->m_type);
427 if (m == 0)
428 goto bad;
429 m->m_len = 0;
430 }
431 space = MMAXOFF - m->m_off;
10103653 432 do {
fcd25562 433 count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len);
668cc26d
SL
434 bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
435 (unsigned)count);
436 len -= count;
437 m->m_len += count;
668cc26d 438 n->m_len -= count;
10103653 439 if (n->m_len)
864d7180
MK
440 n->m_off += count;
441 else
442 n = m_free(n);
fcd25562
MK
443 } while (len > 0 && n);
444 if (len > 0) {
10103653
BJ
445 (void) m_free(m);
446 goto bad;
447 }
448 m->m_next = n;
449 return (m);
450bad:
82bff71e 451 m_freem(n);
7c733634
BJ
452 return (0);
453}