tarenas.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tarenas.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-… | |
119 if(ap->version != ArenaPartVersion){ | |
120 seterr(ECorrupt, "unknown arena partition version %d", a… | |
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… | |
126 freearenapart(ap, 0); | |
127 return nil; | |
128 } | |
129 if(ap->tabbase >= ap->arenabase){ | |
130 seterr(ECorrupt, "arena partition table overlaps with ar… | |
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 … | |
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->ma… | |
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 exp… | |
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… | |
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) & ~(blocksi… | |
200 ap->arenabase = (ap->tabbase + tabsize + blocksize - 1) & ~(bloc… | |
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 … | |
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, a… | |
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 … | |
271 else | |
272 seterr(ECorrupt, "overlapping ranges in … | |
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… | |
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) <… | |
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 i… | |
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\… | |
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 a… | |
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 i… | |
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].s… | |
418 return -1; | |
419 return 0; | |
420 } |