add RMP support for hp300
[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 *
fadcbc74 16 * @(#)uipc_mbuf.c 7.13 (Berkeley) %G%
da7c5cc6 17 */
961945a8 18
94368568 19#include "param.h"
94368568
JB
20#include "user.h"
21#include "proc.h"
22#include "cmap.h"
cb80fe27 23#include "malloc.h"
94368568 24#include "map.h"
cb80fe27 25#define MBTYPES
94368568
JB
26#include "mbuf.h"
27#include "vm.h"
28#include "kernel.h"
6d0e638a
MK
29#include "syslog.h"
30#include "domain.h"
31#include "protosw.h"
cb80fe27 32#include "machine/pte.h"
d80cae33 33
7c733634
BJ
34mbinit()
35{
9c59be2b 36 int s;
7c733634 37
cb80fe27
MK
38#if MCLBYTES < 4096
39#define NCL_INIT (4096/MCLBYTES)
a3010bc1
MK
40#else
41#define NCL_INIT 1
42#endif
9c59be2b 43 s = splimp();
cb80fe27 44 if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
7c733634 45 goto bad;
9c59be2b 46 splx(s);
7c733634
BJ
47 return;
48bad:
49 panic("mbinit");
50}
51
9c59be2b 52/*
cb80fe27
MK
53 * Allocate some number of mbuf clusters
54 * and place on cluster free list.
9c59be2b
MK
55 * Must be called at splimp.
56 */
6d0e638a 57/* ARGSUSED */
cb80fe27 58m_clalloc(ncl, canwait)
7c733634 59 register int ncl;
7c733634
BJ
60{
61 int npg, mbx;
cb80fe27 62 register caddr_t p;
7c733634 63 register int i;
6d0e638a 64 static int logged;
7c733634 65
7c733634 66 npg = ncl * CLSIZE;
a29f7995 67 mbx = rmalloc(mbmap, (long)npg);
9c59be2b 68 if (mbx == 0) {
6d0e638a
MK
69 if (logged == 0) {
70 logged++;
71 log(LOG_ERR, "mbuf map full\n");
72 }
7c733634 73 return (0);
9c59be2b 74 }
cb80fe27 75 p = cltom(mbx * NBPG / MCLBYTES);
961945a8 76 if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
961945a8 77 rmfree(mbmap, (long)npg, (long)mbx);
7c733634 78 return (0);
961945a8 79 }
cb80fe27
MK
80 vmaccess(&Mbmap[mbx], p, npg);
81 ncl = ncl * CLBYTES / MCLBYTES;
82 for (i = 0; i < ncl; i++) {
83 ((union mcluster *)p)->mcl_next = mclfree;
84 mclfree = (union mcluster *)p;
85 p += MCLBYTES;
86 mbstat.m_clfree++;
7c733634 87 }
cb80fe27
MK
88 mbstat.m_clusters += ncl;
89 return (1);
7c733634
BJ
90}
91
9c59be2b 92/*
cb80fe27
MK
93 * When MGET failes, ask protocols to free space when short of memory,
94 * then re-attempt to allocate an mbuf.
95 */
96struct mbuf *
97m_retry(i, t)
98 int i, t;
99{
100 register struct mbuf *m;
101
102 m_reclaim();
103#define m_retry(i, t) (struct mbuf *)0
104 MGET(m, i, t);
105#undef m_retry
106 return (m);
107}
108
109/*
110 * As above; retry an MGETHDR.
9c59be2b 111 */
cb80fe27
MK
112struct mbuf *
113m_retryhdr(i, t)
114 int i, t;
115{
116 register struct mbuf *m;
117
118 m_reclaim();
119#define m_retryhdr(i, t) (struct mbuf *)0
120 MGETHDR(m, i, t);
121#undef m_retryhdr
122 return (m);
123}
124
125m_reclaim()
7c733634 126{
6d0e638a
MK
127 register struct domain *dp;
128 register struct protosw *pr;
cb80fe27 129 int s = splimp();
7c733634 130
cb80fe27
MK
131 for (dp = domains; dp; dp = dp->dom_next)
132 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
133 if (pr->pr_drain)
134 (*pr->pr_drain)();
135 splx(s);
136 mbstat.m_drain++;
137}
7c733634 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
cb80fe27
MK
154struct mbuf *
155m_gethdr(canwait, type)
156 int canwait, type;
157{
158 register struct mbuf *m;
159
160 MGETHDR(m, canwait, type);
161 return (m);
162}
163
cc15ab5d 164struct mbuf *
cce93e4b
SL
165m_getclr(canwait, type)
166 int canwait, type;
cc15ab5d
BJ
167{
168 register struct mbuf *m;
169
9c59be2b 170 MGET(m, canwait, type);
cc15ab5d
BJ
171 if (m == 0)
172 return (0);
cc15ab5d
BJ
173 bzero(mtod(m, caddr_t), MLEN);
174 return (m);
175}
176
d80cae33
BJ
177struct mbuf *
178m_free(m)
179 struct mbuf *m;
180{
181 register struct mbuf *n;
182
d80cae33
BJ
183 MFREE(m, n);
184 return (n);
185}
186
8f3e7457 187m_freem(m)
d80cae33
BJ
188 register struct mbuf *m;
189{
190 register struct mbuf *n;
d80cae33 191
d80cae33 192 if (m == NULL)
ae921915 193 return;
d80cae33 194 do {
8f3e7457 195 MFREE(m, n);
d80cae33 196 } while (m = n);
2b4b57cd
BJ
197}
198
7c733634
BJ
199/*
200 * Mbuffer utility routines.
201 */
9c59be2b 202
39efebb8 203/*
cb80fe27
MK
204 * Lesser-used path for M_PREPEND:
205 * allocate new mbuf to prepend to chain,
206 * copy junk along.
207 */
208struct mbuf *
209m_prepend(m, len, how)
210 register struct mbuf *m;
211 int len, how;
212{
213 struct mbuf *mn;
214
215 MGET(mn, how, m->m_type);
216 if (mn == (struct mbuf *)NULL) {
217 m_freem(m);
218 return ((struct mbuf *)NULL);
219 }
220 if (m->m_flags & M_PKTHDR) {
221 M_COPY_PKTHDR(mn, m);
222 m->m_flags &= ~M_PKTHDR;
223 }
224 mn->m_next = m;
225 m = mn;
226 if (len < MHLEN)
227 MH_ALIGN(m, len);
228 m->m_len = len;
229 return (m);
230}
231
9c59be2b 232/*
cb80fe27
MK
233/*
234 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
9c59be2b 235 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
cb80fe27 236 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
9c59be2b 237 */
2b4b57cd 238struct mbuf *
cb80fe27 239m_copym(m, off0, len, wait)
2b4b57cd 240 register struct mbuf *m;
cb80fe27 241 int off0, wait;
2b4b57cd
BJ
242 register int len;
243{
244 register struct mbuf *n, **np;
cb80fe27
MK
245 register int off = off0;
246 struct mbuf *top;
247 int copyhdr = 0;
2b4b57cd 248
2b4b57cd 249 if (off < 0 || len < 0)
cb80fe27
MK
250 panic("m_copym");
251 if (off == 0 && m->m_flags & M_PKTHDR)
252 copyhdr = 1;
2b4b57cd
BJ
253 while (off > 0) {
254 if (m == 0)
cb80fe27 255 panic("m_copym");
2b4b57cd
BJ
256 if (off < m->m_len)
257 break;
258 off -= m->m_len;
259 m = m->m_next;
260 }
261 np = &top;
262 top = 0;
263 while (len > 0) {
842ff042
BJ
264 if (m == 0) {
265 if (len != M_COPYALL)
cb80fe27 266 panic("m_copym");
842ff042
BJ
267 break;
268 }
cb80fe27 269 MGET(n, wait, m->m_type);
2b4b57cd
BJ
270 *np = n;
271 if (n == 0)
272 goto nospace;
cb80fe27
MK
273 if (copyhdr) {
274 M_COPY_PKTHDR(n, m);
275 if (len == M_COPYALL)
276 n->m_pkthdr.len -= off0;
277 else
278 n->m_pkthdr.len = len;
279 copyhdr = 0;
280 }
2b4b57cd 281 n->m_len = MIN(len, m->m_len - off);
cb80fe27
MK
282 if (m->m_flags & M_EXT) {
283 n->m_data = m->m_data + off;
284 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
285 n->m_ext = m->m_ext;
286 n->m_flags |= M_EXT;
970108c7 287 } else
2b4b57cd
BJ
288 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
289 (unsigned)n->m_len);
842ff042
BJ
290 if (len != M_COPYALL)
291 len -= n->m_len;
2b4b57cd
BJ
292 off = 0;
293 m = m->m_next;
294 np = &n->m_next;
295 }
296 return (top);
297nospace:
2b4b57cd
BJ
298 m_freem(top);
299 return (0);
d80cae33
BJ
300}
301
39efebb8
MK
302/*
303 * Copy data from an mbuf chain starting "off" bytes from the beginning,
304 * continuing for "len" bytes, into the indicated buffer.
305 */
39efebb8
MK
306m_copydata(m, off, len, cp)
307 register struct mbuf *m;
a2ec3cef 308 register int off;
39efebb8 309 register int len;
a2ec3cef 310 caddr_t cp;
39efebb8
MK
311{
312 register unsigned count;
313
314 if (off < 0 || len < 0)
315 panic("m_copydata");
316 while (off > 0) {
317 if (m == 0)
318 panic("m_copydata");
319 if (off < m->m_len)
320 break;
321 off -= m->m_len;
322 m = m->m_next;
323 }
324 while (len > 0) {
325 if (m == 0)
326 panic("m_copydata");
a2ec3cef 327 count = MIN(m->m_len - off, len);
39efebb8
MK
328 bcopy(mtod(m, caddr_t) + off, cp, count);
329 len -= count;
a2ec3cef 330 cp += count;
39efebb8
MK
331 off = 0;
332 m = m->m_next;
333 }
334}
335
cb80fe27
MK
336/*
337 * Concatenate mbuf chain n to m.
338 * Both chains must be of the same type (e.g. MT_DATA).
339 * Any m_pkthdr is not updated.
340 */
8f3e7457
BJ
341m_cat(m, n)
342 register struct mbuf *m, *n;
343{
8f3e7457
BJ
344 while (m->m_next)
345 m = m->m_next;
e495e1cc 346 while (n) {
cb80fe27
MK
347 if (m->m_flags & M_EXT ||
348 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
e495e1cc 349 /* just join the two chains */
8f3e7457 350 m->m_next = n;
e495e1cc 351 return;
8f3e7457 352 }
e495e1cc
BJ
353 /* splat the data from one into the other */
354 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
355 (u_int)n->m_len);
356 m->m_len += n->m_len;
357 n = m_free(n);
358 }
8f3e7457
BJ
359}
360
cb80fe27 361m_adj(mp, req_len)
d80cae33 362 struct mbuf *mp;
d80cae33 363{
cb80fe27 364 register int len = req_len;
fcd25562
MK
365 register struct mbuf *m;
366 register count;
d80cae33 367
d80cae33
BJ
368 if ((m = mp) == NULL)
369 return;
6d19f7ef 370 if (len >= 0) {
cb80fe27
MK
371 /*
372 * Trim from head.
373 */
d80cae33 374 while (m != NULL && len > 0) {
6d19f7ef 375 if (m->m_len <= len) {
d80cae33
BJ
376 len -= m->m_len;
377 m->m_len = 0;
378 m = m->m_next;
6d19f7ef 379 } else {
d80cae33 380 m->m_len -= len;
cb80fe27
MK
381 m->m_data += len;
382 len = 0;
d80cae33
BJ
383 }
384 }
cb80fe27
MK
385 m = mp;
386 if (mp->m_flags & M_PKTHDR)
387 m->m_pkthdr.len -= (req_len - len);
6d19f7ef 388 } else {
fcd25562
MK
389 /*
390 * Trim from tail. Scan the mbuf chain,
391 * calculating its length and finding the last mbuf.
392 * If the adjustment only affects this mbuf, then just
393 * adjust and return. Otherwise, rescan and truncate
394 * after the remaining size.
395 */
d80cae33 396 len = -len;
fcd25562
MK
397 count = 0;
398 for (;;) {
399 count += m->m_len;
400 if (m->m_next == (struct mbuf *)0)
401 break;
402 m = m->m_next;
403 }
404 if (m->m_len >= len) {
405 m->m_len -= len;
698e6480
KS
406 if ((mp = m)->m_flags & M_PKTHDR)
407 m->m_pkthdr.len -= len;
fcd25562
MK
408 return;
409 }
410 count -= len;
cb80fe27
MK
411 if (count < 0)
412 count = 0;
fcd25562
MK
413 /*
414 * Correct length for chain is "count".
415 * Find the mbuf with last data, adjust its length,
416 * and toss data from remaining mbufs on chain.
417 */
cb80fe27
MK
418 m = mp;
419 if (m->m_flags & M_PKTHDR)
420 m->m_pkthdr.len = count;
421 for (; m; m = m->m_next) {
fcd25562
MK
422 if (m->m_len >= count) {
423 m->m_len = count;
d80cae33
BJ
424 break;
425 }
fcd25562 426 count -= m->m_len;
d80cae33 427 }
fcd25562
MK
428 while (m = m->m_next)
429 m->m_len = 0;
d80cae33
BJ
430 }
431}
7c733634 432
864d7180
MK
433/*
434 * Rearange an mbuf chain so that len bytes are contiguous
435 * and in the data area of an mbuf (so that mtod and dtom
fcd25562
MK
436 * will work for a structure of size len). Returns the resulting
437 * mbuf chain on success, frees it and returns null on failure.
cb80fe27 438 * If there is room, it will add up to max_protohdr-len extra bytes to the
fcd25562 439 * contiguous region in an attempt to avoid being called next time.
864d7180 440 */
10103653 441struct mbuf *
fcd25562
MK
442m_pullup(n, len)
443 register struct mbuf *n;
7c733634
BJ
444 int len;
445{
fcd25562
MK
446 register struct mbuf *m;
447 register int count;
448 int space;
7c733634 449
cb80fe27
MK
450 /*
451 * If first mbuf has no cluster, and has room for len bytes
452 * without shifting current data, pullup into it,
453 * otherwise allocate a new mbuf to prepend to the chain.
454 */
455 if ((n->m_flags & M_EXT) == 0 &&
456 n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
457 if (n->m_len >= len)
458 return (n);
fcd25562
MK
459 m = n;
460 n = n->m_next;
461 len -= m->m_len;
462 } else {
cb80fe27 463 if (len > MHLEN)
fcd25562
MK
464 goto bad;
465 MGET(m, M_DONTWAIT, n->m_type);
466 if (m == 0)
467 goto bad;
468 m->m_len = 0;
cb80fe27
MK
469 if (n->m_flags & M_PKTHDR)
470 M_COPY_PKTHDR(m, n);
fcd25562 471 }
cb80fe27 472 space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
10103653 473 do {
cb80fe27
MK
474 count = min(min(max(len, max_protohdr), space), n->m_len);
475 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
668cc26d
SL
476 (unsigned)count);
477 len -= count;
478 m->m_len += count;
668cc26d 479 n->m_len -= count;
cb80fe27 480 space -= count;
10103653 481 if (n->m_len)
cb80fe27 482 n->m_data += count;
864d7180
MK
483 else
484 n = m_free(n);
fcd25562
MK
485 } while (len > 0 && n);
486 if (len > 0) {
10103653
BJ
487 (void) m_free(m);
488 goto bad;
489 }
490 m->m_next = n;
491 return (m);
492bad:
82bff71e 493 m_freem(n);
7c733634
BJ
494 return (0);
495}