new naming convention
[unix-history] / usr / src / sys / kern / uipc_mbuf.c
CommitLineData
da7c5cc6 1/*
5b519e94 2 * All rights reserved.
da7c5cc6 3 *
5b519e94 4 * Redistribution and use in source and binary forms are permitted
616d42db
KB
5 * provided that the above copyright notice and this paragraph are
6 * duplicated in all such forms and that any documentation,
7 * advertising materials, and other materials related to such
8 * distribution and use acknowledge that the software was developed
9 * by the University of California, Berkeley. The name of the
10 * University may not be used to endorse or promote products derived
11 * from this software without specific prior written permission.
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5b519e94 15 *
bf9b1e70 16 * @(#)uipc_mbuf.c 7.4.1.3 (Berkeley) %G%
da7c5cc6 17 */
961945a8
SL
18
19#include "../machine/pte.h"
d80cae33 20
94368568
JB
21#include "param.h"
22#include "dir.h"
23#include "user.h"
24#include "proc.h"
25#include "cmap.h"
26#include "map.h"
27#include "mbuf.h"
28#include "vm.h"
29#include "kernel.h"
6d0e638a
MK
30#include "syslog.h"
31#include "domain.h"
32#include "protosw.h"
d80cae33 33
7c733634
BJ
34mbinit()
35{
9c59be2b 36 int s;
7c733634 37
a3010bc1
MK
38#if CLBYTES < 4096
39#define NCL_INIT (4096/CLBYTES)
40#else
41#define NCL_INIT 1
42#endif
9c59be2b 43 s = splimp();
a3010bc1 44 if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0)
7c733634 45 goto bad;
a3010bc1 46 if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0)
7c733634 47 goto bad;
9c59be2b 48 splx(s);
7c733634
BJ
49 return;
50bad:
51 panic("mbinit");
52}
53
9c59be2b
MK
54/*
55 * Must be called at splimp.
56 */
6d0e638a 57/* ARGSUSED */
7c733634 58caddr_t
9c59be2b 59m_clalloc(ncl, how, canwait)
7c733634
BJ
60 register int ncl;
61 int how;
62{
63 int npg, mbx;
64 register struct mbuf *m;
65 register int i;
6d0e638a 66 static int logged;
7c733634 67
7c733634 68 npg = ncl * CLSIZE;
a29f7995 69 mbx = rmalloc(mbmap, (long)npg);
9c59be2b 70 if (mbx == 0) {
6d0e638a
MK
71 if (logged == 0) {
72 logged++;
73 log(LOG_ERR, "mbuf map full\n");
74 }
7c733634 75 return (0);
9c59be2b 76 }
a3010bc1 77 m = cltom(mbx * NBPG / MCLBYTES);
961945a8 78 if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
961945a8 79 rmfree(mbmap, (long)npg, (long)mbx);
7c733634 80 return (0);
961945a8 81 }
7c733634 82 vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
7c733634
BJ
83 switch (how) {
84
85 case MPG_CLUSTERS:
a3010bc1 86 ncl = ncl * CLBYTES / MCLBYTES;
7c733634
BJ
87 for (i = 0; i < ncl; i++) {
88 m->m_off = 0;
89 m->m_next = mclfree;
90 mclfree = m;
a3010bc1 91 m += MCLBYTES / sizeof (*m);
f8d913c6 92 mbstat.m_clfree++;
7c733634
BJ
93 }
94 mbstat.m_clusters += ncl;
7c733634
BJ
95 break;
96
97 case MPG_MBUFS:
98 for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
99 m->m_off = 0;
cce93e4b
SL
100 m->m_type = MT_DATA;
101 mbstat.m_mtypes[MT_DATA]++;
f8d913c6 102 mbstat.m_mbufs++;
7c733634
BJ
103 (void) m_free(m);
104 m++;
105 }
d2109fac 106 break;
7c733634
BJ
107 }
108 return ((caddr_t)m);
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);
a2ec3cef
MK
193 if (mfree)
194 break;
9c59be2b
MK
195 } else {
196 mbstat.m_drops++;
197 return (NULL);
198 }
d80cae33 199 }
cce93e4b
SL
200#define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
201 MGET(m, canwait, type);
3995e6f7 202#undef m_more
d80cae33
BJ
203 return (m);
204}
205
8f3e7457 206m_freem(m)
d80cae33
BJ
207 register struct mbuf *m;
208{
209 register struct mbuf *n;
2b4b57cd 210 register int s;
d80cae33 211
d80cae33 212 if (m == NULL)
ae921915 213 return;
dad64fdf 214 s = splimp();
d80cae33 215 do {
8f3e7457 216 MFREE(m, n);
d80cae33
BJ
217 } while (m = n);
218 splx(s);
2b4b57cd
BJ
219}
220
7c733634
BJ
221/*
222 * Mbuffer utility routines.
223 */
9c59be2b 224
39efebb8 225/*
9c59be2b
MK
226/*
227 * Make a copy of an mbuf chain starting "off" bytes from the beginning,
228 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
229 * Should get M_WAIT/M_DONTWAIT from caller.
230 */
2b4b57cd
BJ
231struct mbuf *
232m_copy(m, off, len)
233 register struct mbuf *m;
234 int off;
235 register int len;
236{
237 register struct mbuf *n, **np;
238 struct mbuf *top, *p;
2b4b57cd
BJ
239
240 if (len == 0)
241 return (0);
242 if (off < 0 || len < 0)
243 panic("m_copy");
244 while (off > 0) {
245 if (m == 0)
246 panic("m_copy");
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)
257 panic("m_copy");
258 break;
259 }
9c59be2b 260 MGET(n, M_DONTWAIT, m->m_type);
2b4b57cd
BJ
261 *np = n;
262 if (n == 0)
263 goto nospace;
2b4b57cd
BJ
264 n->m_len = MIN(len, m->m_len - off);
265 if (m->m_off > MMAXOFF) {
266 p = mtod(m, struct mbuf *);
267 n->m_off = ((int)p - (int)n) + off;
0ef33f87 268 mclrefcnt[mtocl(p)]++;
970108c7 269 } else
2b4b57cd
BJ
270 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
271 (unsigned)n->m_len);
842ff042
BJ
272 if (len != M_COPYALL)
273 len -= n->m_len;
2b4b57cd
BJ
274 off = 0;
275 m = m->m_next;
276 np = &n->m_next;
277 }
278 return (top);
279nospace:
2b4b57cd
BJ
280 m_freem(top);
281 return (0);
d80cae33
BJ
282}
283
39efebb8
MK
284/*
285 * Copy data from an mbuf chain starting "off" bytes from the beginning,
286 * continuing for "len" bytes, into the indicated buffer.
287 */
39efebb8
MK
288m_copydata(m, off, len, cp)
289 register struct mbuf *m;
a2ec3cef 290 register int off;
39efebb8 291 register int len;
a2ec3cef 292 caddr_t cp;
39efebb8
MK
293{
294 register unsigned count;
295
296 if (off < 0 || len < 0)
297 panic("m_copydata");
298 while (off > 0) {
299 if (m == 0)
300 panic("m_copydata");
301 if (off < m->m_len)
302 break;
303 off -= m->m_len;
304 m = m->m_next;
305 }
306 while (len > 0) {
307 if (m == 0)
308 panic("m_copydata");
a2ec3cef 309 count = MIN(m->m_len - off, len);
39efebb8
MK
310 bcopy(mtod(m, caddr_t) + off, cp, count);
311 len -= count;
a2ec3cef 312 cp += count;
39efebb8
MK
313 off = 0;
314 m = m->m_next;
315 }
316}
317
8f3e7457
BJ
318m_cat(m, n)
319 register struct mbuf *m, *n;
320{
8f3e7457
BJ
321 while (m->m_next)
322 m = m->m_next;
e495e1cc
BJ
323 while (n) {
324 if (m->m_off >= MMAXOFF ||
325 m->m_off + m->m_len + n->m_len > MMAXOFF) {
326 /* just join the two chains */
8f3e7457 327 m->m_next = n;
e495e1cc 328 return;
8f3e7457 329 }
e495e1cc
BJ
330 /* splat the data from one into the other */
331 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
332 (u_int)n->m_len);
333 m->m_len += n->m_len;
334 n = m_free(n);
335 }
8f3e7457
BJ
336}
337
d80cae33
BJ
338m_adj(mp, len)
339 struct mbuf *mp;
ae921915 340 register int len;
d80cae33 341{
fcd25562
MK
342 register struct mbuf *m;
343 register count;
d80cae33 344
d80cae33
BJ
345 if ((m = mp) == NULL)
346 return;
6d19f7ef 347 if (len >= 0) {
d80cae33 348 while (m != NULL && len > 0) {
6d19f7ef 349 if (m->m_len <= len) {
d80cae33
BJ
350 len -= m->m_len;
351 m->m_len = 0;
352 m = m->m_next;
6d19f7ef 353 } else {
d80cae33
BJ
354 m->m_len -= len;
355 m->m_off += len;
356 break;
357 }
358 }
6d19f7ef 359 } else {
fcd25562
MK
360 /*
361 * Trim from tail. Scan the mbuf chain,
362 * calculating its length and finding the last mbuf.
363 * If the adjustment only affects this mbuf, then just
364 * adjust and return. Otherwise, rescan and truncate
365 * after the remaining size.
366 */
d80cae33 367 len = -len;
fcd25562
MK
368 count = 0;
369 for (;;) {
370 count += m->m_len;
371 if (m->m_next == (struct mbuf *)0)
372 break;
373 m = m->m_next;
374 }
375 if (m->m_len >= len) {
376 m->m_len -= len;
377 return;
378 }
379 count -= len;
380 /*
381 * Correct length for chain is "count".
382 * Find the mbuf with last data, adjust its length,
383 * and toss data from remaining mbufs on chain.
384 */
385 for (m = mp; m; m = m->m_next) {
386 if (m->m_len >= count) {
387 m->m_len = count;
d80cae33
BJ
388 break;
389 }
fcd25562 390 count -= m->m_len;
d80cae33 391 }
fcd25562
MK
392 while (m = m->m_next)
393 m->m_len = 0;
d80cae33
BJ
394 }
395}
7c733634 396
864d7180
MK
397/*
398 * Rearange an mbuf chain so that len bytes are contiguous
399 * and in the data area of an mbuf (so that mtod and dtom
fcd25562
MK
400 * will work for a structure of size len). Returns the resulting
401 * mbuf chain on success, frees it and returns null on failure.
402 * If there is room, it will add up to MPULL_EXTRA bytes to the
403 * contiguous region in an attempt to avoid being called next time.
864d7180 404 */
10103653 405struct mbuf *
fcd25562
MK
406m_pullup(n, len)
407 register struct mbuf *n;
7c733634
BJ
408 int len;
409{
fcd25562
MK
410 register struct mbuf *m;
411 register int count;
412 int space;
7c733634 413
fcd25562
MK
414 if (n->m_off + len <= MMAXOFF && n->m_next) {
415 m = n;
416 n = n->m_next;
417 len -= m->m_len;
418 } else {
419 if (len > MLEN)
420 goto bad;
421 MGET(m, M_DONTWAIT, n->m_type);
422 if (m == 0)
423 goto bad;
424 m->m_len = 0;
425 }
426 space = MMAXOFF - m->m_off;
10103653 427 do {
fcd25562 428 count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len);
668cc26d
SL
429 bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
430 (unsigned)count);
431 len -= count;
432 m->m_len += count;
668cc26d 433 n->m_len -= count;
10103653 434 if (n->m_len)
864d7180
MK
435 n->m_off += count;
436 else
437 n = m_free(n);
fcd25562
MK
438 } while (len > 0 && n);
439 if (len > 0) {
10103653
BJ
440 (void) m_free(m);
441 goto bad;
442 }
443 m->m_next = n;
444 return (m);
445bad:
82bff71e 446 m_freem(n);
7c733634
BJ
447 return (0);
448}