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 }