5 typedef struct AHash AHash;
8 * hash table for finding arena's based on their names.
21 static AHash *ahash[AHashSize];
32 h += (c << 11) ^ (c >> 1);
34 h ^= (c << 14) + (c << 7) + (c << 4) + c;
40 addarena(Arena *arena)
45 h = hashstr(arena->name) & (AHashSize - 1);
61 h = hashstr(name) & (AHashSize - 1);
62 for(a = ahash[h]; a != nil; a = a->next)
63 if(strcmp(a->arena->name, name) == 0)
69 delarena(Arena *arena)
74 h = hashstr(arena->name) & (AHashSize - 1);
76 for(a = ahash[h]; a != nil; a = a->next){
77 if(a->arena == arena){
91 initarenapart(Part *part)
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");
111 ok = unpackarenapart(ap, b->data);
114 freearenapart(ap, 0);
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);
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);
129 if(ap->tabbase >= ap->arenabase){
130 seterr(ECorrupt, "arena partition table overlaps with arena storage");
131 freearenapart(ap, 0);
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);
144 if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0){
145 freearenapart(ap, 0);
149 ap->arenas = MKNZ(Arena*, ap->narenas);
150 for(i = 0; i < ap->narenas; i++){
151 ap->arenas[i] = initarena(part, ap->map[i].start, ap->map[i].stop - ap->map[i].start, ap->blocksize);
152 if(ap->arenas[i] == nil){
153 seterr(ECorrupt, "%s: %r", ap->map[i].name);
154 freearenapart(ap, 1);
157 if(namecmp(ap->map[i].name, ap->arenas[i]->name) != 0){
158 seterr(ECorrupt, "arena name mismatches with expected name: %s vs. %s",
159 ap->map[i].name, ap->arenas[i]->name);
160 freearenapart(ap, 1);
163 if(findarena(ap->arenas[i]->name)){
164 seterr(ECorrupt, "duplicate arena name %s in %s",
165 ap->map[i].name, ap->part->name);
166 freearenapart(ap, 1);
171 for(i = 0; i < ap->narenas; i++)
172 addarena(ap->arenas[i]);
178 newarenapart(Part *part, u32int blocksize, u32int tabsize)
182 if(blocksize & (blocksize - 1)){
183 seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", blocksize);
190 ap->version = ArenaPartVersion;
192 ap->blocksize = blocksize;
193 partblocksize(part, blocksize);
194 ap->size = part->size & ~(u64int)(blocksize - 1);
195 ap->tabbase = (PartBlank + HeadSize + blocksize - 1) & ~(blocksize - 1);
196 ap->arenabase = (ap->tabbase + tabsize + blocksize - 1) & ~(blocksize - 1);
197 ap->tabsize = ap->arenabase - ap->tabbase;
200 if(wbarenapart(ap) < 0){
201 freearenapart(ap, 0);
209 wbarenapart(ArenaPart *ap)
213 if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0)
215 b = alloczblock(HeadSize, 1, 0);
217 /* ZZZ set error message? */
220 if(packarenapart(ap, b->data) < 0){
221 seterr(ECorrupt, "can't make arena partition header: %r");
225 if(writepart(ap->part, PartBlank, b->data, HeadSize) < 0 ||
226 flushpart(ap->part) < 0){
227 seterr(EAdmin, "can't write arena partition header: %r");
233 return wbarenamap(ap->map, ap->narenas, ap->part, ap->tabbase, ap->tabsize);
237 freearenapart(ArenaPart *ap, int freearenas)
244 for(i = 0; i < ap->narenas; i++){
245 if(ap->arenas[i] == nil)
247 delarena(ap->arenas[i]);
248 freearena(ap->arenas[i]);
257 okamap(AMap *am, int n, u64int start, u64int stop, char *what)
263 for(i = 0; i < n; i++){
264 if(am[i].start < last){
266 seterr(ECorrupt, "invalid start address in %s", what);
268 seterr(ECorrupt, "overlapping ranges in %s", what);
271 if(am[i].stop < am[i].start){
272 seterr(ECorrupt, "invalid range in %s", what);
278 seterr(ECorrupt, "invalid ending address in %s", what);
285 maparenas(AMap *am, Arena **arenas, int n, char *what)
289 for(i = 0; i < n; i++){
290 arenas[i] = findarena(am[i].name);
291 if(arenas[i] == nil){
292 seterr(EAdmin, "can't find arena '%s' for '%s'\n", am[i].name, what);
300 readarenamap(AMapN *amn, Part *part, u64int base, u32int size)
305 if(partifile(&f, part, base, size) < 0)
307 ok = parseamap(&f, amn);
313 wbarenamap(AMap *am, int n, Part *part, u64int base, u64int size)
318 b = alloczblock(size, 1, part->blocksize);
324 if(outputamap(&f, am, n) < 0){
325 seterr(ECorrupt, "arena set size too small");
329 if(writepart(part, base, b->data, size) < 0 || flushpart(part) < 0){
330 seterr(EAdmin, "can't write arena set: %r");
339 * amap: n '\n' amapelem * n
341 * amapelem: name '\t' astart '\t' astop '\n'
342 * astart, astop: u64int
345 parseamap(IFile *f, AMapN *amn)
350 char *s, *t, *flds[4];
356 if(ifileu32int(f, &v) < 0){
357 seterr(ECorrupt, "syntax error: bad number of elements in %s", f->name);
362 seterr(ECorrupt, "illegal number of elements in %s", f->name);
367 fprint(2, "out of memory\n");
370 for(i = 0; i < n; i++){
376 if(s == nil || getfields(s, flds, 4, 0, "\t") != 3){
377 fprint(2, "early eof after %d of %d, %s:#%d: %s\n", i, n, f->name, f->pos, t);
382 if(nameok(flds[0]) < 0)
384 namecp(am[i].name, flds[0]);
385 if(stru64int(flds[1], &v64) < 0){
386 seterr(ECorrupt, "syntax error: bad arena base address in %s", f->name);
391 if(stru64int(flds[2], &v64) < 0){
392 seterr(ECorrupt, "syntax error: bad arena size in %s", f->name);
405 outputamap(Fmt *f, AMap *am, int n)
409 if(fmtprint(f, "%ud\n", n) < 0)
411 for(i = 0; i < n; i++)
412 if(fmtprint(f, "%s\t%llud\t%llud\n", am[i].name, am[i].start, am[i].stop) < 0)