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