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->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 }