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