hammer2 - Limit bulkfree cpu and SSD I/O
[dragonfly.git] / usr.sbin / ppp / mbuf.c
blob30b73260033cf6f355be357d022b9683b421e297
1 /*-
2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
28 * $FreeBSD: src/usr.sbin/ppp/mbuf.c,v 1.36.2.5 2002/09/01 02:12:28 brian Exp $
31 #include <sys/types.h>
32 #include <sys/select.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sysexits.h>
39 #include <termios.h>
41 #include "defs.h"
42 #include "command.h"
43 #include "mbuf.h"
44 #include "log.h"
45 #include "descriptor.h"
46 #include "prompt.h"
47 #include "main.h"
49 #define BUCKET_CHUNK 20
50 #define BUCKET_HASH 256
52 struct mbucket;
54 struct mfree {
55 struct mbucket *next;
56 size_t count;
59 static struct mbucket {
60 union {
61 struct mbuf m;
62 struct mfree f;
63 } u;
64 } *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
66 #define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
67 #define M_BUCKET(sz) (bucket + M_BINDEX(sz))
68 #define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH)
70 static struct memmap {
71 struct mbuf *queue;
72 size_t fragments;
73 size_t octets;
74 } MemMap[MB_MAX + 1];
76 static unsigned long long mbuf_Mallocs, mbuf_Frees;
78 size_t
79 m_length(struct mbuf *bp)
81 size_t len;
83 for (len = 0; bp; bp = bp->m_next)
84 len += bp->m_len;
85 return len;
88 static const char *
89 mbuftype(int type)
91 static const char * const mbufdesc[MB_MAX] = {
92 "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
93 "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
94 "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
95 "proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
96 "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
97 "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
98 "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
101 return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
104 struct mbuf *
105 m_get(size_t m_len, int type)
107 struct mbucket **mb;
108 struct mbuf *bp;
109 size_t size;
111 if (type > MB_MAX) {
112 log_Printf(LogERROR, "Bad mbuf type %d\n", type);
113 type = MB_UNKNOWN;
116 if (m_len > M_MAXLEN || m_len == 0) {
117 log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
118 (u_long)m_len, mbuftype(type));
119 AbortProgram(EX_OSERR);
122 mb = M_BUCKET(m_len);
123 size = M_ROUNDUP(m_len);
125 if (*mb) {
126 /* We've got some free blocks of the right size */
127 bp = &(*mb)->u.m;
128 if (--(*mb)->u.f.count == 0)
129 *mb = (*mb)->u.f.next;
130 else {
131 ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
132 *mb = (struct mbucket *)((char *)*mb + size);
133 (*mb)->u.f.next = NULL;
135 } else {
137 * Allocate another chunk of mbufs, use the first and put the rest on
138 * the free list
140 *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
141 if (*mb == NULL) {
142 log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
143 (unsigned long)BUCKET_CHUNK * size);
144 AbortProgram(EX_OSERR);
146 bp = &(*mb)->u.m;
147 *mb = (struct mbucket *)((char *)*mb + size);
148 (*mb)->u.f.count = BUCKET_CHUNK - 1;
149 (*mb)->u.f.next = NULL;
152 mbuf_Mallocs++;
154 memset(bp, '\0', sizeof(struct mbuf));
155 bp->m_size = size - sizeof *bp;
156 bp->m_len = m_len;
157 bp->m_type = type;
159 MemMap[type].fragments++;
160 MemMap[type].octets += bp->m_size;
162 return bp;
165 struct mbuf *
166 m_free(struct mbuf *bp)
168 struct mbucket **mb, *f;
169 struct mbuf *nbp;
171 if ((f = (struct mbucket *)bp) != NULL) {
172 MemMap[bp->m_type].fragments--;
173 MemMap[bp->m_type].octets -= bp->m_size;
175 nbp = bp->m_next;
176 mb = M_BUCKET(bp->m_size);
177 f->u.f.next = *mb;
178 f->u.f.count = 1;
179 *mb = f;
181 mbuf_Frees++;
182 bp = nbp;
185 return bp;
188 void
189 m_freem(struct mbuf *bp)
191 while (bp)
192 bp = m_free(bp);
195 struct mbuf *
196 mbuf_Read(struct mbuf *bp, void *v, size_t len)
198 int nb;
199 u_char *ptr = v;
201 while (bp && len > 0) {
202 if (len > bp->m_len)
203 nb = bp->m_len;
204 else
205 nb = len;
206 if (nb) {
207 memcpy(ptr, MBUF_CTOP(bp), nb);
208 ptr += nb;
209 bp->m_len -= nb;
210 len -= nb;
211 bp->m_offset += nb;
213 if (bp->m_len == 0)
214 bp = m_free(bp);
217 while (bp && bp->m_len == 0)
218 bp = m_free(bp);
220 return bp;
223 size_t
224 mbuf_View(struct mbuf *bp, void *v, size_t len)
226 size_t nb, l = len;
227 u_char *ptr = v;
229 while (bp && l > 0) {
230 if (l > bp->m_len)
231 nb = bp->m_len;
232 else
233 nb = l;
234 memcpy(ptr, MBUF_CTOP(bp), nb);
235 ptr += nb;
236 l -= nb;
237 bp = bp->m_next;
240 return len - l;
243 struct mbuf *
244 m_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra)
246 struct mbuf *head;
248 if (bp && bp->m_offset) {
249 if (bp->m_offset >= len) {
250 bp->m_offset -= len;
251 bp->m_len += len;
252 memcpy(MBUF_CTOP(bp), ptr, len);
253 return bp;
255 len -= bp->m_offset;
256 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
257 bp->m_len += bp->m_offset;
258 bp->m_offset = 0;
261 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
262 head->m_offset = extra;
263 head->m_len -= extra;
264 if (ptr)
265 memcpy(MBUF_CTOP(head), ptr, len);
266 head->m_next = bp;
268 return head;
271 struct mbuf *
272 m_adj(struct mbuf *bp, ssize_t n)
274 if (n > 0) {
275 while (bp) {
276 if ((size_t)n < bp->m_len) {
277 bp->m_len = n;
278 bp->m_offset += n;
279 return bp;
281 n -= bp->m_len;
282 bp = m_free(bp);
284 } else {
285 if ((n = m_length(bp) + n) <= 0) {
286 m_freem(bp);
287 return NULL;
289 for (; bp; bp = bp->m_next, n -= bp->m_len)
290 if ((size_t)n < bp->m_len) {
291 bp->m_len = n;
292 m_freem(bp->m_next);
293 bp->m_next = NULL;
294 break;
298 return bp;
301 void
302 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
304 size_t plen;
305 int nb;
307 plen = m_length(bp);
308 if (plen < m_len)
309 m_len = plen;
311 while (m_len > 0) {
312 nb = (m_len < bp->m_len) ? m_len : bp->m_len;
313 memcpy(MBUF_CTOP(bp), ptr, nb);
314 m_len -= bp->m_len;
315 bp = bp->m_next;
320 mbuf_Show(struct cmdargs const *arg)
322 int i;
324 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
325 for (i = 0; i < MB_MAX; i += 2)
326 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
327 "%10.10s: %04lu (%06lu)\n",
328 mbuftype(i), (u_long)MemMap[i].fragments,
329 (u_long)MemMap[i].octets, mbuftype(i+1),
330 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
332 if (i == MB_MAX)
333 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
334 mbuftype(i), (u_long)MemMap[i].fragments,
335 (u_long)MemMap[i].octets);
337 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n",
338 mbuf_Mallocs, mbuf_Frees);
340 return 0;
343 struct mbuf *
344 m_dequeue(struct mqueue *q)
346 struct mbuf *bp;
348 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
349 bp = q->top;
350 if (bp) {
351 q->top = q->top->m_nextpkt;
352 q->len--;
353 if (q->top == NULL) {
354 q->last = q->top;
355 if (q->len)
356 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
357 (u_long)q->len);
359 bp->m_nextpkt = NULL;
362 return bp;
365 void
366 m_enqueue(struct mqueue *queue, struct mbuf *bp)
368 if (bp != NULL) {
369 if (queue->last) {
370 queue->last->m_nextpkt = bp;
371 queue->last = bp;
372 } else
373 queue->last = queue->top = bp;
374 queue->len++;
375 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
379 struct mbuf *
380 m_pullup(struct mbuf *bp)
382 /* Put it all in one contigous (aligned) mbuf */
384 if (bp != NULL) {
385 if (bp->m_next != NULL) {
386 struct mbuf *nbp;
387 u_char *cp;
389 nbp = m_get(m_length(bp), bp->m_type);
391 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
392 memcpy(cp, MBUF_CTOP(bp), bp->m_len);
393 cp += bp->m_len;
395 bp = nbp;
396 } else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
397 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
398 bp->m_offset = 0;
402 return bp;
405 void
406 m_settype(struct mbuf *bp, int type)
408 for (; bp; bp = bp->m_next)
409 if (type != bp->m_type) {
410 MemMap[bp->m_type].fragments--;
411 MemMap[bp->m_type].octets -= bp->m_size;
412 bp->m_type = type;
413 MemMap[type].fragments++;
414 MemMap[type].octets += bp->m_size;
418 struct mbuf *
419 m_append(struct mbuf *bp, const void *v, size_t sz)
421 struct mbuf *m = bp;
423 if (m) {
424 while (m->m_next)
425 m = m->m_next;
426 if (m->m_size - m->m_len > sz)
427 m->m_len += sz;
428 else
429 m->m_next = m_prepend(NULL, v, sz, 0);
430 } else
431 bp = m_prepend(NULL, v, sz, 0);
433 return bp;