|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)uipc_mbuf.c 7.17 (Berkeley) 7/25/90
21: */
22:
23: #include "param.h"
24: #include "user.h"
25: #include "proc.h"
26: #include "cmap.h"
27: #include "malloc.h"
28: #include "map.h"
29: #define MBTYPES
30: #include "mbuf.h"
31: #include "vm.h"
32: #include "kernel.h"
33: #include "syslog.h"
34: #include "domain.h"
35: #include "protosw.h"
36: #include "machine/pte.h"
37:
38: mbinit()
39: {
40: int s;
41:
42: #if MCLBYTES < 4096
43: #define NCL_INIT (4096/CLBYTES)
44: #else
45: #define NCL_INIT 1
46: #endif
47: s = splimp();
48: if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
49: goto bad;
50: splx(s);
51: return;
52: bad:
53: panic("mbinit");
54: }
55:
56: /*
57: * Allocate some number of mbuf clusters
58: * and place on cluster free list.
59: * Must be called at splimp.
60: */
61: /* ARGSUSED */
62: m_clalloc(ncl, canwait)
63: register int ncl;
64: {
65: int npg, mbx;
66: register caddr_t p;
67: register int i;
68: static int logged;
69:
70: npg = ncl * CLSIZE;
71: mbx = rmalloc(mbmap, (long)npg);
72: if (mbx == 0) {
73: if (logged == 0) {
74: logged++;
75: log(LOG_ERR, "mbuf map full\n");
76: }
77: return (0);
78: }
79: p = cltom(mbx * NBPG / MCLBYTES);
80: if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
81: rmfree(mbmap, (long)npg, (long)mbx);
82: return (0);
83: }
84: vmaccess(&Mbmap[mbx], p, npg);
85: ncl = ncl * CLBYTES / MCLBYTES;
86: for (i = 0; i < ncl; i++) {
87: ((union mcluster *)p)->mcl_next = mclfree;
88: mclfree = (union mcluster *)p;
89: p += MCLBYTES;
90: mbstat.m_clfree++;
91: }
92: mbstat.m_clusters += ncl;
93: return (1);
94: }
95:
96: /*
97: * When MGET failes, ask protocols to free space when short of memory,
98: * then re-attempt to allocate an mbuf.
99: */
100: struct mbuf *
101: m_retry(i, t)
102: int i, t;
103: {
104: register struct mbuf *m;
105:
106: m_reclaim();
107: #define m_retry(i, t) (struct mbuf *)0
108: MGET(m, i, t);
109: #undef m_retry
110: return (m);
111: }
112:
113: /*
114: * As above; retry an MGETHDR.
115: */
116: struct mbuf *
117: m_retryhdr(i, t)
118: int i, t;
119: {
120: register struct mbuf *m;
121:
122: m_reclaim();
123: #define m_retryhdr(i, t) (struct mbuf *)0
124: MGETHDR(m, i, t);
125: #undef m_retryhdr
126: return (m);
127: }
128:
129: m_reclaim()
130: {
131: register struct domain *dp;
132: register struct protosw *pr;
133: int s = splimp();
134:
135: for (dp = domains; dp; dp = dp->dom_next)
136: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
137: if (pr->pr_drain)
138: (*pr->pr_drain)();
139: splx(s);
140: mbstat.m_drain++;
141: }
142:
143: /*
144: * Space allocation routines.
145: * These are also available as macros
146: * for critical paths.
147: */
148: struct mbuf *
149: m_get(canwait, type)
150: int canwait, type;
151: {
152: register struct mbuf *m;
153:
154: MGET(m, canwait, type);
155: return (m);
156: }
157:
158: struct mbuf *
159: m_gethdr(canwait, type)
160: int canwait, type;
161: {
162: register struct mbuf *m;
163:
164: MGETHDR(m, canwait, type);
165: return (m);
166: }
167:
168: struct mbuf *
169: m_getclr(canwait, type)
170: int canwait, type;
171: {
172: register struct mbuf *m;
173:
174: MGET(m, canwait, type);
175: if (m == 0)
176: return (0);
177: bzero(mtod(m, caddr_t), MLEN);
178: return (m);
179: }
180:
181: struct mbuf *
182: m_free(m)
183: struct mbuf *m;
184: {
185: register struct mbuf *n;
186:
187: MFREE(m, n);
188: return (n);
189: }
190:
191: m_freem(m)
192: register struct mbuf *m;
193: {
194: register struct mbuf *n;
195:
196: if (m == NULL)
197: return;
198: do {
199: MFREE(m, n);
200: } while (m = n);
201: }
202:
203: /*
204: * Mbuffer utility routines.
205: */
206:
207: /*
208: * Lesser-used path for M_PREPEND:
209: * allocate new mbuf to prepend to chain,
210: * copy junk along.
211: */
212: struct mbuf *
213: m_prepend(m, len, how)
214: register struct mbuf *m;
215: int len, how;
216: {
217: struct mbuf *mn;
218:
219: MGET(mn, how, m->m_type);
220: if (mn == (struct mbuf *)NULL) {
221: m_freem(m);
222: return ((struct mbuf *)NULL);
223: }
224: if (m->m_flags & M_PKTHDR) {
225: M_COPY_PKTHDR(mn, m);
226: m->m_flags &= ~M_PKTHDR;
227: }
228: mn->m_next = m;
229: m = mn;
230: if (len < MHLEN)
231: MH_ALIGN(m, len);
232: m->m_len = len;
233: return (m);
234: }
235:
236: /*
237: * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
238: * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
239: * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
240: */
241: int MCFail;
242:
243: struct mbuf *
244: m_copym(m, off0, len, wait)
245: register struct mbuf *m;
246: int off0, wait;
247: register int len;
248: {
249: register struct mbuf *n, **np;
250: register int off = off0;
251: struct mbuf *top;
252: int copyhdr = 0;
253:
254: if (off < 0 || len < 0)
255: panic("m_copym");
256: if (off == 0 && m->m_flags & M_PKTHDR)
257: copyhdr = 1;
258: while (off > 0) {
259: if (m == 0)
260: panic("m_copym");
261: if (off < m->m_len)
262: break;
263: off -= m->m_len;
264: m = m->m_next;
265: }
266: np = ⊤
267: top = 0;
268: while (len > 0) {
269: if (m == 0) {
270: if (len != M_COPYALL)
271: panic("m_copym");
272: break;
273: }
274: MGET(n, wait, m->m_type);
275: *np = n;
276: if (n == 0)
277: goto nospace;
278: if (copyhdr) {
279: M_COPY_PKTHDR(n, m);
280: if (len == M_COPYALL)
281: n->m_pkthdr.len -= off0;
282: else
283: n->m_pkthdr.len = len;
284: copyhdr = 0;
285: }
286: n->m_len = MIN(len, m->m_len - off);
287: if (m->m_flags & M_EXT) {
288: n->m_data = m->m_data + off;
289: mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
290: n->m_ext = m->m_ext;
291: n->m_flags |= M_EXT;
292: } else
293: bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
294: (unsigned)n->m_len);
295: if (len != M_COPYALL)
296: len -= n->m_len;
297: off = 0;
298: m = m->m_next;
299: np = &n->m_next;
300: }
301: if (top == 0)
302: MCFail++;
303: return (top);
304: nospace:
305: m_freem(top);
306: MCFail++;
307: return (0);
308: }
309:
310: /*
311: * Copy data from an mbuf chain starting "off" bytes from the beginning,
312: * continuing for "len" bytes, into the indicated buffer.
313: */
314: m_copydata(m, off, len, cp)
315: register struct mbuf *m;
316: register int off;
317: register int len;
318: caddr_t cp;
319: {
320: register unsigned count;
321:
322: if (off < 0 || len < 0)
323: panic("m_copydata");
324: while (off > 0) {
325: if (m == 0)
326: panic("m_copydata");
327: if (off < m->m_len)
328: break;
329: off -= m->m_len;
330: m = m->m_next;
331: }
332: while (len > 0) {
333: if (m == 0)
334: panic("m_copydata");
335: count = MIN(m->m_len - off, len);
336: bcopy(mtod(m, caddr_t) + off, cp, count);
337: len -= count;
338: cp += count;
339: off = 0;
340: m = m->m_next;
341: }
342: }
343:
344: /*
345: * Concatenate mbuf chain n to m.
346: * Both chains must be of the same type (e.g. MT_DATA).
347: * Any m_pkthdr is not updated.
348: */
349: m_cat(m, n)
350: register struct mbuf *m, *n;
351: {
352: while (m->m_next)
353: m = m->m_next;
354: while (n) {
355: if (m->m_flags & M_EXT ||
356: m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
357: /* just join the two chains */
358: m->m_next = n;
359: return;
360: }
361: /* splat the data from one into the other */
362: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
363: (u_int)n->m_len);
364: m->m_len += n->m_len;
365: n = m_free(n);
366: }
367: }
368:
369: m_adj(mp, req_len)
370: struct mbuf *mp;
371: {
372: register int len = req_len;
373: register struct mbuf *m;
374: register count;
375:
376: if ((m = mp) == NULL)
377: return;
378: if (len >= 0) {
379: /*
380: * Trim from head.
381: */
382: while (m != NULL && len > 0) {
383: if (m->m_len <= len) {
384: len -= m->m_len;
385: m->m_len = 0;
386: m = m->m_next;
387: } else {
388: m->m_len -= len;
389: m->m_data += len;
390: len = 0;
391: }
392: }
393: m = mp;
394: if (mp->m_flags & M_PKTHDR)
395: m->m_pkthdr.len -= (req_len - len);
396: } else {
397: /*
398: * Trim from tail. Scan the mbuf chain,
399: * calculating its length and finding the last mbuf.
400: * If the adjustment only affects this mbuf, then just
401: * adjust and return. Otherwise, rescan and truncate
402: * after the remaining size.
403: */
404: len = -len;
405: count = 0;
406: for (;;) {
407: count += m->m_len;
408: if (m->m_next == (struct mbuf *)0)
409: break;
410: m = m->m_next;
411: }
412: if (m->m_len >= len) {
413: m->m_len -= len;
414: if ((mp = m)->m_flags & M_PKTHDR)
415: m->m_pkthdr.len -= len;
416: return;
417: }
418: count -= len;
419: if (count < 0)
420: count = 0;
421: /*
422: * Correct length for chain is "count".
423: * Find the mbuf with last data, adjust its length,
424: * and toss data from remaining mbufs on chain.
425: */
426: m = mp;
427: if (m->m_flags & M_PKTHDR)
428: m->m_pkthdr.len = count;
429: for (; m; m = m->m_next) {
430: if (m->m_len >= count) {
431: m->m_len = count;
432: break;
433: }
434: count -= m->m_len;
435: }
436: while (m = m->m_next)
437: m->m_len = 0;
438: }
439: }
440:
441: /*
442: * Rearange an mbuf chain so that len bytes are contiguous
443: * and in the data area of an mbuf (so that mtod and dtom
444: * will work for a structure of size len). Returns the resulting
445: * mbuf chain on success, frees it and returns null on failure.
446: * If there is room, it will add up to max_protohdr-len extra bytes to the
447: * contiguous region in an attempt to avoid being called next time.
448: */
449: int MPFail;
450:
451: struct mbuf *
452: m_pullup(n, len)
453: register struct mbuf *n;
454: int len;
455: {
456: register struct mbuf *m;
457: register int count;
458: int space;
459:
460: /*
461: * If first mbuf has no cluster, and has room for len bytes
462: * without shifting current data, pullup into it,
463: * otherwise allocate a new mbuf to prepend to the chain.
464: */
465: if ((n->m_flags & M_EXT) == 0 &&
466: n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
467: if (n->m_len >= len)
468: return (n);
469: m = n;
470: n = n->m_next;
471: len -= m->m_len;
472: } else {
473: if (len > MHLEN)
474: goto bad;
475: MGET(m, M_DONTWAIT, n->m_type);
476: if (m == 0)
477: goto bad;
478: m->m_len = 0;
479: if (n->m_flags & M_PKTHDR) {
480: M_COPY_PKTHDR(m, n);
481: n->m_flags &= ~M_PKTHDR;
482: }
483: }
484: space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
485: do {
486: count = min(min(max(len, max_protohdr), space), n->m_len);
487: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
488: (unsigned)count);
489: len -= count;
490: m->m_len += count;
491: n->m_len -= count;
492: space -= count;
493: if (n->m_len)
494: n->m_data += count;
495: else
496: n = m_free(n);
497: } while (len > 0 && n);
498: if (len > 0) {
499: (void) m_free(m);
500: goto bad;
501: }
502: m->m_next = n;
503: return (m);
504: bad:
505: m_freem(n);
506: MPFail++;
507: return (0);
508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.