xref: /original-bsd/sys/kern/uipc_mbuf.c (revision f0fd5f8a)
1 /*	uipc_mbuf.c	1.42	82/12/17	*/
2 
3 #include "../machine/pte.h"
4 
5 #include "../h/param.h"
6 #include "../h/dir.h"
7 #include "../h/user.h"
8 #include "../h/proc.h"
9 #include "../h/cmap.h"
10 #include "../h/map.h"
11 #include "../h/mbuf.h"
12 #include "../h/vm.h"
13 #include "../h/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 	int type;
185 
186 	if (len == 0)
187 		return (0);
188 	if (off < 0 || len < 0)
189 		panic("m_copy");
190 	type = m->m_type;
191 	while (off > 0) {
192 		if (m == 0)
193 			panic("m_copy");
194 		if (off < m->m_len)
195 			break;
196 		off -= m->m_len;
197 		m = m->m_next;
198 	}
199 	np = &top;
200 	top = 0;
201 	while (len > 0) {
202 		if (m == 0) {
203 			if (len != M_COPYALL)
204 				panic("m_copy");
205 			break;
206 		}
207 		MGET(n, M_WAIT, type);
208 		*np = n;
209 		if (n == 0)
210 			goto nospace;
211 		n->m_len = MIN(len, m->m_len - off);
212 		if (m->m_off > MMAXOFF) {
213 			p = mtod(m, struct mbuf *);
214 			n->m_off = ((int)p - (int)n) + off;
215 			mclrefcnt[mtocl(p)]++;
216 		} else
217 			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
218 			    (unsigned)n->m_len);
219 		if (len != M_COPYALL)
220 			len -= n->m_len;
221 		off = 0;
222 		m = m->m_next;
223 		np = &n->m_next;
224 	}
225 	return (top);
226 nospace:
227 	m_freem(top);
228 	return (0);
229 }
230 
231 m_cat(m, n)
232 	register struct mbuf *m, *n;
233 {
234 	while (m->m_next)
235 		m = m->m_next;
236 	while (n) {
237 		if (m->m_off >= MMAXOFF ||
238 		    m->m_off + m->m_len + n->m_len > MMAXOFF) {
239 			/* just join the two chains */
240 			m->m_next = n;
241 			return;
242 		}
243 		/* splat the data from one into the other */
244 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
245 		    (u_int)n->m_len);
246 		m->m_len += n->m_len;
247 		n = m_free(n);
248 	}
249 }
250 
251 m_adj(mp, len)
252 	struct mbuf *mp;
253 	register int len;
254 {
255 	register struct mbuf *m, *n;
256 
257 	if ((m = mp) == NULL)
258 		return;
259 	if (len >= 0) {
260 		while (m != NULL && len > 0) {
261 			if (m->m_len <= len) {
262 				len -= m->m_len;
263 				m->m_len = 0;
264 				m = m->m_next;
265 			} else {
266 				m->m_len -= len;
267 				m->m_off += len;
268 				break;
269 			}
270 		}
271 	} else {
272 		/* a 2 pass algorithm might be better */
273 		len = -len;
274 		while (len > 0 && m->m_len != 0) {
275 			while (m != NULL && m->m_len != 0) {
276 				n = m;
277 				m = m->m_next;
278 			}
279 			if (n->m_len <= len) {
280 				len -= n->m_len;
281 				n->m_len = 0;
282 				m = mp;
283 			} else {
284 				n->m_len -= len;
285 				break;
286 			}
287 		}
288 	}
289 }
290 
291 struct mbuf *
292 m_pullup(m0, len)
293 	struct mbuf *m0;
294 	int len;
295 {
296 	register struct mbuf *m, *n;
297 	int count;
298 
299 	n = m0;
300 	if (len > MLEN)
301 		goto bad;
302 	MGET(m, M_DONTWAIT, n->m_type);
303 	if (m == 0)
304 		goto bad;
305 	m->m_len = 0;
306 	do {
307 		count = MIN(MLEN - m->m_len, len);
308 		if (count > n->m_len)
309 			count = n->m_len;
310 		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
311 		  (unsigned)count);
312 		len -= count;
313 		m->m_len += count;
314 		n->m_off += count;
315 		n->m_len -= count;
316 		if (n->m_len)
317 			break;
318 		n = m_free(n);
319 	} while (n);
320 	if (len) {
321 		(void) m_free(m);
322 		goto bad;
323 	}
324 	m->m_next = n;
325 	return (m);
326 bad:
327 	m_freem(n);
328 	return (0);
329 }
330