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