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
hashstr(char * s)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
addarena(Arena * arena)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*
findarena(char * name)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
delarena(Arena * arena)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*
initarenapart(Part * part)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*
newarenapart(Part * part,u32int blocksize,u32int tabsize)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
wbarenapart(ArenaPart * ap)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
freearenapart(ArenaPart * ap,int freearenas)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
okamap(AMap * am,int n,u64int start,u64int stop,char * what)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
maparenas(AMap * am,Arena ** arenas,int n,char * what)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
readarenamap(AMapN * amn,Part * part,u64int base,u32int size)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
wbarenamap(AMap * am,int n,Part * part,u64int base,u64int size)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
parseamap(IFile * f,AMapN * amn)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
outputamap(Fmt * f,AMap * am,int n)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 }
421