xref: /inferno-os/liblogfs/boot.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "local.h"
437da2899SCharles.Forsyth 
537da2899SCharles.Forsyth struct LogfsBoot {
637da2899SCharles.Forsyth 	LogfsLowLevel *ll;
737da2899SCharles.Forsyth 	long bootblocks;
837da2899SCharles.Forsyth 	long blocksize;
937da2899SCharles.Forsyth 	long size;
1037da2899SCharles.Forsyth 	long *map;
1137da2899SCharles.Forsyth 	int trace;
1237da2899SCharles.Forsyth 	int printbad;
1337da2899SCharles.Forsyth //	ulong bootpathmask;
1437da2899SCharles.Forsyth //	int bootgenshift;
1537da2899SCharles.Forsyth };
1637da2899SCharles.Forsyth 
1737da2899SCharles.Forsyth typedef struct LogfsBootPath LogfsBootPath;
1837da2899SCharles.Forsyth 
1937da2899SCharles.Forsyth //#define LogfsBootGenBits 2
2037da2899SCharles.Forsyth //#define LogfsBootGenMask ((1 << LogfsBootGenBits) - 1)
2137da2899SCharles.Forsyth #define LogfsBootGenMask ((1 << L2BlockCopies) - 1)
2237da2899SCharles.Forsyth 
2337da2899SCharles.Forsyth struct LogfsBootPath {
2437da2899SCharles.Forsyth 	ulong path;
2537da2899SCharles.Forsyth 	uchar gen;
2637da2899SCharles.Forsyth };
2737da2899SCharles.Forsyth 
2837da2899SCharles.Forsyth #define LOGFSMKBOOTPATH(lb, p) mkdatapath((p)->path, (p)->gen)
2937da2899SCharles.Forsyth #define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = dataseqof(v), (p)->gen = copygenof(v))
3037da2899SCharles.Forsyth #define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX(0, 0, p, v)
3137da2899SCharles.Forsyth 
3237da2899SCharles.Forsyth //#define LOGFSMKBOOTPATH(lb, p) (((p)->path & (lb)->bootpathmask) | (((p)->gen & LogfsBootGenMask) << (lb)->bootgenshift))
3337da2899SCharles.Forsyth //#define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = (v) & (bpm), (p)->gen = ((v) >> (bgs)) & LogfsBootGenMask)
3437da2899SCharles.Forsyth //#define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX((lb)->bootgenshift, (lb)->bootpathmask, p, v)
3537da2899SCharles.Forsyth 
3637da2899SCharles.Forsyth extern LogfsBootPath logfsbooterasedpath;
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth static char Ecorrupt[] = "filesystem corrupt";
3937da2899SCharles.Forsyth static char Enospc[] = "no free blocks";
4037da2899SCharles.Forsyth static char Eaddress[] = "address out of range";
4137da2899SCharles.Forsyth 
4237da2899SCharles.Forsyth static char *
logfsbootblockupdate(LogfsBoot * lb,void * buf,LogfsBootPath * path,uchar tag,ulong block)4337da2899SCharles.Forsyth logfsbootblockupdate(LogfsBoot *lb, void *buf, LogfsBootPath *path, uchar tag, ulong block)
4437da2899SCharles.Forsyth {
4537da2899SCharles.Forsyth 	LogfsLowLevel *ll =  lb->ll;
4637da2899SCharles.Forsyth 	char *errmsg;
4737da2899SCharles.Forsyth 	ulong packedpath;
4837da2899SCharles.Forsyth 
4937da2899SCharles.Forsyth 	if(lb->trace > 1)
5037da2899SCharles.Forsyth 		print("logfsbootblockupdate: path 0x%.8lux(%d) tag %s block %lud\n",
5137da2899SCharles.Forsyth 		    path->path, path->gen, logfstagname(tag), block);
5237da2899SCharles.Forsyth 
5337da2899SCharles.Forsyth 	packedpath = LOGFSMKBOOTPATH(lb, path);
5437da2899SCharles.Forsyth 	errmsg = (*ll->writeblock)(ll, buf, tag, packedpath, 1, &lb->bootblocks, block);
5537da2899SCharles.Forsyth 
5637da2899SCharles.Forsyth 	if(errmsg) {
5737da2899SCharles.Forsyth 		/*
5837da2899SCharles.Forsyth 		 * ensure block never used again until file system reinitialised
5937da2899SCharles.Forsyth 		 * We have absolutely no idea what state it's in. This is most
6037da2899SCharles.Forsyth 		 * likely if someone turns off the power (or at least threatens
6137da2899SCharles.Forsyth 		 * the power supply), during a block update. This way the block
6237da2899SCharles.Forsyth 		 * is protected until the file system in reinitialised. An alternative
6337da2899SCharles.Forsyth 		 * would be check the file system after a power fail false alarm,
6437da2899SCharles.Forsyth 		 * and erase any Tworse blocks
6537da2899SCharles.Forsyth 		 */
6637da2899SCharles.Forsyth 		(*ll->setblocktag)(ll, block, LogfsTworse);
6737da2899SCharles.Forsyth 		return errmsg;
6837da2899SCharles.Forsyth 	}
6937da2899SCharles.Forsyth 
7037da2899SCharles.Forsyth 	(*ll->setblocktag)(ll, block, tag);
7137da2899SCharles.Forsyth 	(*ll->setblockpath)(ll, block, packedpath);
7237da2899SCharles.Forsyth 
7337da2899SCharles.Forsyth 	return nil;
7437da2899SCharles.Forsyth }
7537da2899SCharles.Forsyth 
7637da2899SCharles.Forsyth char *
logfsbootfettleblock(LogfsBoot * lb,long block,uchar tag,long path,int * markedbad)7737da2899SCharles.Forsyth logfsbootfettleblock(LogfsBoot *lb, long block, uchar tag, long path, int *markedbad)
7837da2899SCharles.Forsyth {
7937da2899SCharles.Forsyth 	LogfsLowLevel *ll = lb->ll;
8037da2899SCharles.Forsyth 	char *errmsg;
8137da2899SCharles.Forsyth 	void *llsave;
8237da2899SCharles.Forsyth 
8337da2899SCharles.Forsyth 	errmsg = (*ll->eraseblock)(ll, block, &llsave, markedbad);
8437da2899SCharles.Forsyth 	if(errmsg || (markedbad && *markedbad)) {
8537da2899SCharles.Forsyth 		logfsfreemem(llsave);
8637da2899SCharles.Forsyth 		return errmsg;
8737da2899SCharles.Forsyth 	}
8837da2899SCharles.Forsyth 	errmsg = (*ll->reformatblock)(ll, block, tag, path, 1, &lb->bootblocks, llsave, markedbad);
8937da2899SCharles.Forsyth 	logfsfreemem(llsave);
9037da2899SCharles.Forsyth 	return errmsg;
9137da2899SCharles.Forsyth }
9237da2899SCharles.Forsyth 
9337da2899SCharles.Forsyth /*
9437da2899SCharles.Forsyth  * block transfer is the critical unit of update
9537da2899SCharles.Forsyth  * we are going to assume that page writes and block erases are atomic
9637da2899SCharles.Forsyth  * this can pretty much be assured by not starting a page write or block erase
9737da2899SCharles.Forsyth  * if the device feels it is in power fail
9837da2899SCharles.Forsyth  */
9937da2899SCharles.Forsyth 
10037da2899SCharles.Forsyth static char *
logfsbootblocktransfer(LogfsBoot * lb,void * buf,ulong oldblock,int markbad)10137da2899SCharles.Forsyth logfsbootblocktransfer(LogfsBoot *lb, void *buf, ulong oldblock, int markbad)
10237da2899SCharles.Forsyth {
10337da2899SCharles.Forsyth 	LogfsLowLevel *ll = lb->ll;
10437da2899SCharles.Forsyth 	long bestnewblock;
10537da2899SCharles.Forsyth 	ulong oldpackedpath;
10637da2899SCharles.Forsyth 	LogfsBootPath oldpath;
10737da2899SCharles.Forsyth 	short oldtag;
10837da2899SCharles.Forsyth 	char *errmsg;
10937da2899SCharles.Forsyth 	int markedbad;
11037da2899SCharles.Forsyth 
11137da2899SCharles.Forsyth 	oldpackedpath = (*ll->getblockpath)(ll, oldblock);
11237da2899SCharles.Forsyth 	oldtag = (*ll->getblocktag)(ll, oldblock);
11337da2899SCharles.Forsyth 
11437da2899SCharles.Forsyth 	LOGFSSPLITBOOTPATH(lb, &oldpath, oldpackedpath);
11537da2899SCharles.Forsyth 
11637da2899SCharles.Forsyth 	for(;;) {
11737da2899SCharles.Forsyth 		LogfsBootPath newpath;
11837da2899SCharles.Forsyth 
11937da2899SCharles.Forsyth 		bestnewblock = logfsfindfreeblock(ll, markbad ? AllocReasonReplace : AllocReasonTransfer);
12037da2899SCharles.Forsyth 		if(lb->trace > 0 && markbad)
12137da2899SCharles.Forsyth 			print("logfsbootblocktransfer: block %lud is bad, copying to %ld\n",
12237da2899SCharles.Forsyth 				oldblock, bestnewblock);
12337da2899SCharles.Forsyth 		if(lb->trace > 1 && !markbad)
12437da2899SCharles.Forsyth 			print("logfsbootblocktransfer: copying block %lud to %ld\n",
12537da2899SCharles.Forsyth 				oldblock, bestnewblock);
12637da2899SCharles.Forsyth 		if(bestnewblock == -1)
12737da2899SCharles.Forsyth 			return Enospc;
12837da2899SCharles.Forsyth 		newpath = oldpath;
12937da2899SCharles.Forsyth //		newpath.gen = (newpath.gen + 1) & LogfsBootGenMask;
13037da2899SCharles.Forsyth 		newpath.gen = copygensucc(newpath.gen);
13137da2899SCharles.Forsyth 		errmsg = logfsbootblockupdate(lb, buf, &newpath, oldtag, bestnewblock);
13237da2899SCharles.Forsyth 		if(errmsg == nil)
13337da2899SCharles.Forsyth 			break;
13437da2899SCharles.Forsyth 		if(strcmp(errmsg, Eio) != 0)
13537da2899SCharles.Forsyth 			return errmsg;
13637da2899SCharles.Forsyth 		(*ll->markblockbad)(ll, bestnewblock);
13737da2899SCharles.Forsyth 	}
13837da2899SCharles.Forsyth 
13937da2899SCharles.Forsyth #ifdef LOGFSTEST
14037da2899SCharles.Forsyth 	if(logfstest.partialupdate) {
14137da2899SCharles.Forsyth 		print("skipping erase\n");
14237da2899SCharles.Forsyth 		logfstest.partialupdate = 0;
14337da2899SCharles.Forsyth 		return nil;
14437da2899SCharles.Forsyth 	}
14537da2899SCharles.Forsyth 	if(logfstest.updatenoerase) {
14637da2899SCharles.Forsyth 		print("skipping erase\n");
14737da2899SCharles.Forsyth 		logfstest.updatenoerase = 0;
14837da2899SCharles.Forsyth 		return nil;
14937da2899SCharles.Forsyth 	}
15037da2899SCharles.Forsyth #endif
15137da2899SCharles.Forsyth 
15237da2899SCharles.Forsyth 	if(oldtag == LogfsTboot)
15337da2899SCharles.Forsyth 		lb->map[oldpath.path] = bestnewblock;
15437da2899SCharles.Forsyth 
15537da2899SCharles.Forsyth 	return logfsbootfettleblock(lb, oldblock, LogfsTnone, ~0, &markedbad);
15637da2899SCharles.Forsyth }
15737da2899SCharles.Forsyth 
15837da2899SCharles.Forsyth static char *
logfsbootblockread(LogfsBoot * lb,void * buf,long block,LogfsLowLevelReadResult * blocke)15937da2899SCharles.Forsyth logfsbootblockread(LogfsBoot *lb, void *buf, long block, LogfsLowLevelReadResult *blocke)
16037da2899SCharles.Forsyth {
16137da2899SCharles.Forsyth 	LogfsLowLevel *ll = lb->ll;
16237da2899SCharles.Forsyth 	char *errmsg;
16337da2899SCharles.Forsyth 
16437da2899SCharles.Forsyth 	*blocke = LogfsLowLevelReadResultOk;
16537da2899SCharles.Forsyth 	errmsg = (*ll->readblock)(ll, buf, block, blocke);
16637da2899SCharles.Forsyth 	if(errmsg)
16737da2899SCharles.Forsyth 		return errmsg;
16837da2899SCharles.Forsyth 
16937da2899SCharles.Forsyth 	if(*blocke != LogfsLowLevelReadResultOk) {
17037da2899SCharles.Forsyth 		char *errmsg = logfsbootblocktransfer(lb, buf, block, 1);
17137da2899SCharles.Forsyth 		if(errmsg)
17237da2899SCharles.Forsyth 			return errmsg;
17337da2899SCharles.Forsyth 	}
17437da2899SCharles.Forsyth 
17537da2899SCharles.Forsyth 	if(*blocke == LogfsLowLevelReadResultHardError)
17637da2899SCharles.Forsyth 		return Eio;
17737da2899SCharles.Forsyth 
17837da2899SCharles.Forsyth 	return nil;
17937da2899SCharles.Forsyth }
18037da2899SCharles.Forsyth 
18137da2899SCharles.Forsyth char *
logfsbootread(LogfsBoot * lb,void * buf,long n,ulong offset)18237da2899SCharles.Forsyth logfsbootread(LogfsBoot *lb, void *buf, long n, ulong offset)
18337da2899SCharles.Forsyth {
18437da2899SCharles.Forsyth 	int i;
18537da2899SCharles.Forsyth 
18637da2899SCharles.Forsyth 	if(lb->trace > 0)
18737da2899SCharles.Forsyth 		print("logfsbootread(0x%.8lux, 0x%lx, 0x%lux)\n", (ulong)buf, n, offset);
18837da2899SCharles.Forsyth 	if(offset % lb->blocksize || n % lb->blocksize)
18937da2899SCharles.Forsyth 		return Eio;
19037da2899SCharles.Forsyth 	n /= lb->blocksize;
19137da2899SCharles.Forsyth 	offset /= lb->blocksize;
19237da2899SCharles.Forsyth 	if(offset + n > lb->bootblocks)
19337da2899SCharles.Forsyth 		return Eio;
19437da2899SCharles.Forsyth 	for(i = 0; i < n; i++) {
19537da2899SCharles.Forsyth 		LogfsLowLevelReadResult result;
19637da2899SCharles.Forsyth 		char *errmsg = logfsbootblockread(lb, buf, lb->map[offset + i], &result);
19737da2899SCharles.Forsyth 		if(errmsg)
19837da2899SCharles.Forsyth 			return errmsg;
19937da2899SCharles.Forsyth 		buf = (uchar *)buf + lb->blocksize;
20037da2899SCharles.Forsyth 	}
20137da2899SCharles.Forsyth 	return nil;
20237da2899SCharles.Forsyth }
20337da2899SCharles.Forsyth 
20437da2899SCharles.Forsyth static char *
logfsbootblockreplace(LogfsBoot * lb,void * buf,ulong logicalblock)20537da2899SCharles.Forsyth logfsbootblockreplace(LogfsBoot *lb, void *buf, ulong logicalblock)
20637da2899SCharles.Forsyth {
20737da2899SCharles.Forsyth 	uchar *oldblockbuf;
20837da2899SCharles.Forsyth 	ulong oldblock;
20937da2899SCharles.Forsyth 	char *errmsg;
21037da2899SCharles.Forsyth 	LogfsLowLevelReadResult result;
21137da2899SCharles.Forsyth 
21237da2899SCharles.Forsyth 	oldblock = lb->map[logicalblock];
21337da2899SCharles.Forsyth 	oldblockbuf = logfsrealloc(nil, lb->blocksize);
21437da2899SCharles.Forsyth 	if(oldblockbuf == nil)
21537da2899SCharles.Forsyth 		return Enomem;
21637da2899SCharles.Forsyth 
21737da2899SCharles.Forsyth 	errmsg = logfsbootblockread(lb, oldblockbuf, oldblock, &result);
21837da2899SCharles.Forsyth 	if(errmsg == nil && memcmp(oldblockbuf, buf, lb->blocksize) != 0)
21937da2899SCharles.Forsyth 		errmsg = logfsbootblocktransfer(lb, buf, oldblock, 0);
22037da2899SCharles.Forsyth 
22137da2899SCharles.Forsyth 	logfsfreemem(oldblockbuf);
22237da2899SCharles.Forsyth 	return errmsg;
22337da2899SCharles.Forsyth }
22437da2899SCharles.Forsyth 
22537da2899SCharles.Forsyth char *
logfsbootwrite(LogfsBoot * lb,void * buf,long n,ulong offset)22637da2899SCharles.Forsyth logfsbootwrite(LogfsBoot *lb, void *buf, long n, ulong offset)
22737da2899SCharles.Forsyth {
22837da2899SCharles.Forsyth 	int i;
22937da2899SCharles.Forsyth 
23037da2899SCharles.Forsyth 	if(lb->trace > 0)
23137da2899SCharles.Forsyth 		print("logfsbootwrite(0x%.8lux, 0x%lux, 0x%lux)\n", (ulong)buf, n, offset);
23237da2899SCharles.Forsyth 	/*
23337da2899SCharles.Forsyth 	 * don't even get started on a write if the power has failed
23437da2899SCharles.Forsyth 	 */
23537da2899SCharles.Forsyth 	if(offset % lb->blocksize || n % lb->blocksize)
23637da2899SCharles.Forsyth 		return Eio;
23737da2899SCharles.Forsyth 	n /= lb->blocksize;
23837da2899SCharles.Forsyth 	offset /= lb->blocksize;
23937da2899SCharles.Forsyth 	if(offset + n > lb->bootblocks)
24037da2899SCharles.Forsyth 		return Eio;
24137da2899SCharles.Forsyth 	for(i = 0; i < n; i++) {
24237da2899SCharles.Forsyth 		logfsbootblockreplace(lb, buf, offset + i);
24337da2899SCharles.Forsyth 		buf = (uchar *)buf + lb->blocksize;
24437da2899SCharles.Forsyth 	}
24537da2899SCharles.Forsyth 	return nil;
24637da2899SCharles.Forsyth }
24737da2899SCharles.Forsyth 
24837da2899SCharles.Forsyth char *
logfsbootio(LogfsBoot * lb,void * buf,long n,ulong offset,int write)24937da2899SCharles.Forsyth logfsbootio(LogfsBoot *lb, void *buf, long n, ulong offset, int write)
25037da2899SCharles.Forsyth {
25137da2899SCharles.Forsyth 	return (write ? logfsbootwrite : logfsbootread)(lb, buf, n, offset);
25237da2899SCharles.Forsyth }
25337da2899SCharles.Forsyth 
25437da2899SCharles.Forsyth static char *
eraseandformatblock(LogfsBoot * lb,long block,int trace)25537da2899SCharles.Forsyth eraseandformatblock(LogfsBoot *lb, long block, int trace)
25637da2899SCharles.Forsyth {
25737da2899SCharles.Forsyth 	char *errmsg;
25837da2899SCharles.Forsyth 	int markedbad;
25937da2899SCharles.Forsyth 
26037da2899SCharles.Forsyth 	errmsg = logfsbootfettleblock(lb, block, LogfsTnone, ~0, &markedbad);
26137da2899SCharles.Forsyth 	if(errmsg)
26237da2899SCharles.Forsyth 		return errmsg;
26337da2899SCharles.Forsyth 	if(markedbad && trace > 1)
26437da2899SCharles.Forsyth 		print("erase/format failed - marked bad\n");
26537da2899SCharles.Forsyth 	return nil;
26637da2899SCharles.Forsyth }
26737da2899SCharles.Forsyth 
26837da2899SCharles.Forsyth char *
logfsbootopen(LogfsLowLevel * ll,long base,long limit,int trace,int printbad,LogfsBoot ** lbp)26937da2899SCharles.Forsyth logfsbootopen(LogfsLowLevel *ll, long base, long limit, int trace, int printbad, LogfsBoot **lbp)
27037da2899SCharles.Forsyth {
27137da2899SCharles.Forsyth 	long *reversemap;
27237da2899SCharles.Forsyth 	ulong blocksize;
27337da2899SCharles.Forsyth 	ulong blocks;
27437da2899SCharles.Forsyth 	long i;
27537da2899SCharles.Forsyth 	long bootblockmax;
27637da2899SCharles.Forsyth 	LogfsBoot *lb = nil;
27737da2899SCharles.Forsyth 	ulong baseblock;
27837da2899SCharles.Forsyth 	char *errmsg;
27937da2899SCharles.Forsyth //	int bootgenshift = ll->pathbits- LogfsBootGenBits;
28037da2899SCharles.Forsyth //	ulong bootpathmask = (1 << (ll->pathbits - LogfsBootGenBits)) - 1;
28137da2899SCharles.Forsyth 	long expectedbootblocks;
28237da2899SCharles.Forsyth 
28337da2899SCharles.Forsyth 	errmsg = (*ll->open)(ll, base, limit, trace, 1, &expectedbootblocks);
28437da2899SCharles.Forsyth 	if(errmsg)
28537da2899SCharles.Forsyth 		return errmsg;
28637da2899SCharles.Forsyth 
28737da2899SCharles.Forsyth 	bootblockmax = -1;
28837da2899SCharles.Forsyth 	blocks = ll->blocks;
28937da2899SCharles.Forsyth 	baseblock = (*ll->getbaseblock)(ll);
29037da2899SCharles.Forsyth 	blocksize = (*ll->getblocksize)(ll);
29137da2899SCharles.Forsyth 
29237da2899SCharles.Forsyth 	for(i = 0; i < blocks; i++) {
29337da2899SCharles.Forsyth 		if((*ll->getblocktag)(ll, i) == LogfsTboot) {
29437da2899SCharles.Forsyth 			long path = (*ll->getblockpath)(ll, i);
29537da2899SCharles.Forsyth 			LogfsBootPath lp;
29637da2899SCharles.Forsyth 			LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &lp, path);
29737da2899SCharles.Forsyth 			if((long)lp.path > bootblockmax)
29837da2899SCharles.Forsyth 				bootblockmax = lp.path;
29937da2899SCharles.Forsyth 		}
30037da2899SCharles.Forsyth 	}
30137da2899SCharles.Forsyth 	if(bootblockmax + 1 >= blocks) {
30237da2899SCharles.Forsyth 		if(printbad)
30337da2899SCharles.Forsyth 			print("logfsbootinit: bootblockmax %ld exceeds number of blocks\n", bootblockmax);
30437da2899SCharles.Forsyth 		return Ecorrupt;
30537da2899SCharles.Forsyth 	}
30637da2899SCharles.Forsyth 	if(bootblockmax < 0) {
30737da2899SCharles.Forsyth 		if(printbad)
30837da2899SCharles.Forsyth 			print("logfsbootopen: no boot area\n");
30937da2899SCharles.Forsyth 		return Ecorrupt;
31037da2899SCharles.Forsyth 	}
31137da2899SCharles.Forsyth 	if(bootblockmax + 1 != expectedbootblocks) {
31237da2899SCharles.Forsyth 		if(printbad)
31337da2899SCharles.Forsyth 			print("logfsbootopen: wrong number of bootblocks (found %lud, expected %lud)\n",
31437da2899SCharles.Forsyth 				bootblockmax + 1, expectedbootblocks);
31537da2899SCharles.Forsyth 	}
31637da2899SCharles.Forsyth 
31737da2899SCharles.Forsyth 	reversemap = logfsrealloc(nil, sizeof(*reversemap) * (bootblockmax + 1));
31837da2899SCharles.Forsyth 	if(reversemap == nil)
31937da2899SCharles.Forsyth 		return Enomem;
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 	for(i = 0; i <= bootblockmax; i++)
32237da2899SCharles.Forsyth 		reversemap[i] = -1;
32337da2899SCharles.Forsyth 	for(i = 0; i < blocks; i++) {
32437da2899SCharles.Forsyth 		LogfsBootPath ipath;
32537da2899SCharles.Forsyth 		long rm;
32637da2899SCharles.Forsyth 		ulong ip;
32737da2899SCharles.Forsyth 
32837da2899SCharles.Forsyth 		if((*ll->getblocktag)(ll, i) != LogfsTboot)
32937da2899SCharles.Forsyth 			continue;
33037da2899SCharles.Forsyth 		ip = (*ll->getblockpath)(ll, i);
33137da2899SCharles.Forsyth 		LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &ipath, ip);
33237da2899SCharles.Forsyth 		rm = reversemap[ipath.path];
33337da2899SCharles.Forsyth 		if(rm != -1) {
33437da2899SCharles.Forsyth 			if(printbad)
33537da2899SCharles.Forsyth 				print("logfsbootopen: blockaddr 0x%.8lux: path %ld(%d): duplicate\n",
33637da2899SCharles.Forsyth 					blocksize * (baseblock + i), ipath.path, ipath.gen);
33737da2899SCharles.Forsyth 			/*
33837da2899SCharles.Forsyth 			 * resolve collision
33937da2899SCharles.Forsyth 			 * if this one is partial, then erase it
34037da2899SCharles.Forsyth 			 * if the existing one is partial, erase that
34137da2899SCharles.Forsyth 			 * if both valid, give up
34237da2899SCharles.Forsyth 			 */
34337da2899SCharles.Forsyth 			if((*ll->getblockpartialformatstatus)(ll, i)) {
34437da2899SCharles.Forsyth 				errmsg = eraseandformatblock(lb, i, trace);
34537da2899SCharles.Forsyth 				if(errmsg)
34637da2899SCharles.Forsyth 					goto error;
34737da2899SCharles.Forsyth 			}
34837da2899SCharles.Forsyth 			else if((*ll->getblockpartialformatstatus)(ll, rm)) {
34937da2899SCharles.Forsyth 				errmsg = eraseandformatblock(lb, rm, trace);
35037da2899SCharles.Forsyth 				if(errmsg)
35137da2899SCharles.Forsyth 					goto error;
35237da2899SCharles.Forsyth 				reversemap[ipath.path] = i;
35337da2899SCharles.Forsyth 			}
35437da2899SCharles.Forsyth 			else {
35537da2899SCharles.Forsyth 				int d;
35637da2899SCharles.Forsyth 				ulong rmp;
35737da2899SCharles.Forsyth 				LogfsBootPath rmpath;
35837da2899SCharles.Forsyth 				rmp = (*ll->getblockpath)(ll, rm);
35937da2899SCharles.Forsyth 				LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &rmpath, rmp);
36037da2899SCharles.Forsyth 				d = (ipath.gen - rmpath.gen) & LogfsBootGenMask;
36137da2899SCharles.Forsyth 				if(printbad)
36237da2899SCharles.Forsyth 					print("i.gen = %d rm.gen = %d d = %d\n", ipath.gen, rmpath.gen, d);
36337da2899SCharles.Forsyth 				if(d == 1) {
36437da2899SCharles.Forsyth 					/* i is newer;
36537da2899SCharles.Forsyth 					 * keep the OLDER one because
36637da2899SCharles.Forsyth 					 * we might have had a write failure on the last page, but lost the
36737da2899SCharles.Forsyth 					 * power before being able to mark the first page bad
36837da2899SCharles.Forsyth 					 * if, worse, the auxiliary area's tag is the same for first and last page,
36937da2899SCharles.Forsyth 					 * this looks like a successfully written page. so, we cannot believe the
37037da2899SCharles.Forsyth 					 * data in the newer block unless we erased the old one, and then of
37137da2899SCharles.Forsyth 					 * course, we wouldn't have a duplicate.
37237da2899SCharles.Forsyth 					 */
37337da2899SCharles.Forsyth 					errmsg = eraseandformatblock(lb, i, trace);
37437da2899SCharles.Forsyth 					if(errmsg)
37537da2899SCharles.Forsyth 						goto error;
37637da2899SCharles.Forsyth 				}
37737da2899SCharles.Forsyth 				else if(d == LogfsBootGenMask) {
37837da2899SCharles.Forsyth 					/* rm is newer */
37937da2899SCharles.Forsyth 					errmsg = eraseandformatblock(lb, rm, trace);
38037da2899SCharles.Forsyth 					if(errmsg)
38137da2899SCharles.Forsyth 						goto error;
38237da2899SCharles.Forsyth 					reversemap[ipath.path] = i;
38337da2899SCharles.Forsyth 				}
38437da2899SCharles.Forsyth 				else {
38537da2899SCharles.Forsyth 					errmsg = Ecorrupt;
38637da2899SCharles.Forsyth 					goto error;
38737da2899SCharles.Forsyth 				}
38837da2899SCharles.Forsyth 			}
38937da2899SCharles.Forsyth 		}
39037da2899SCharles.Forsyth 		else
39137da2899SCharles.Forsyth 			reversemap[ipath.path] = i;
39237da2899SCharles.Forsyth 	}
39337da2899SCharles.Forsyth 	/*
39437da2899SCharles.Forsyth 	 * final checks; not partial blocks, and no holes
39537da2899SCharles.Forsyth 	 */
39637da2899SCharles.Forsyth 	for(i = 0; i <= bootblockmax; i++) {
39737da2899SCharles.Forsyth 		long rm;
39837da2899SCharles.Forsyth 		rm = reversemap[i];
39937da2899SCharles.Forsyth 		if(rm == -1) {
40037da2899SCharles.Forsyth 			if(printbad)
40137da2899SCharles.Forsyth 				print("logfsbootopen: missing boot block %ld\n", i);
40237da2899SCharles.Forsyth 			errmsg = Ecorrupt;
40337da2899SCharles.Forsyth 			goto error;
40437da2899SCharles.Forsyth 		}
40537da2899SCharles.Forsyth 		if((*ll->getblockpartialformatstatus)(ll, rm)) {
40637da2899SCharles.Forsyth 			if(printbad)
40737da2899SCharles.Forsyth 				print("logfsbootopen: boot block %ld partially written\n", rm);
40837da2899SCharles.Forsyth 			errmsg = Ecorrupt;
40937da2899SCharles.Forsyth 			goto error;
41037da2899SCharles.Forsyth 		}
41137da2899SCharles.Forsyth 	}
41237da2899SCharles.Forsyth 	/* the reverse map is consistent */
41337da2899SCharles.Forsyth 	lb = logfsrealloc(nil, sizeof(*lb));
41437da2899SCharles.Forsyth 	if(lb == nil) {
41537da2899SCharles.Forsyth 		errmsg = Enomem;
41637da2899SCharles.Forsyth 		goto error;
41737da2899SCharles.Forsyth 	}
41837da2899SCharles.Forsyth 
41937da2899SCharles.Forsyth 	lb->blocksize = blocksize;
42037da2899SCharles.Forsyth 	lb->bootblocks = bootblockmax + 1;
42137da2899SCharles.Forsyth 	lb->map = reversemap;
42237da2899SCharles.Forsyth 	lb->trace = trace;
42337da2899SCharles.Forsyth 	lb->printbad = printbad;
42437da2899SCharles.Forsyth 	lb->ll = ll;
42537da2899SCharles.Forsyth 	lb->size = blocksize * lb->bootblocks;
42637da2899SCharles.Forsyth //	lb->bootgenshift = bootgenshift;
42737da2899SCharles.Forsyth //	lb->bootpathmask = bootpathmask;
42837da2899SCharles.Forsyth 	*lbp = lb;
42937da2899SCharles.Forsyth 	if(trace)
43037da2899SCharles.Forsyth 		print("logfsbootopen: success\n");
43137da2899SCharles.Forsyth 	return nil;
43237da2899SCharles.Forsyth 
43337da2899SCharles.Forsyth error:
43437da2899SCharles.Forsyth 	logfsfreemem(reversemap);
43537da2899SCharles.Forsyth 	logfsfreemem(lb);
43637da2899SCharles.Forsyth 	return errmsg;
43737da2899SCharles.Forsyth }
43837da2899SCharles.Forsyth 
43937da2899SCharles.Forsyth void
logfsbootfree(LogfsBoot * lb)44037da2899SCharles.Forsyth logfsbootfree(LogfsBoot *lb)
44137da2899SCharles.Forsyth {
44237da2899SCharles.Forsyth 	if(lb) {
44337da2899SCharles.Forsyth 		logfsfreemem(lb->map);
44437da2899SCharles.Forsyth 		logfsfreemem(lb);
44537da2899SCharles.Forsyth 	}
44637da2899SCharles.Forsyth }
44737da2899SCharles.Forsyth 
44837da2899SCharles.Forsyth char *
logfsbootmap(LogfsBoot * lb,ulong laddress,ulong * lblockp,int * lboffsetp,int * lpagep,int * lpageoffsetp,ulong * pblockp,ulong * paddressp)44937da2899SCharles.Forsyth logfsbootmap(LogfsBoot *lb, ulong laddress, ulong *lblockp, int *lboffsetp, int *lpagep, int *lpageoffsetp, ulong *pblockp, ulong *paddressp)
45037da2899SCharles.Forsyth {
45137da2899SCharles.Forsyth 	LogfsLowLevel *ll = lb->ll;
45237da2899SCharles.Forsyth 	ulong lblock;
45337da2899SCharles.Forsyth 	ulong lboffset, lpageoffset, lpage;
45437da2899SCharles.Forsyth 	ulong pblock;
45537da2899SCharles.Forsyth 	ulong paddress;
45637da2899SCharles.Forsyth 
45737da2899SCharles.Forsyth 	lblock = laddress / lb->blocksize;
45837da2899SCharles.Forsyth 	if(lblock >= lb->bootblocks)
45937da2899SCharles.Forsyth 		return Eaddress;
46037da2899SCharles.Forsyth 	lboffset = laddress % lb->blocksize;
46137da2899SCharles.Forsyth 	pblock = lb->map[lblock];
46237da2899SCharles.Forsyth 	paddress = (*ll->calcrawaddress)(ll, pblock, lboffset);
46337da2899SCharles.Forsyth 	lpage = lboffset >>  ll->l2pagesize;
46437da2899SCharles.Forsyth 	lpageoffset = lboffset & ((1 << ll->l2pagesize) - 1);
46537da2899SCharles.Forsyth 	if(lblockp)
46637da2899SCharles.Forsyth 		*lblockp = lblock;
46737da2899SCharles.Forsyth 	if(lboffsetp)
46837da2899SCharles.Forsyth 		*lboffsetp = lboffset;
46937da2899SCharles.Forsyth 	if(lpagep)
47037da2899SCharles.Forsyth 		*lpagep = lpage;
47137da2899SCharles.Forsyth 	if(lpageoffsetp)
47237da2899SCharles.Forsyth 		*lpageoffsetp = lpageoffset;
47337da2899SCharles.Forsyth 	if(pblockp)
47437da2899SCharles.Forsyth 		*pblockp = pblock;
47537da2899SCharles.Forsyth 	if(paddressp)
47637da2899SCharles.Forsyth 		*paddressp = paddress;
47737da2899SCharles.Forsyth 	return nil;
47837da2899SCharles.Forsyth }
47937da2899SCharles.Forsyth 
48037da2899SCharles.Forsyth long
logfsbootgetiosize(LogfsBoot * lb)48137da2899SCharles.Forsyth logfsbootgetiosize(LogfsBoot *lb)
48237da2899SCharles.Forsyth {
48337da2899SCharles.Forsyth 	return lb->blocksize;
48437da2899SCharles.Forsyth }
48537da2899SCharles.Forsyth 
48637da2899SCharles.Forsyth long
logfsbootgetsize(LogfsBoot * lb)48737da2899SCharles.Forsyth logfsbootgetsize(LogfsBoot *lb)
48837da2899SCharles.Forsyth {
48937da2899SCharles.Forsyth 	return lb->size;
49037da2899SCharles.Forsyth }
49137da2899SCharles.Forsyth 
49237da2899SCharles.Forsyth void
logfsboottrace(LogfsBoot * lb,int level)49337da2899SCharles.Forsyth logfsboottrace(LogfsBoot *lb, int level)
49437da2899SCharles.Forsyth {
49537da2899SCharles.Forsyth 	lb->trace = level;
49637da2899SCharles.Forsyth }
497