plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

arenas.c (8107B)


      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 }