xref: /inferno-os/liblogfs/scan.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
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