]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/venti/srv/arenas.c
0316c4c86772adf37a92a185c935ed7d9331b0b2
[plan9front.git] / sys / src / cmd / venti / srv / arenas.c
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4
5 typedef struct AHash    AHash;
6
7 /*
8  * hash table for finding arena's based on their names.
9  */
10 struct AHash
11 {
12         AHash   *next;
13         Arena   *arena;
14 };
15
16 enum
17 {
18         AHashSize       = 512
19 };
20
21 static AHash    *ahash[AHashSize];
22
23 static u32int
24 hashstr(char *s)
25 {
26         u32int h;
27         int c;
28
29         h = 0;
30         for(; c = *s; s++){
31                 c ^= c << 6;
32                 h += (c << 11) ^ (c >> 1);
33                 c = *s;
34                 h ^= (c << 14) + (c << 7) + (c << 4) + c;
35         }
36         return h;
37 }
38
39 int
40 addarena(Arena *arena)
41 {
42         AHash *a;
43         u32int h;
44
45         h = hashstr(arena->name) & (AHashSize - 1);
46         a = MK(AHash);
47         if(a == nil)
48                 return -1;
49         a->arena = arena;
50         a->next = ahash[h];
51         ahash[h] = a;
52         return 0;
53 }
54
55 Arena*
56 findarena(char *name)
57 {
58         AHash *a;
59         u32int h;
60
61         h = hashstr(name) & (AHashSize - 1);
62         for(a = ahash[h]; a != nil; a = a->next)
63                 if(strcmp(a->arena->name, name) == 0)
64                         return a->arena;
65         return nil;
66 }
67
68 int
69 delarena(Arena *arena)
70 {
71         AHash *a, *last;
72         u32int h;
73
74         h = hashstr(arena->name) & (AHashSize - 1);
75         last = nil;
76         for(a = ahash[h]; a != nil; a = a->next){
77                 if(a->arena == arena){
78                         if(last != nil)
79                                 last->next = a->next;
80                         else
81                                 ahash[h] = a->next;
82                         free(a);
83                         return 0;
84                 }
85                 last = a;
86         }
87         return -1;
88 }
89
90 ArenaPart*
91 initarenapart(Part *part)
92 {
93         AMapN amn;
94         ArenaPart *ap;
95         ZBlock *b;
96         u32int i;
97         int ok;
98
99         b = alloczblock(HeadSize, 0, 0);
100         if(b == nil || readpart(part, PartBlank, b->data, HeadSize) < 0){
101                 seterr(EAdmin, "can't read arena partition header: %r");
102                 return nil;
103         }
104
105         ap = MKZ(ArenaPart);
106         if(ap == nil){
107                 freezblock(b);
108                 return nil;
109         }
110         ap->part = part;
111         ok = unpackarenapart(ap, b->data);
112         freezblock(b);
113         if(ok < 0){
114                 freearenapart(ap, 0);
115                 return nil;
116         }
117
118         ap->tabbase = (PartBlank + HeadSize + ap->blocksize - 1) & ~(ap->blocksize - 1);
119         if(ap->version != ArenaPartVersion){
120                 seterr(ECorrupt, "unknown arena partition version %d", ap->version);
121                 freearenapart(ap, 0);
122                 return nil;
123         }
124         if(ap->blocksize & (ap->blocksize - 1)){
125                 seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", ap->blocksize);
126                 freearenapart(ap, 0);
127                 return nil;
128         }
129         if(ap->tabbase >= ap->arenabase){
130                 seterr(ECorrupt, "arena partition table overlaps with arena storage");
131                 freearenapart(ap, 0);
132                 return nil;
133         }
134         ap->tabsize = ap->arenabase - ap->tabbase;
135         partblocksize(part, ap->blocksize);
136         ap->size = ap->part->size & ~(u64int)(ap->blocksize - 1);
137
138         if(readarenamap(&amn, part, ap->tabbase, ap->tabsize) < 0){
139                 freearenapart(ap, 0);
140                 return nil;
141         }
142         ap->narenas = amn.n;
143         ap->map = amn.map;
144         if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0){
145                 freearenapart(ap, 0);
146                 return nil;
147         }
148
149         ap->arenas = MKNZ(Arena*, ap->narenas);
150         for(i = 0; i < ap->narenas; i++){
151                 debugarena = i;
152                 ap->arenas[i] = initarena(part, ap->map[i].start, ap->map[i].stop - ap->map[i].start, ap->blocksize);
153                 if(ap->arenas[i] == nil){
154                         seterr(ECorrupt, "%s: %r", ap->map[i].name);
155                         freearenapart(ap, 1);
156                         return nil;
157                 }
158                 if(namecmp(ap->map[i].name, ap->arenas[i]->name) != 0){
159                         seterr(ECorrupt, "arena name mismatches with expected name: %s vs. %s",
160                                 ap->map[i].name, ap->arenas[i]->name);
161                         freearenapart(ap, 1);
162                         return nil;
163                 }
164                 if(findarena(ap->arenas[i]->name)){
165                         seterr(ECorrupt, "duplicate arena name %s in %s",
166                                 ap->map[i].name, ap->part->name);
167                         freearenapart(ap, 1);
168                         return nil;
169                 }
170         }
171
172         for(i = 0; i < ap->narenas; i++) {
173                 debugarena = i;
174                 addarena(ap->arenas[i]);
175         }
176         debugarena = -1;
177
178         return ap;
179 }
180
181 ArenaPart*
182 newarenapart(Part *part, u32int blocksize, u32int tabsize)
183 {
184         ArenaPart *ap;
185
186         if(blocksize & (blocksize - 1)){
187                 seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", blocksize);
188                 return nil;
189         }
190         ap = MKZ(ArenaPart);
191         if(ap == nil)
192                 return nil;
193
194         ap->version = ArenaPartVersion;
195         ap->part = part;
196         ap->blocksize = blocksize;
197         partblocksize(part, blocksize);
198         ap->size = part->size & ~(u64int)(blocksize - 1);
199         ap->tabbase = (PartBlank + HeadSize + blocksize - 1) & ~(blocksize - 1);
200         ap->arenabase = (ap->tabbase + tabsize + blocksize - 1) & ~(blocksize - 1);
201         ap->tabsize = ap->arenabase - ap->tabbase;
202         ap->narenas = 0;
203
204         if(wbarenapart(ap) < 0){
205                 freearenapart(ap, 0);
206                 return nil;
207         }
208
209         return ap;
210 }
211
212 int
213 wbarenapart(ArenaPart *ap)
214 {
215         ZBlock *b;
216
217         if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0)
218                 return -1;
219         b = alloczblock(HeadSize, 1, 0);
220         if(b == nil)
221 /* ZZZ set error message? */
222                 return -1;
223
224         if(packarenapart(ap, b->data) < 0){
225                 seterr(ECorrupt, "can't make arena partition header: %r");
226                 freezblock(b);
227                 return -1;
228         }
229         if(writepart(ap->part, PartBlank, b->data, HeadSize) < 0 ||
230            flushpart(ap->part) < 0){
231                 seterr(EAdmin, "can't write arena partition header: %r");
232                 freezblock(b);
233                 return -1;
234         }
235         freezblock(b);
236
237         return wbarenamap(ap->map, ap->narenas, ap->part, ap->tabbase, ap->tabsize);
238 }
239
240 void
241 freearenapart(ArenaPart *ap, int freearenas)
242 {
243         int i;
244
245         if(ap == nil)
246                 return;
247         if(freearenas){
248                 for(i = 0; i < ap->narenas; i++){
249                         if(ap->arenas[i] == nil)
250                                 continue;
251                         delarena(ap->arenas[i]);
252                         freearena(ap->arenas[i]);
253                 }
254         }
255         free(ap->map);
256         free(ap->arenas);
257         free(ap);
258 }
259
260 int
261 okamap(AMap *am, int n, u64int start, u64int stop, char *what)
262 {
263         u64int last;
264         u32int i;
265
266         last = start;
267         for(i = 0; i < n; i++){
268                 if(am[i].start < last){
269                         if(i == 0)
270                                 seterr(ECorrupt, "invalid start address in %s", what);
271                         else
272                                 seterr(ECorrupt, "overlapping ranges in %s", what);
273                         return -1;
274                 }
275                 if(am[i].stop < am[i].start){
276                         seterr(ECorrupt, "invalid range in %s", what);
277                         return -1;
278                 }
279                 last = am[i].stop;
280         }
281         if(last > stop){
282                 seterr(ECorrupt, "invalid ending address in %s", what);
283                 return -1;
284         }
285         return 0;
286 }
287
288 int
289 maparenas(AMap *am, Arena **arenas, int n, char *what)
290 {
291         u32int i;
292
293         for(i = 0; i < n; i++){
294                 arenas[i] = findarena(am[i].name);
295                 if(arenas[i] == nil){
296                         seterr(EAdmin, "can't find arena '%s' for '%s'\n", am[i].name, what);
297                         return -1;
298                 }
299         }
300         return 0;
301 }
302
303 int
304 readarenamap(AMapN *amn, Part *part, u64int base, u32int size)
305 {
306         IFile f;
307         u32int ok;
308
309         if(partifile(&f, part, base, size) < 0)
310                 return -1;
311         ok = parseamap(&f, amn);
312         freeifile(&f);
313         return ok;
314 }
315
316 int
317 wbarenamap(AMap *am, int n, Part *part, u64int base, u64int size)
318 {
319         Fmt f;
320         ZBlock *b;
321
322         b = alloczblock(size, 1, part->blocksize);
323         if(b == nil)
324                 return -1;
325
326         fmtzbinit(&f, b);
327
328         if(outputamap(&f, am, n) < 0){
329                 seterr(ECorrupt, "arena set size too small");
330                 freezblock(b);
331                 return -1;
332         }
333         if(writepart(part, base, b->data, size) < 0 || flushpart(part) < 0){
334                 seterr(EAdmin, "can't write arena set: %r");
335                 freezblock(b);
336                 return -1;
337         }
338         freezblock(b);
339         return 0;
340 }
341
342 /*
343  * amap: n '\n' amapelem * n
344  * n: u32int
345  * amapelem: name '\t' astart '\t' astop '\n'
346  * astart, astop: u64int
347  */
348 int
349 parseamap(IFile *f, AMapN *amn)
350 {
351         AMap *am;
352         u64int v64;
353         u32int v;
354         char *s, *t, *flds[4];
355         int i, n;
356
357         /*
358          * arenas
359          */
360         if(ifileu32int(f, &v) < 0){
361                 seterr(ECorrupt, "syntax error: bad number of elements in %s", f->name);
362                 return -1;
363         }
364         n = v;
365         if(n > MaxAMap){
366                 seterr(ECorrupt, "illegal number of elements %d in %s",
367                         n, f->name);
368                 return -1;
369         }
370         am = MKNZ(AMap, n);
371         if(am == nil){
372                 fprint(2, "out of memory\n");
373                 return -1;
374         }
375         for(i = 0; i < n; i++){
376                 s = ifileline(f);
377                 if(s)
378                         t = estrdup(s);
379                 else
380                         t = nil;
381                 if(s == nil || getfields(s, flds, 4, 0, "\t") != 3){
382                         fprint(2, "early eof after %d of %d, %s:#%d: %s\n", i, n, f->name, f->pos, t);
383                         free(t);
384                         return -1;
385                 }
386                 free(t);
387                 if(nameok(flds[0]) < 0)
388                         return -1;
389                 namecp(am[i].name, flds[0]);
390                 if(stru64int(flds[1], &v64) < 0){
391                         seterr(ECorrupt, "syntax error: bad arena base address in %s", f->name);
392                         free(am);
393                         return -1;
394                 }
395                 am[i].start = v64;
396                 if(stru64int(flds[2], &v64) < 0){
397                         seterr(ECorrupt, "syntax error: bad arena size in %s", f->name);
398                         free(am);
399                         return -1;
400                 }
401                 am[i].stop = v64;
402         }
403
404         amn->map = am;
405         amn->n = n;
406         return 0;
407 }
408
409 int
410 outputamap(Fmt *f, AMap *am, int n)
411 {
412         int i;
413
414         if(fmtprint(f, "%ud\n", n) < 0)
415                 return -1;
416         for(i = 0; i < n; i++)
417                 if(fmtprint(f, "%s\t%llud\t%llud\n", am[i].name, am[i].start, am[i].stop) < 0)
418                         return -1;
419         return 0;
420 }