URI: 
       tarenas.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR 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->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 }