1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "local.h"
437da2899SCharles.Forsyth #include "fcall.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth typedef struct PathEnt {
737da2899SCharles.Forsyth ulong path;
837da2899SCharles.Forsyth long block;
937da2899SCharles.Forsyth } PathEnt;
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsyth typedef struct GenInfo {
1237da2899SCharles.Forsyth long start;
1337da2899SCharles.Forsyth long end;
1437da2899SCharles.Forsyth int gaps;
1537da2899SCharles.Forsyth } GenInfo;
1637da2899SCharles.Forsyth
1737da2899SCharles.Forsyth static int
dataorder(ulong p1,ulong p2)1837da2899SCharles.Forsyth dataorder(ulong p1, ulong p2)
1937da2899SCharles.Forsyth {
2037da2899SCharles.Forsyth int o;
2137da2899SCharles.Forsyth o = dataseqof(p1) - dataseqof(p2);
2237da2899SCharles.Forsyth if(o != 0)
2337da2899SCharles.Forsyth return o;
2437da2899SCharles.Forsyth return copygenof(p1) - copygenof(p2);
2537da2899SCharles.Forsyth }
2637da2899SCharles.Forsyth
2737da2899SCharles.Forsyth static int
logorder(ulong p1,ulong p2)2837da2899SCharles.Forsyth logorder(ulong p1, ulong p2)
2937da2899SCharles.Forsyth {
3037da2899SCharles.Forsyth int o;
3137da2899SCharles.Forsyth o = loggenof(p1) - loggenof(p2);
3237da2899SCharles.Forsyth if(o != 0)
3337da2899SCharles.Forsyth return o;
3437da2899SCharles.Forsyth o = logseqof(p1) - logseqof(p2);
3537da2899SCharles.Forsyth if(o != 0)
3637da2899SCharles.Forsyth return o;
3737da2899SCharles.Forsyth return copygenof(p1) - copygenof(p2);
3837da2899SCharles.Forsyth }
3937da2899SCharles.Forsyth
4037da2899SCharles.Forsyth static void
insert(PathEnt * pathmap,long entries,ulong path,long block,int (* order)(ulong p1,ulong p2))4137da2899SCharles.Forsyth insert(PathEnt *pathmap, long entries, ulong path, long block, int (*order)(ulong p1, ulong p2))
4237da2899SCharles.Forsyth {
4337da2899SCharles.Forsyth long i;
4437da2899SCharles.Forsyth for(i = 0; i < entries; i++)
4537da2899SCharles.Forsyth if((*order)(path, pathmap[i].path) < 0)
4637da2899SCharles.Forsyth break;
4737da2899SCharles.Forsyth memmove(&pathmap[i + 1], &pathmap[i], (entries - i) * sizeof(PathEnt));
4837da2899SCharles.Forsyth pathmap[i].path = path;
4937da2899SCharles.Forsyth pathmap[i].block = block;
5037da2899SCharles.Forsyth }
5137da2899SCharles.Forsyth
5237da2899SCharles.Forsyth static void
populate(LogSegment * seg,int gen,long unsweptblockindex,long curblockindex,PathEnt * pathent)5337da2899SCharles.Forsyth populate(LogSegment *seg, int gen, long unsweptblockindex, long curblockindex, PathEnt *pathent)
5437da2899SCharles.Forsyth {
5537da2899SCharles.Forsyth long i;
5637da2899SCharles.Forsyth seg->gen = gen;
5737da2899SCharles.Forsyth seg->unsweptblockindex = unsweptblockindex;
5837da2899SCharles.Forsyth seg->curblockindex = curblockindex;
5937da2899SCharles.Forsyth for(i = unsweptblockindex; i <= curblockindex; i++) {
6037da2899SCharles.Forsyth // print("populate %d: %d\n", i, pathent[i - unsweptblockindex].block);
6137da2899SCharles.Forsyth seg->blockmap[i] = pathent->block;
6237da2899SCharles.Forsyth pathent++;
6337da2899SCharles.Forsyth }
6437da2899SCharles.Forsyth }
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsyth static int
dataduplicate(PathEnt * p1,PathEnt * p2)6737da2899SCharles.Forsyth dataduplicate(PathEnt *p1, PathEnt *p2)
6837da2899SCharles.Forsyth {
6937da2899SCharles.Forsyth return dataseqof(p2->path) == dataseqof(p1->path)
7037da2899SCharles.Forsyth && copygenof(p2->path) == copygensucc(copygenof(p1->path));
7137da2899SCharles.Forsyth }
7237da2899SCharles.Forsyth
7337da2899SCharles.Forsyth static char *
eliminateduplicates(LogfsServer * server,char * name,PathEnt * map,long * entriesp)7437da2899SCharles.Forsyth eliminateduplicates(LogfsServer *server, char *name, PathEnt *map, long *entriesp)
7537da2899SCharles.Forsyth {
7637da2899SCharles.Forsyth long i;
7737da2899SCharles.Forsyth long k = *entriesp;
7837da2899SCharles.Forsyth for(i = 0; i < k;) {
7937da2899SCharles.Forsyth PathEnt *prev = &map[i - 1];
8037da2899SCharles.Forsyth PathEnt *this = &map[i];
8137da2899SCharles.Forsyth if(i > 0 && dataduplicate(prev, this)) {
8237da2899SCharles.Forsyth print("%s duplicate detected\n", name);
8337da2899SCharles.Forsyth if(i + 1 < k && dataduplicate(this, &map[i + 1]))
8437da2899SCharles.Forsyth return "three or more copies of same block";
8537da2899SCharles.Forsyth /*
8637da2899SCharles.Forsyth * check that the copy generations are in order
8737da2899SCharles.Forsyth */
8837da2899SCharles.Forsyth if(copygensucc(copygenof(this->path)) == copygenof(prev->path)) {
8937da2899SCharles.Forsyth PathEnt m;
9037da2899SCharles.Forsyth /*
9137da2899SCharles.Forsyth * previous entry is newer, so swap
9237da2899SCharles.Forsyth */
9337da2899SCharles.Forsyth m = *this;
9437da2899SCharles.Forsyth *this = *prev;
9537da2899SCharles.Forsyth *prev = m;
9637da2899SCharles.Forsyth }
9737da2899SCharles.Forsyth else if(copygensucc(copygenof(prev->path)) != copygenof(this->path))
9837da2899SCharles.Forsyth return "duplicate blocks but copy generations not sequential";
9937da2899SCharles.Forsyth /* erase and format previous block */
10037da2899SCharles.Forsyth logfsbootfettleblock(server->lb, prev->block, LogfsTnone, ~0, nil);
10137da2899SCharles.Forsyth /*
10237da2899SCharles.Forsyth * remove entry from table
10337da2899SCharles.Forsyth */
10437da2899SCharles.Forsyth memmove(prev, this, sizeof(PathEnt) * (k - i));
10537da2899SCharles.Forsyth k--;
10637da2899SCharles.Forsyth continue;
10737da2899SCharles.Forsyth }
10837da2899SCharles.Forsyth i++;
10937da2899SCharles.Forsyth }
11037da2899SCharles.Forsyth *entriesp = k;
11137da2899SCharles.Forsyth return nil;
11237da2899SCharles.Forsyth }
11337da2899SCharles.Forsyth
11437da2899SCharles.Forsyth char *
logfsscan(LogfsServer * server)11537da2899SCharles.Forsyth logfsscan(LogfsServer *server)
11637da2899SCharles.Forsyth {
11737da2899SCharles.Forsyth LogfsLowLevel *ll = server->ll;
11837da2899SCharles.Forsyth long b;
11937da2899SCharles.Forsyth long i;
12037da2899SCharles.Forsyth long logfound = 0;
12137da2899SCharles.Forsyth long datafound = 0;
12237da2899SCharles.Forsyth PathEnt *logpathmap, *datapathmap;
12337da2899SCharles.Forsyth GenInfo geninfo[1 << L2LogSweeps];
12437da2899SCharles.Forsyth int gensfound, lastgenfound;
12537da2899SCharles.Forsyth int g0, g1;
12637da2899SCharles.Forsyth char *errmsg;
12737da2899SCharles.Forsyth //print("logfsscan %ld blocks\n", server->ll->blocks);
12837da2899SCharles.Forsyth logpathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
12937da2899SCharles.Forsyth datapathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
13037da2899SCharles.Forsyth if(logpathmap == nil || datapathmap == nil)
13137da2899SCharles.Forsyth return Enomem;
13237da2899SCharles.Forsyth for(b = 0; b < ll->blocks; b++) {
13337da2899SCharles.Forsyth short tag = (*ll->getblocktag)(ll, b);
13437da2899SCharles.Forsyth ulong path = (*ll->getblockpath)(ll, b);
13537da2899SCharles.Forsyth //print("scan: %ld: %d %ld\n", b, tag, path);
13637da2899SCharles.Forsyth switch(tag) {
13737da2899SCharles.Forsyth case LogfsTlog:
13837da2899SCharles.Forsyth insert(logpathmap, logfound++, path, b, logorder);
13937da2899SCharles.Forsyth break;
14037da2899SCharles.Forsyth case LogfsTdata:
14137da2899SCharles.Forsyth insert(datapathmap, datafound++, path, b, dataorder);
14237da2899SCharles.Forsyth break;
14337da2899SCharles.Forsyth }
14437da2899SCharles.Forsyth }
14537da2899SCharles.Forsyth if(server->trace > 1) {
14637da2899SCharles.Forsyth for(i = 0; i < logfound; i++)
14737da2899SCharles.Forsyth print("log gen %lud seq %lud copygen %lud block %ld\n",
14837da2899SCharles.Forsyth loggenof(logpathmap[i].path), logseqof(logpathmap[i].path), copygenof(datapathmap[i].path), logpathmap[i].block);
14937da2899SCharles.Forsyth for(i = 0; i < datafound; i++)
15037da2899SCharles.Forsyth print("data seq %lud copygen %lud block %ld\n",
15137da2899SCharles.Forsyth dataseqof(datapathmap[i].path), copygenof(datapathmap[i].path), datapathmap[i].block);
15237da2899SCharles.Forsyth }
15337da2899SCharles.Forsyth /*
15437da2899SCharles.Forsyth * sort out data first
15537da2899SCharles.Forsyth */
15637da2899SCharles.Forsyth errmsg = eliminateduplicates(server, "data", datapathmap, &datafound);
15737da2899SCharles.Forsyth if(errmsg)
15837da2899SCharles.Forsyth goto fail;
15937da2899SCharles.Forsyth /*
16037da2899SCharles.Forsyth * data blocks guaranteed to be ordered
16137da2899SCharles.Forsyth */
16237da2899SCharles.Forsyth if(datafound)
16337da2899SCharles.Forsyth server->ndatablocks = dataseqof(datapathmap[datafound - 1].path) + 1;
16437da2899SCharles.Forsyth else
16537da2899SCharles.Forsyth server->ndatablocks = 0;
16637da2899SCharles.Forsyth for(i = 0; i < server->ndatablocks; i++)
16737da2899SCharles.Forsyth server->datablock[i].block = -1;
16837da2899SCharles.Forsyth for(i = 0; i < datafound; i++) {
16937da2899SCharles.Forsyth long j;
17037da2899SCharles.Forsyth j = dataseqof(datapathmap[i].path);
17137da2899SCharles.Forsyth server->datablock[j].path = datapathmap[i].path;
17237da2899SCharles.Forsyth server->datablock[j].block = datapathmap[i].block;
17337da2899SCharles.Forsyth /*
17437da2899SCharles.Forsyth * mark pages as free and dirty, which indicates they cannot be used
17537da2899SCharles.Forsyth */
17637da2899SCharles.Forsyth server->datablock[j].dirty = server->datablock[j].free = logfsdatapagemask(1 << ll->l2pagesperblock, 0);
17737da2899SCharles.Forsyth }
17837da2899SCharles.Forsyth /*
17937da2899SCharles.Forsyth * find how many generations are present, and whether there are any gaps
18037da2899SCharles.Forsyth */
18137da2899SCharles.Forsyth errmsg = eliminateduplicates(server, "log", logpathmap, &logfound);
18237da2899SCharles.Forsyth if(errmsg)
18337da2899SCharles.Forsyth goto fail;
18437da2899SCharles.Forsyth gensfound = 0;
18537da2899SCharles.Forsyth lastgenfound = -1;
18637da2899SCharles.Forsyth for(i = 0; i < nelem(geninfo); i++)
18737da2899SCharles.Forsyth geninfo[i].start = -1;
18837da2899SCharles.Forsyth for(i = 0; i < logfound; i++) {
18937da2899SCharles.Forsyth int gen;
19037da2899SCharles.Forsyth gen = loggenof(logpathmap[i].path);
19137da2899SCharles.Forsyth if(geninfo[gen].start < 0) {
19237da2899SCharles.Forsyth if(lastgenfound >= 0)
19337da2899SCharles.Forsyth geninfo[lastgenfound].end = i;
19437da2899SCharles.Forsyth geninfo[gen].start = i;
19537da2899SCharles.Forsyth lastgenfound = gen;
19637da2899SCharles.Forsyth geninfo[gen].gaps = 0;
19737da2899SCharles.Forsyth gensfound++;
19837da2899SCharles.Forsyth }
19937da2899SCharles.Forsyth else if(!geninfo[lastgenfound].gaps && logseqof(logpathmap[i - 1].path) + 1 != logseqof(logpathmap[i].path)) {
20037da2899SCharles.Forsyth geninfo[lastgenfound].gaps = 1;
20137da2899SCharles.Forsyth print("generation %d has gaps (%lud, %lud)\n", lastgenfound,
20237da2899SCharles.Forsyth logseqof(logpathmap[i - 1].path), logseqof(logpathmap[i].path));
20337da2899SCharles.Forsyth }
20437da2899SCharles.Forsyth }
20537da2899SCharles.Forsyth if(lastgenfound >= 0)
20637da2899SCharles.Forsyth geninfo[lastgenfound].end = i;
20737da2899SCharles.Forsyth if(server->trace > 1) {
20837da2899SCharles.Forsyth for(i = 0; i < nelem(geninfo); i++)
20937da2899SCharles.Forsyth print("geninfo: %ld: start %ld end %ld gaps %d\n", i, geninfo[i].start, geninfo[i].end, geninfo[i].gaps);
21037da2899SCharles.Forsyth }
21137da2899SCharles.Forsyth switch(gensfound) {
21237da2899SCharles.Forsyth case 0:
21337da2899SCharles.Forsyth /* active log - empty */
21437da2899SCharles.Forsyth break;
21537da2899SCharles.Forsyth case 1:
21637da2899SCharles.Forsyth /*
21737da2899SCharles.Forsyth * one log, active
21837da2899SCharles.Forsyth */
21937da2899SCharles.Forsyth for(g0 = 0; g0 < nelem(geninfo); g0++)
22037da2899SCharles.Forsyth if(geninfo[g0].start >= 0)
22137da2899SCharles.Forsyth break;
22237da2899SCharles.Forsyth if(geninfo[g0].gaps || geninfo[g0].start != 0) {
22337da2899SCharles.Forsyth errmsg = "missing log blocks";
22437da2899SCharles.Forsyth goto fail;
22537da2899SCharles.Forsyth }
22637da2899SCharles.Forsyth populate(server->activelog, g0, 0, geninfo[g0].end - geninfo[g0].start - 1, logpathmap + geninfo[g0].start);
22737da2899SCharles.Forsyth break;
22837da2899SCharles.Forsyth case 2:
22937da2899SCharles.Forsyth /*
23037da2899SCharles.Forsyth * two logs, active, swept
23137da2899SCharles.Forsyth */
23237da2899SCharles.Forsyth g0 = -1;
23337da2899SCharles.Forsyth for(g1 = 0; g1 < nelem(geninfo); g1++)
23437da2899SCharles.Forsyth if(geninfo[g1].start >= 0) {
23537da2899SCharles.Forsyth if(g0 < 0)
23637da2899SCharles.Forsyth g0 = g1;
23737da2899SCharles.Forsyth else
23837da2899SCharles.Forsyth break;
23937da2899SCharles.Forsyth }
24037da2899SCharles.Forsyth if(geninfo[g0].gaps || geninfo[g1].gaps) {
24137da2899SCharles.Forsyth errmsg = "missing log blocks";
24237da2899SCharles.Forsyth goto fail;
24337da2899SCharles.Forsyth }
24437da2899SCharles.Forsyth if(g0 == loggensucc(g1)) {
24537da2899SCharles.Forsyth int tmp = g0;
24637da2899SCharles.Forsyth g0 = g1;
24737da2899SCharles.Forsyth g1 = tmp;
24837da2899SCharles.Forsyth }
24937da2899SCharles.Forsyth else if(g1 != loggensucc(g0)) {
25037da2899SCharles.Forsyth errmsg = "nonsequential generations in log";
25137da2899SCharles.Forsyth goto fail;
25237da2899SCharles.Forsyth }
25337da2899SCharles.Forsyth if(logseqof(logpathmap[geninfo[g1].start].path) != 0) {
25437da2899SCharles.Forsyth errmsg = "swept log does not start at 0";
25537da2899SCharles.Forsyth goto fail;
25637da2899SCharles.Forsyth }
25737da2899SCharles.Forsyth if(logseqof(logpathmap[geninfo[g0].start].path) == logseqof(logpathmap[geninfo[g1].end - 1].path)) {
25837da2899SCharles.Forsyth /*
25937da2899SCharles.Forsyth * duplicate block
26037da2899SCharles.Forsyth * as the log never gets bigger, information from active[n] is either entirely in swept[n],
26137da2899SCharles.Forsyth * or split between swept[n-1] and swept[n]. we can safely remove swept[n]. this might
26237da2899SCharles.Forsyth * leave some duplication between swept[n - 1] and active[n], but this is always true
26337da2899SCharles.Forsyth * for a partially swept log
26437da2899SCharles.Forsyth */
26537da2899SCharles.Forsyth logfsbootfettleblock(server->lb, logpathmap[geninfo[g1].end - 1].block, LogfsTnone, ~0, nil);
26637da2899SCharles.Forsyth geninfo[g1].end--;
26737da2899SCharles.Forsyth }
26837da2899SCharles.Forsyth if(logseqof(logpathmap[geninfo[g0].start].path) < logseqof(logpathmap[geninfo[g1].end - 1].path)) {
26937da2899SCharles.Forsyth errmsg = "active log overlaps end of swept log";
27037da2899SCharles.Forsyth goto fail;
27137da2899SCharles.Forsyth }
27237da2899SCharles.Forsyth populate(server->activelog, g0, logseqof(logpathmap[geninfo[g0].start].path),
27337da2899SCharles.Forsyth logseqof(logpathmap[geninfo[g0].end - 1].path), logpathmap + geninfo[g0].start);
27437da2899SCharles.Forsyth if(server->sweptlog == nil) {
27537da2899SCharles.Forsyth errmsg = logfslogsegmentnew(server, g1, &server->sweptlog);
27637da2899SCharles.Forsyth if(errmsg)
27737da2899SCharles.Forsyth goto fail;
27837da2899SCharles.Forsyth }
27937da2899SCharles.Forsyth populate(server->sweptlog, g1, logseqof(logpathmap[geninfo[g1].start].path),
28037da2899SCharles.Forsyth logseqof(logpathmap[geninfo[g1].end - 1].path), logpathmap + geninfo[g1].start);
28137da2899SCharles.Forsyth break;
28237da2899SCharles.Forsyth default:
28337da2899SCharles.Forsyth errmsg = "more than two generations in log";
28437da2899SCharles.Forsyth goto fail;
28537da2899SCharles.Forsyth }
28637da2899SCharles.Forsyth goto ok;
28737da2899SCharles.Forsyth fail:
28837da2899SCharles.Forsyth logfslogsegmentfree(&server->sweptlog);
28937da2899SCharles.Forsyth ok:
29037da2899SCharles.Forsyth logfsfreemem(logpathmap);
29137da2899SCharles.Forsyth logfsfreemem(datapathmap);
29237da2899SCharles.Forsyth return errmsg;
29337da2899SCharles.Forsyth }
294