xref: /csrg-svn/sys/kern/uipc_mbuf.c (revision 7178)
1 /*	uipc_mbuf.c	1.35	82/06/14	*/
2 
3 #include "../h/param.h"
4 #include "../h/dir.h"
5 #include "../h/user.h"
6 #include "../h/proc.h"
7 #include "../h/pte.h"
8 #include "../h/cmap.h"
9 #include "../h/map.h"
10 #include "../h/mbuf.h"
11 #include "../net/in_systm.h"		/* XXX */
12 #include "../h/vm.h"
13 
14 mbinit()
15 {
16 
17 COUNT(MBINIT);
18 	if (m_clalloc(4, MPG_MBUFS) == 0)
19 		goto bad;
20 	if (m_clalloc(32, MPG_CLUSTERS) == 0)
21 		goto bad;
22 	return;
23 bad:
24 	panic("mbinit");
25 }
26 
27 caddr_t
28 m_clalloc(ncl, how)
29 	register int ncl;
30 	int how;
31 {
32 	int npg, mbx;
33 	register struct mbuf *m;
34 	register int i;
35 	int s;
36 
37 COUNT(M_CLALLOC);
38 	npg = ncl * CLSIZE;
39 	s = splimp();		/* careful: rmalloc isn't reentrant */
40 	mbx = rmalloc(mbmap, npg);
41 	splx(s);
42 	if (mbx == 0)
43 		return (0);
44 	m = cltom(mbx / CLSIZE);
45 	if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0)
46 		return (0);
47 	vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
48 	switch (how) {
49 
50 	case MPG_CLUSTERS:
51 		s = splimp();
52 		for (i = 0; i < ncl; i++) {
53 			m->m_off = 0;
54 			m->m_next = mclfree;
55 			mclfree = m;
56 			m += CLBYTES / sizeof (*m);
57 			mbstat.m_clfree++;
58 		}
59 		mbstat.m_clusters += ncl;
60 		splx(s);
61 		break;
62 
63 	case MPG_MBUFS:
64 		for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
65 			m->m_off = 0;
66 			m->m_free = 0;
67 			mbstat.m_mbufs++;
68 			(void) m_free(m);
69 			m++;
70 		}
71 		break;
72 	}
73 	return ((caddr_t)m);
74 }
75 
76 m_pgfree(addr, n)
77 	caddr_t addr;
78 	int n;
79 {
80 
81 COUNT(M_PGFREE);
82 #ifdef lint
83 	addr = addr; n = n;
84 #endif
85 }
86 
87 m_expand()
88 {
89 
90 COUNT(M_EXPAND);
91 	if (m_clalloc(1, MPG_MBUFS) == 0)
92 		goto steal;
93 	return (1);
94 steal:
95 	/* should ask protocols to free code */
96 	return (0);
97 }
98 
99 /* NEED SOME WAY TO RELEASE SPACE */
100 
101 /*
102  * Space allocation routines.
103  * These are also available as macros
104  * for critical paths.
105  */
106 struct mbuf *
107 m_get(canwait)
108 	int canwait;
109 {
110 	register struct mbuf *m;
111 
112 COUNT(M_GET);
113 	MGET(m, canwait);
114 	return (m);
115 }
116 
117 struct mbuf *
118 m_getclr(canwait)
119 	int canwait;
120 {
121 	register struct mbuf *m;
122 
123 COUNT(M_GETCLR);
124 	m = m_get(canwait);
125 	if (m == 0)
126 		return (0);
127 	m->m_off = MMINOFF;
128 	bzero(mtod(m, caddr_t), MLEN);
129 	return (m);
130 }
131 
132 struct mbuf *
133 m_free(m)
134 	struct mbuf *m;
135 {
136 	register struct mbuf *n;
137 
138 COUNT(M_FREE);
139 	MFREE(m, n);
140 	return (n);
141 }
142 
143 /*ARGSUSED*/
144 struct mbuf *
145 m_more(type)
146 	int type;
147 {
148 	register struct mbuf *m;
149 
150 COUNT(M_MORE);
151 	if (!m_expand()) {
152 		mbstat.m_drops++;
153 		return (NULL);
154 	}
155 #define m_more(x) (panic("m_more"), (struct mbuf *)0)
156 	MGET(m, type);
157 #undef m_more
158 	return (m);
159 }
160 
161 m_freem(m)
162 	register struct mbuf *m;
163 {
164 	register struct mbuf *n;
165 	register int s;
166 
167 COUNT(M_FREEM);
168 	if (m == NULL)
169 		return;
170 	s = splimp();
171 	do {
172 		MFREE(m, n);
173 	} while (m = n);
174 	splx(s);
175 }
176 
177 /*
178  * Mbuffer utility routines.
179  */
180 struct mbuf *
181 m_copy(m, off, len)
182 	register struct mbuf *m;
183 	int off;
184 	register int len;
185 {
186 	register struct mbuf *n, **np;
187 	struct mbuf *top, *p;
188 COUNT(M_COPY);
189 
190 	if (len == 0)
191 		return (0);
192 	if (off < 0 || len < 0)
193 		panic("m_copy");
194 	while (off > 0) {
195 		if (m == 0)
196 			panic("m_copy");
197 		if (off < m->m_len)
198 			break;
199 		off -= m->m_len;
200 		m = m->m_next;
201 	}
202 	np = &top;
203 	top = 0;
204 	while (len > 0) {
205 		if (m == 0) {
206 			if (len != M_COPYALL)
207 				panic("m_copy");
208 			break;
209 		}
210 		MGET(n, 1);
211 		*np = n;
212 		if (n == 0)
213 			goto nospace;
214 		n->m_len = MIN(len, m->m_len - off);
215 		if (m->m_off > MMAXOFF) {
216 			p = mtod(m, struct mbuf *);
217 			n->m_off = ((int)p - (int)n) + off;
218 			mclrefcnt[mtocl(p)]++;
219 		} else {
220 			n->m_off = MMINOFF;
221 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
222 			    (unsigned)n->m_len);
223 		}
224 		if (len != M_COPYALL)
225 			len -= n->m_len;
226 		off = 0;
227 		m = m->m_next;
228 		np = &n->m_next;
229 	}
230 	return (top);
231 nospace:
232 	m_freem(top);
233 	return (0);
234 }
235 
236 m_cat(m, n)
237 	register struct mbuf *m, *n;
238 {
239 	while (m->m_next)
240 		m = m->m_next;
241 	while (n) {
242 		if (m->m_off >= MMAXOFF ||
243 		    m->m_off + m->m_len + n->m_len > MMAXOFF) {
244 			/* just join the two chains */
245 			m->m_next = n;
246 			return;
247 		}
248 		/* splat the data from one into the other */
249 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
250 		    (u_int)n->m_len);
251 		m->m_len += n->m_len;
252 		n = m_free(n);
253 	}
254 }
255 
256 m_adj(mp, len)
257 	struct mbuf *mp;
258 	register int len;
259 {
260 	register struct mbuf *m, *n;
261 
262 COUNT(M_ADJ);
263 	if ((m = mp) == NULL)
264 		return;
265 	if (len >= 0) {
266 		while (m != NULL && len > 0) {
267 			if (m->m_len <= len) {
268 				len -= m->m_len;
269 				m->m_len = 0;
270 				m = m->m_next;
271 			} else {
272 				m->m_len -= len;
273 				m->m_off += len;
274 				break;
275 			}
276 		}
277 	} else {
278 		/* a 2 pass algorithm might be better */
279 		len = -len;
280 		while (len > 0 && m->m_len != 0) {
281 			while (m != NULL && m->m_len != 0) {
282 				n = m;
283 				m = m->m_next;
284 			}
285 			if (n->m_len <= len) {
286 				len -= n->m_len;
287 				n->m_len = 0;
288 				m = mp;
289 			} else {
290 				n->m_len -= len;
291 				break;
292 			}
293 		}
294 	}
295 }
296 
297 struct mbuf *
298 m_pullup(m0, len)
299 	struct mbuf *m0;
300 	int len;
301 {
302 	register struct mbuf *m, *n;
303 	int count;
304 
305 	n = m0;
306 	if (len > MLEN)
307 		goto bad;
308 	MGET(m, 0);
309 	if (m == 0)
310 		goto bad;
311 	m->m_off = MMINOFF;
312 	m->m_len = 0;
313 	do {
314 		count = MIN(MLEN - m->m_len, len);
315 		if (count > n->m_len)
316 			count = n->m_len;
317 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
318 		  (unsigned)count);
319 		len -= count;
320 		m->m_len += count;
321 		n->m_off += count;
322 		n->m_len -= count;
323 		if (n->m_len)
324 			break;
325 		n = m_free(n);
326 	} while (n);
327 	if (len) {
328 		(void) m_free(m);
329 		goto bad;
330 	}
331 	m->m_next = n;
332 	return (m);
333 bad:
334 	m_freem(n);
335 	return (0);
336 }
337