/* * read the arena header and trailer blocks from disk */ static int loadarena(Arena *arena) { ArenaHead head; ZBlock *b; b = alloczblock(arena->blocksize, 0, arena->part->blocksize); if(b == nil) return -1; if(readpart(arena->part, arena->base + arena->size, b->data, arena->blocksize) < 0){ freezblock(b); return -1; } if(unpackarena(arena, b->data) < 0){ freezblock(b); return -1; } if(arena->version != ArenaVersion4 && arena->version != ArenaVersion5){ seterr(EAdmin, "unknown arena version %d", arena->version); freezblock(b); return -1; } scorecp(arena->score, &b->data[arena->blocksize - VtScoreSize]); if(readpart(arena->part, arena->base - arena->blocksize, b->data, arena->blocksize) < 0){ logerr(EAdmin, "can't read arena header: %r"); freezblock(b); return 0; } if(unpackarenahead(&head, b->data) < 0) logerr(ECorrupt, "corrupted arena header: %r"); else if(namecmp(arena->name, head.name)!=0 || arena->clumpmagic != head.clumpmagic || arena->version != head.version || arena->blocksize != head.blocksize || arena->size + 2 * arena->blocksize != head.size){ if(namecmp(arena->name, head.name)!=0) logerr(ECorrupt, "arena tail name %s head %s", arena->name, head.name); else if(arena->clumpmagic != head.clumpmagic) logerr(ECorrupt, "arena %d tail clumpmagic 0x%lux head 0x%lux", debugarena, (uint32_t)arena->clumpmagic, (uint32_t)head.clumpmagic); else if(arena->version != head.version) logerr(ECorrupt, "arena tail version %d head version %d", arena->version, head.version); else if(arena->blocksize != head.blocksize) logerr(ECorrupt, "arena tail block size %d head %d", arena->blocksize, head.blocksize); else if(arena->size+2*arena->blocksize != head.size) logerr(ECorrupt, "arena tail size %lud head %lud", (uint32_t)arena->size+2*arena->blocksize, head.size); else logerr(ECorrupt, "arena header inconsistent with arena data"); } freezblock(b); return 0; }
/* * read in all of the arena's clump directory, * convert to IEntry format, and bucket sort based * on the first few bits. */ static uint32_t readarenainfo(IEBucks *ib, Arena *arena, uint64_t a, Bloom *b) { IEntry ie; ClumpInfo *ci, *cis; uint32_t clump; int i, n, ok, nskip; if(arena->memstats.clumps) fprint(2, "\tarena %s: %d entries\n", arena->name, arena->memstats.clumps); else fprint(2, "[%s] ", arena->name); cis = MKN(ClumpInfo, ClumpChunks); ok = 0; nskip = 0; memset(&ie, 0, sizeof(IEntry)); for(clump = 0; clump < arena->memstats.clumps; clump += n){ n = ClumpChunks; if(n > arena->memstats.clumps - clump) n = arena->memstats.clumps - clump; if(readclumpinfos(arena, clump, cis, n) != n){ seterr(EOk, "arena directory read failed: %r"); ok = -1; break; } for(i = 0; i < n; i++){ ci = &cis[i]; ie.ia.type = ci->type; ie.ia.size = ci->uncsize; ie.ia.addr = a; a += ci->size + ClumpSize; ie.ia.blocks = (ci->size + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog; scorecp(ie.score, ci->score); if(ci->type == VtCorruptType){ if(0) print("! %V %22lld %3d %5d %3d\n", ie.score, ie.ia.addr, ie.ia.type, ie.ia.size, ie.ia.blocks); nskip++; }else sprayientry(ib, &ie); markbloomfilter(b, ie.score); } } free(cis); if(ok < 0) return TWID32; return clump - nskip; }
/* * write the arena trailer block to the partition */ int wbarena(Arena *arena) { DBlock *b; int bad; if((b = getdblock(arena->part, arena->base + arena->size, OWRITE)) == nil){ logerr(EAdmin, "can't write arena trailer: %r"); return -1; } dirtydblock(b, DirtyArenaTrailer); bad = okarena(arena)<0 || packarena(arena, b->data)<0; scorecp(b->data + arena->blocksize - VtScoreSize, arena->score); putdblock(b); if(bad) return -1; return 0; }
int installentry(u8int *data, ulong len, u8int *score, uchar blocktype) { int ix, initial; datasha1(data, len, score); initial = ix = hashbits(score, hashb); //fprint(2, "installentry: ix %d, V %V, maps[].data %p\n", ix, score, maps[ix].data); while (maps[ix].data) { ix++; if (ix > maxmap) ix = 0; if (ix == initial) sysfatal("OOPS -- no more map slots"); } maps[ix].data = data; //fprint(2, "set map[%d] to %p\n", ix, mmventidata); maps[ix].len = len; scorecp(maps[ix].score, score); maps[ix].blocktype = blocktype; return ix; }
/* * load the clump info for group g into the index entries. */ int asumload(Arena *arena, int g, IEntry *entries, int nentries) { int i, base, limit; uint64_t addr; ClumpInfo ci; IEntry *ie; if(nentries < ArenaCIGSize){ fprint(2, "asking for too few entries\n"); return -1; } qlock(&arena->lock); if(arena->cig == nil) loadcig(arena); if(arena->cig == nil || arena->ncig == 0 || g >= arena->ncig){ qunlock(&arena->lock); return -1; } addr = 0; base = g*ArenaCIGSize; limit = base + ArenaCIGSize; if(base > arena->memstats.clumps) base = arena->memstats.clumps; ie = entries; for(i=base; i<limit; i++){ if(readclumpinfo(arena, i, &ci) < 0) break; if(ci.type != VtCorruptType){ scorecp(ie->score, ci.score); ie->ia.type = ci.type; ie->ia.size = ci.uncsize; ie->ia.blocks = (ci.size + ClumpSize + (1<<ABlockLog) - 1) >> ABlockLog; ie->ia.addr = addr; ie++; } addr += ClumpSize + ci.size; }
void sumarena(Arena *arena) { ZBlock *b; DigestState s; uint64_t a, e; uint32_t bs; int t; uint8_t score[VtScoreSize]; bs = MaxIoSize; if(bs < arena->blocksize) bs = arena->blocksize; /* * read & sum all blocks except the last one */ flushdcache(); memset(&s, 0, sizeof s); b = alloczblock(bs, 0, arena->part->blocksize); e = arena->base + arena->size; for(a = arena->base - arena->blocksize; a + arena->blocksize <= e; a += bs){ disksched(); while((t=arenasumsleeptime) == SleepForever){ sleep(1000); disksched(); } sleep(t); if(a + bs > e) bs = arena->blocksize; if(readpart(arena->part, a, b->data, bs) < 0) goto ReadErr; addstat(StatSumRead, 1); addstat(StatSumReadBytes, bs); sha1(b->data, bs, nil, &s); } /* * the last one is special, since it may already have the checksum included */ bs = arena->blocksize; if(readpart(arena->part, e, b->data, bs) < 0){ ReadErr: logerr(EOk, "sumarena can't sum %s, read at %lld failed: %r", arena->name, a); freezblock(b); return; } addstat(StatSumRead, 1); addstat(StatSumReadBytes, bs); sha1(b->data, bs-VtScoreSize, nil, &s); sha1(zeroscore, VtScoreSize, nil, &s); sha1(nil, 0, score, &s); /* * check for no checksum or the same */ if(scorecmp(score, &b->data[bs - VtScoreSize]) != 0 && scorecmp(zeroscore, &b->data[bs - VtScoreSize]) != 0) logerr(EOk, "overwriting mismatched checksums for arena=%s, found=%V calculated=%V", arena->name, &b->data[bs - VtScoreSize], score); freezblock(b); qlock(&arena->lock); scorecp(arena->score, score); wbarena(arena); qunlock(&arena->lock); }
static int diskarenapart(HConnect *c, char *disk, Part *p) { char *arenaname; ArenaPart ap; ArenaHead head; Arena arena; char *table; char *score; char *clump; uchar *blk; vlong start, end, off; char tbuf[60]; hprint(&c->hout, "<h1>arena partition %s</h1>\n", disk); if((table = readap(p, &ap)) == nil){ hprint(&c->hout, "%r\n"); goto out; } hprint(&c->hout, "<pre>\n"); hprint(&c->hout, "version=%d blocksize=%d base=%d\n", ap.version, ap.blocksize, ap.arenabase); hprint(&c->hout, "</pre>\n"); arenaname = hargstr(c, "arena", ""); if(arenaname[0] == 0){ diskarenatable(c, disk, table); goto out; } if(xfindarena(table, arenaname, &start, &end) < 0){ hprint(&c->hout, "no such arena %s\n", arenaname); goto out; } hprint(&c->hout, "<h2>arena %s</h2>\n", arenaname); hprint(&c->hout, "<pre>start=%#llx end=%#llx<pre>\n", start, end); if(end < start || end - start < HeadSize){ hprint(&c->hout, "bad size %#llx\n", end - start); goto out; } // read arena header, tail blk = vtmalloc(HeadSize); if(readpart(p, start, blk, HeadSize) != HeadSize){ hprint(&c->hout, "reading header: %r\n"); vtfree(blk); goto out; } if(unpackarenahead(&head, blk) < 0){ hprint(&c->hout, "corrupt arena header: %r\n"); // hhex(blk, HeadSize); vtfree(blk); goto out; } vtfree(blk); hprint(&c->hout, "head:\n<pre>\n"); hprint(&c->hout, "version=%d name=%s blocksize=%d size=%#llx clumpmagic=%#ux\n", head.version, head.name, head.blocksize, head.size, head.clumpmagic); hprint(&c->hout, "</pre><br><br>\n"); if(head.blocksize > MaxIoSize || head.blocksize >= end - start){ hprint(&c->hout, "corrupt block size %d\n", head.blocksize); goto out; } blk = vtmalloc(head.blocksize); if(readpart(p, end - head.blocksize, blk, head.blocksize) < 0){ hprint(&c->hout, "reading tail: %r\n"); vtfree(blk); goto out; } memset(&arena, 0, sizeof arena); arena.part = p; arena.blocksize = head.blocksize; arena.clumpmax = head.blocksize / ClumpInfoSize; arena.base = start + head.blocksize; arena.size = end - start - 2 * head.blocksize; if(unpackarena(&arena, blk) < 0){ vtfree(blk); goto out; } scorecp(arena.score, blk+head.blocksize - VtScoreSize); vtfree(blk); hprint(&c->hout, "tail:\n<pre>\n"); hprint(&c->hout, "version=%d name=%s\n", arena.version, arena.name); hprint(&c->hout, "ctime=%d %s\n", arena.ctime, fmttime(tbuf, arena.ctime)); hprint(&c->hout, "wtime=%d %s\n", arena.wtime, fmttime(tbuf, arena.wtime)); hprint(&c->hout, "clumpmagic=%#ux\n", arena.clumpmagic); hprint(&c->hout, "score %V\n", arena.score); hprint(&c->hout, "diskstats:\n"); hprint(&c->hout, "\tclumps=%,d cclumps=%,d used=%,lld uncsize=%,lld sealed=%d\n", arena.diskstats.clumps, arena.diskstats.cclumps, arena.diskstats.used, arena.diskstats.uncsize, arena.diskstats.sealed); hprint(&c->hout, "memstats:\n"); hprint(&c->hout, "\tclumps=%,d cclumps=%,d used=%,lld uncsize=%,lld sealed=%d\n", arena.memstats.clumps, arena.memstats.cclumps, arena.memstats.used, arena.memstats.uncsize, arena.memstats.sealed); if(arena.clumpmax == 0){ hprint(&c->hout, "bad clumpmax\n"); goto out; } score = hargstr(c, "score", ""); clump = hargstr(c, "clump", ""); if(clump[0]){ off = strtoull(clump, 0, 0); diskarenaclump(c, &arena, off, score[0] ? score : nil); }else if(score[0]){ diskarenaclump(c, &arena, -1, score); }else{ diskarenatoc(c, &arena); } out: free(table); return 0; }