Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
5 typedef struct AHash AHash;
7 /*
8 * hash table for finding arena's based on their names.
9 */
10 struct AHash
11 {
12 AHash *next;
13 Arena *arena;
14 };
16 enum
17 {
18 AHashSize = 512
19 };
21 static AHash *ahash[AHashSize];
23 static u32int
24 hashstr(char *s)
25 {
26 u32int h;
27 int c;
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 }
39 int
40 addarena(Arena *arena)
41 {
42 AHash *a;
43 u32int h;
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 }
55 Arena*
56 findarena(char *name)
57 {
58 AHash *a;
59 u32int h;
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 }
68 int
69 delarena(Arena *arena)
70 {
71 AHash *a, *last;
72 u32int h;
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 }
90 ArenaPart*
91 initarenapart(Part *part)
92 {
93 AMapN amn;
94 ArenaPart *ap;
95 ZBlock *b;
96 u32int i;
97 int ok;
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;
105 ap = MKZ(ArenaPart);
106 if(ap == nil){
107 freezblock(b);
108 return nil;
110 ap->part = part;
111 ok = unpackarenapart(ap, b->data);
112 freezblock(b);
113 if(ok < 0){
114 freearenapart(ap, 0);
115 return nil;
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;
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;
129 if(ap->tabbase >= ap->arenabase){
130 seterr(ECorrupt, "arena partition table overlaps with arena storage");
131 freearenapart(ap, 0);
132 return nil;
134 ap->tabsize = ap->arenabase - ap->tabbase;
135 partblocksize(part, ap->blocksize);
136 ap->size = ap->part->size & ~(u64int)(ap->blocksize - 1);
138 if(readarenamap(&amn, part, ap->tabbase, ap->tabsize) < 0){
139 freearenapart(ap, 0);
140 return nil;
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;
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;
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;
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;
172 for(i = 0; i < ap->narenas; i++) {
173 debugarena = i;
174 addarena(ap->arenas[i]);
176 debugarena = -1;
178 return ap;
181 ArenaPart*
182 newarenapart(Part *part, u32int blocksize, u32int tabsize)
184 ArenaPart *ap;
186 if(blocksize & (blocksize - 1)){
187 seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", blocksize);
188 return nil;
190 ap = MKZ(ArenaPart);
191 if(ap == nil)
192 return nil;
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;
204 if(wbarenapart(ap) < 0){
205 freearenapart(ap, 0);
206 return nil;
209 return ap;
212 int
213 wbarenapart(ArenaPart *ap)
215 ZBlock *b;
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;
224 if(packarenapart(ap, b->data) < 0){
225 seterr(ECorrupt, "can't make arena partition header: %r");
226 freezblock(b);
227 return -1;
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;
235 freezblock(b);
237 return wbarenamap(ap->map, ap->narenas, ap->part, ap->tabbase, ap->tabsize);
240 void
241 freearenapart(ArenaPart *ap, int freearenas)
243 int i;
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]);
255 free(ap->map);
256 free(ap->arenas);
257 free(ap);
260 int
261 okamap(AMap *am, int n, u64int start, u64int stop, char *what)
263 u64int last;
264 u32int i;
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;
275 if(am[i].stop < am[i].start){
276 seterr(ECorrupt, "invalid range in %s", what);
277 return -1;
279 last = am[i].stop;
281 if(last > stop){
282 seterr(ECorrupt, "invalid ending address in %s", what);
283 return -1;
285 return 0;
288 int
289 maparenas(AMap *am, Arena **arenas, int n, char *what)
291 u32int i;
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;
300 return 0;
303 int
304 readarenamap(AMapN *amn, Part *part, u64int base, u32int size)
306 IFile f;
307 u32int ok;
309 if(partifile(&f, part, base, size) < 0)
310 return -1;
311 ok = parseamap(&f, amn);
312 freeifile(&f);
313 return ok;
316 int
317 wbarenamap(AMap *am, int n, Part *part, u64int base, u64int size)
319 Fmt f;
320 ZBlock *b;
322 b = alloczblock(size, 1, part->blocksize);
323 if(b == nil)
324 return -1;
326 fmtzbinit(&f, b);
328 if(outputamap(&f, am, n) < 0){
329 seterr(ECorrupt, "arena set size too small");
330 freezblock(b);
331 return -1;
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;
338 freezblock(b);
339 return 0;
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)
351 AMap *am;
352 u64int v64;
353 u32int v;
354 char *s, *t, *flds[4];
355 int i, n;
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;
364 n = v;
365 if(n > MaxAMap){
366 seterr(ECorrupt, "illegal number of elements %d in %s",
367 n, f->name);
368 return -1;
370 am = MKNZ(AMap, n);
371 if(am == nil){
372 fprint(2, "out of memory\n");
373 return -1;
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;
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;
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;
401 am[i].stop = v64;
404 amn->map = am;
405 amn->n = n;
406 return 0;
409 int
410 outputamap(Fmt *f, AMap *am, int n)
412 int i;
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;