ref: f31b4ce3b34f7191f7cfdae7b3d88e8e27e6b179
dir: /arena.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "neoventi.h"
int
arenarepair(VtArena *arena, uchar *ci, u64int addr)
{
uchar buf[30];
u16int tmp;
if(!vtarenaread(arena, addr, buf, 30)){
werrstr("arenarepair: %r");
return 0;
}
if(U32GET(buf) != arena->clumpmagic){
werrstr("arenarepair: magic is incorrect. If this block was not written by old-venti, you may have a problem.");
return 0;
}
// Update the clumpinfo, just in case.
ci[0] = 1;
U16PUT(ci + 1, tmp);
U16PUT(ci + 3, U16GET(buf + 7));
return 1;
}
int
vtarenasync(VtArena *arena)
{
// First, check if the directory and the data log are in sync
fprint(2, "skipping arena sync, logic needs rethought...\n");
return 1;
usize n, m, corruptchain;
char *buf, *ci;
u32int block, perblock, off;
u64int addr, goodaddr;
int good;
n = arena->arenastats.clumps;
corruptchain = 0;
fprint(2, "clumps: %d, %d\n", n, arena->indexstats.clumps);
if(n == arena->indexstats.clumps)
return 1;
buf = nil;
perblock = arena->blocksize / ClumpInfoSize;
off = 0;
addr = 0;
for(m = 0; m < n; m += 1){
if(m % perblock == 0){
// Load next block
if(buf != nil)
cacheunlock(arena->index, block);
block = (arena->size / arena->blocksize) - 1 - (m / perblock);
buf = vtarenareadblock(arena, block);
if(buf == nil){
werrstr("vtarenasync: unable to read CIG: %r");
return 0;
}
off = 0;
}
off += ClumpInfoSize;
ci = &buf[off];
good = arenarepair(arena, (u8int*)ci, addr);
addr += (((u64int)(U16GET(ci + 1))) + 38);
if(!good){
fprint(2, "clump %d is broken, at address %llud: %r\n", m, addr);
corruptchain += 1;
// Skip. old venti creates corruption in some easy-to-repro cases
// (e.g. write, kill venti within a few seconds) and I don't need people
// complaining about it.
} else {
corruptchain = 0;
goodaddr = addr;
}
}
if(addr != goodaddr){
assert(corruptchain > 0);
fprint(2, "corruption detected: the last %d clumps are corrupt. Dropping them.\n"
"\taddr dropped from %llud to %llud\n",
corruptchain, addr, goodaddr);
addr = goodaddr;
arena->arenastats.clumps -= corruptchain;
}
if(arena->arenastats.used != addr){
fprint(2, "corrupt: found addr %d, expected %d", addr, arena->arenastats.used);
arena->arenastats.used = addr;
}
// TODO: we haven't updated indexstats->clumps, so this is safe, but we _do_
// need to be indexing these clumps.
vtarenawb(arena);
return 1;
}
int
vtarenawritedirectory(VtArena *arena, char score[20], u16int uncsize)
{
return 0;
}
int
vtarenawb(VtArena *arena)
{
char *buf, *p;
u32int blockindex, t;
int ret;
blockindex = arena->size / arena->blocksize;
// FIXME rebuild on vtarenareadblock
if(!cachelookup(&buf, arena->index, blockindex)){
if(pread(arena->fd, buf, arena->blocksize, arena->base + arena->size) != arena->blocksize)
sysfatal("failed to pread");
}
p = buf + 8 + NameSize;
// Only support split stats
U32PUT(p, arena->indexstats.clumps);
// If it wasn't already using split arenastats and index stats, make it so.
// If it wasn't, that space should be clear.
p[37] = 1;
U32PUT(p + 38, arena->arenastats.clumps);
U64PUT(p + 46, arena->arenastats.used, t);
p[62] = arena->arenastats.sealed;
ret = pwrite(arena->fd, buf, arena->blocksize, arena->base + arena->size);
cacheunlock(arena->index, blockindex);
if(ret != arena->blocksize){
werrstr("writeback failed: %r");
return 0;
}
return 1;
}