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