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