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