Fixes allocb's use of mem flags
[akaros.git] / kern / src / ns / allocb.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15 #include <process.h>
16
17 enum {
18         Hdrspc = 64,                            /* leave room for high-level headers */
19         Bdead = 0x51494F42,     /* "QIOB" */
20         BLOCKALIGN = 32,        /* was the old BY2V in inferno, which was 8 */
21 };
22
23 static atomic_t ialloc_bytes = 0;
24
25 /*
26  *  allocate blocks (round data base address to 64 bit boundary).
27  *  if mallocz gives us more than we asked for, leave room at the front
28  *  for header.
29  */
30 static struct block *_allocb(int size, int mem_flags)
31 {
32         struct block *b;
33         uintptr_t addr;
34         int n;
35
36         b = kmalloc(sizeof(struct block) + size + Hdrspc + (BLOCKALIGN - 1),
37                                 mem_flags);
38         if (b == NULL)
39                 return NULL;
40
41         b->next = NULL;
42         b->list = NULL;
43         b->free = NULL;
44         b->flag = 0;
45
46         addr = (uintptr_t) b;
47         addr = ROUNDUP(addr + sizeof(struct block), BLOCKALIGN);
48         b->base = (uint8_t *) addr;
49         /* TODO: support this */
50         /* interesting. We can ask the allocator, after allocating,
51          * the *real* size of the block we got. Very nice.
52          * Not on akaros yet.
53          b->lim = ((uint8_t*)b) + msize(b);
54          */
55         b->lim =
56                 ((uint8_t *) b) + sizeof(struct block) + size + Hdrspc + (BLOCKALIGN -
57                                                                                                                                   1);
58         b->rp = b->base;
59         n = b->lim - b->base - size;
60         b->rp += n & ~(BLOCKALIGN - 1);
61         b->wp = b->rp;
62         /* b->base is aligned, rounded up from b
63          * b->lim is the upper bound on our malloc
64          * b->rp is advanced by some aligned amount, based on how much extra we
65          * received from kmalloc and the Hdrspc. */
66         return b;
67 }
68
69 struct block *allocb(int size)
70 {
71         return _allocb(size, KMALLOC_WAIT);
72 }
73
74
75 /*
76  *  interrupt time allocation
77  */
78 struct block *iallocb(int size)
79 {
80         struct block *b;
81
82 #if 0   /* conf is some inferno global config */
83         if (atomic_read(&ialloc_bytes) > conf.ialloc) {
84                 //printk("iallocb: limited %lu/%lu\n", atomic_read(&ialloc_bytes),
85                 //       conf.ialloc);
86                 return NULL;
87         }
88 #endif
89
90         b = _allocb(size, 0);   /* no KMALLOC_WAIT */
91         if (b == NULL) {
92                 //printk("iallocb: no memory %lu/%lu\n", atomic_read(&ialloc_bytes),
93                 //       conf.ialloc);
94                 return NULL;
95         }
96         b->flag = BINTR;
97
98         atomic_add(&ialloc_bytes, b->lim - b->base);
99
100         return b;
101 }
102
103 void freeb(struct block *b)
104 {
105         void *dead = (void *)Bdead;
106
107         if (b == NULL)
108                 return;
109
110         /*
111          * drivers which perform non cache coherent DMA manage their own buffer
112          * pool of uncached buffers and provide their own free routine.
113          */
114         if (b->free) {
115                 b->free(b);
116                 return;
117         }
118         if (b->flag & BINTR) {
119                 /* subtracting the size of b */
120                 atomic_add(&ialloc_bytes, -(b->lim - b->base));
121         }
122
123         /* poison the block in case someone is still holding onto it */
124         b->next = dead;
125         b->rp = dead;
126         b->wp = dead;
127         b->lim = dead;
128         b->base = dead;
129
130         kfree(b);
131 }
132
133 void checkb(struct block *b, char *msg)
134 {
135         void *dead = (void *)Bdead;
136
137         if (b == dead)
138                 panic("checkb b %s 0x%lx", msg, b);
139         if (b->base == dead || b->lim == dead || b->next == dead
140                 || b->rp == dead || b->wp == dead) {
141                 printd("checkb: base 0x%8.8lx lim 0x%8.8lx next 0x%8.8lx\n",
142                            b->base, b->lim, b->next);
143                 printd("checkb: rp 0x%8.8lx wp 0x%8.8lx\n", b->rp, b->wp);
144                 panic("checkb dead: %s\n", msg);
145         }
146
147         if (b->base > b->lim)
148                 panic("checkb 0 %s 0x%lx 0x%lx", msg, b->base, b->lim);
149         if (b->rp < b->base)
150                 panic("checkb 1 %s 0x%lx 0x%lx", msg, b->base, b->rp);
151         if (b->wp < b->base)
152                 panic("checkb 2 %s 0x%lx 0x%lx", msg, b->base, b->wp);
153         if (b->rp > b->lim)
154                 panic("checkb 3 %s 0x%lx 0x%lx", msg, b->rp, b->lim);
155         if (b->wp > b->lim)
156                 panic("checkb 4 %s 0x%lx 0x%lx", msg, b->wp, b->lim);
157
158 }
159
160 void iallocsummary(void)
161 {
162         printd("ialloc %lu/%lu\n", atomic_read(&ialloc_bytes), 0 /*conf.ialloc */ );
163 }