📄 uipc_mbuf.c
字号:
/* $Id: uipc_mbuf.c,v 1.3 1997/09/01 14:46:08 nigel Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91 */#include "param.h"#include "proc.h"#include "malloc.h"#include "map.h"#define MBTYPES#include "mbuf.h"#include "kernel.h"#include "syslog.h"#include "domain.h"#include "protosw.h"#include "vm/vm.h"extern vm_map_t mb_map;struct mbuf *mbutl;char *mclrefcnt;mbinit(){ int s;#if CLBYTES < 4096#define NCL_INIT (4096/CLBYTES)#else#define NCL_INIT 1#endif s = splimp(); if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) goto bad; splx(s); return;bad: panic("mbinit");}/* * Allocate some number of mbuf clusters * and place on cluster free list. * Must be called at splimp. *//* ARGSUSED */m_clalloc(ncl, canwait) register int ncl;{ int npg, mbx; register caddr_t p; register int i; static int logged; npg = ncl * CLSIZE; p = (caddr_t)kmem_malloc(mb_map, ctob(npg), canwait); if (p == NULL) { if (logged == 0) { logged++; log(LOG_INFO, "mb_map full\n"); } m_reclaim(); if (mclfree != NULL) return (1); } if (p == NULL) return (0); if (!mbutl) mbutl = (struct mbuf *)p; ncl = ncl * CLBYTES / MCLBYTES; for (i = 0; i < ncl; i++) { ((union mcluster *)p)->mcl_next = mclfree; mclfree = (union mcluster *)p; p += MCLBYTES; mbstat.m_clfree++; } mbstat.m_clusters += ncl; return (1);}/* * When MGET failes, ask protocols to free space when short of memory, * then re-attempt to allocate an mbuf. */struct mbuf *m_retry(i, t) int i, t;{ register struct mbuf *m; m_reclaim();#define m_retry(i, t) (struct mbuf *)0 MGET(m, i, t);#undef m_retry return (m);}/* * As above; retry an MGETHDR. */struct mbuf *m_retryhdr(i, t) int i, t;{ register struct mbuf *m; m_reclaim();#define m_retryhdr(i, t) (struct mbuf *)0 MGETHDR(m, i, t);#undef m_retryhdr return (m);}m_reclaim(){ register struct domain *dp; register const struct protosw *pr; int s = splimp(); for (dp = domains; dp; dp = dp->dom_next) for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_drain) (*pr->pr_drain)(); splx(s); mbstat.m_drain++;}/* * Space allocation routines. * These are also available as macros * for critical paths. */struct mbuf *m_get(canwait, type) int canwait, type;{ register struct mbuf *m; MGET(m, canwait, type); return (m);}struct mbuf *m_gethdr(canwait, type) int canwait, type;{ register struct mbuf *m; MGETHDR(m, canwait, type); return (m);}struct mbuf *m_getclr(canwait, type) int canwait, type;{ register struct mbuf *m; MGET(m, canwait, type); if (m == 0) return (0); bzero(mtod(m, caddr_t), MLEN); return (m);}struct mbuf *m_free(m) struct mbuf *m;{ register struct mbuf *n; MFREE(m, n); return (n);}m_freem(m) register struct mbuf *m;{ register struct mbuf *n; if (m == NULL) return; do { MFREE(m, n); } while (m = n);}/* * Mbuffer utility routines. *//* * Lesser-used path for M_PREPEND: * allocate new mbuf to prepend to chain, * copy junk along. */struct mbuf *m_prepend(m, len, how) register struct mbuf *m; int len, how;{ struct mbuf *mn; MGET(mn, how, m->m_type); if (mn == (struct mbuf *)NULL) { m_freem(m); return ((struct mbuf *)NULL); } if (m->m_flags & M_PKTHDR) { M_COPY_PKTHDR(mn, m); m->m_flags &= ~M_PKTHDR; } mn->m_next = m; m = mn; if (len < MHLEN) MH_ALIGN(m, len); m->m_len = len; return (m);}/* * Make a copy of an mbuf chain starting "off0" bytes from the beginning, * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. */int MCFail;struct mbuf *m_copym(m, off0, len, wait) register struct mbuf *m; int off0, wait; register int len;{ register struct mbuf *n, **np; register int off = off0; struct mbuf *top; int copyhdr = 0; if (off < 0 || len < 0) panic("m_copym"); if (off == 0 && m->m_flags & M_PKTHDR) copyhdr = 1; while (off > 0) { if (m == 0) panic("m_copym"); if (off < m->m_len) break; off -= m->m_len; m = m->m_next; } np = ⊤ top = 0; while (len > 0) { if (m == 0) { if (len != M_COPYALL) panic("m_copym"); break; } MGET(n, wait, m->m_type); *np = n; if (n == 0) goto nospace; if (copyhdr) { M_COPY_PKTHDR(n, m); if (len == M_COPYALL) n->m_pkthdr.len -= off0; else n->m_pkthdr.len = len; copyhdr = 0; } n->m_len = MIN(len, m->m_len - off); if (m->m_flags & M_EXT) { n->m_data = m->m_data + off; mclrefcnt[mtocl(m->m_ext.ext_buf)]++; n->m_ext = m->m_ext; n->m_flags |= M_EXT; } else bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), (unsigned)n->m_len); if (len != M_COPYALL) len -= n->m_len; off = 0; m = m->m_next; np = &n->m_next; } if (top == 0) MCFail++; return (top);nospace: m_freem(top); MCFail++; return (0);}/* * Copy data from an mbuf chain starting "off" bytes from the beginning, * continuing for "len" bytes, into the indicated buffer. */m_copydata(m, off, len, cp) register struct mbuf *m; register int off; register int len; caddr_t cp;{ register unsigned count; if (off < 0 || len < 0) panic("m_copydata"); while (off > 0) { if (m == 0) panic("m_copydata"); if (off < m->m_len) break; off -= m->m_len; m = m->m_next; } while (len > 0) { if (m == 0) panic("m_copydata"); count = MIN(m->m_len - off, len); bcopy(mtod(m, caddr_t) + off, cp, count); len -= count; cp += count; off = 0; m = m->m_next; }}/* * Concatenate mbuf chain n to m. * Both chains must be of the same type (e.g. MT_DATA). * Any m_pkthdr is not updated. */m_cat(m, n) register struct mbuf *m, *n;{ while (m->m_next) m = m->m_next; while (n) { if (m->m_flags & M_EXT || m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { /* just join the two chains */ m->m_next = n; return; } /* splat the data from one into the other */ bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, (u_int)n->m_len); m->m_len += n->m_len; n = m_free(n); }}m_adj(mp, req_len) struct mbuf *mp;{ register int len = req_len; register struct mbuf *m; register count; if ((m = mp) == NULL) return; if (len >= 0) { /* * Trim from head. */ while (m != NULL && len > 0) { if (m->m_len <= len) { len -= m->m_len; m->m_len = 0; m = m->m_next; } else { m->m_len -= len; m->m_data += len; len = 0; } } m = mp; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= (req_len - len); } else { /* * Trim from tail. Scan the mbuf chain, * calculating its length and finding the last mbuf. * If the adjustment only affects this mbuf, then just * adjust and return. Otherwise, rescan and truncate * after the remaining size. */ len = -len; count = 0; for (;;) { count += m->m_len; if (m->m_next == (struct mbuf *)0) break; m = m->m_next; } if (m->m_len >= len) { m->m_len -= len; m = mp; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= len; return; } count -= len; if (count < 0) count = 0; /* * Correct length for chain is "count". * Find the mbuf with last data, adjust its length, * and toss data from remaining mbufs on chain. */ m = mp; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len = count; for (; m; m = m->m_next) { if (m->m_len >= count) { m->m_len = count; break; } count -= m->m_len; } while (m = m->m_next) m->m_len = 0; }}/* * Rearange an mbuf chain so that len bytes are contiguous * and in the data area of an mbuf (so that mtod and dtom * will work for a structure of size len). Returns the resulting * mbuf chain on success, frees it and returns null on failure. * If there is room, it will add up to max_protohdr-len extra bytes to the * contiguous region in an attempt to avoid being called next time. */int MPFail;struct mbuf *m_pullup(n, len) register struct mbuf *n; int len;{ register struct mbuf *m; register int count; int space; /* * If first mbuf has no cluster, and has room for len bytes * without shifting current data, pullup into it, * otherwise allocate a new mbuf to prepend to the chain. */ if ((n->m_flags & M_EXT) == 0 && n->m_data + len < &n->m_dat[MLEN] && n->m_next) { if (n->m_len >= len) return (n); m = n; n = n->m_next; len -= m->m_len; } else { if (len > MHLEN) goto bad; MGET(m, M_DONTWAIT, n->m_type); if (m == 0) goto bad; m->m_len = 0; if (n->m_flags & M_PKTHDR) { M_COPY_PKTHDR(m, n); n->m_flags &= ~M_PKTHDR; } } space = &m->m_dat[MLEN] - (m->m_data + m->m_len); do { count = min(min(max(len, max_protohdr), space), n->m_len); bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, (unsigned)count); len -= count; m->m_len += count; n->m_len -= count; space -= count; if (n->m_len) n->m_data += count; else n = m_free(n); } while (len > 0 && n); if (len > 0) { (void) m_free(m); goto bad; } m->m_next = n; return (m);bad: m_freem(n); MPFail++; return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -