#include "logfsos.h" #include "logfs.h" #include "nandfs.h" #include "local.h" char * nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata) { NandfsBlockData *blockdata = nil; long u; ulong badones, goodones; char *errmsg; long possiblebaseblock, possiblesize; long baseblock, limitblock; int ppb; if (trace > 1) print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock); if (nandfs->blockdata) return Eperm; if (base % nandfs->rawblocksize) return Ebadarg; baseblock = base / nandfs->rawblocksize; if (limit == 0) limitblock = nandfs->limitblock; else if (limit % nandfs->rawblocksize) return Ebadarg; else limitblock = limit / nandfs->rawblocksize; if (trace > 1) print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock); possiblebaseblock = 0; possiblesize = 0; /* * search for Tboot block which will reveal the parameters */ nandfs->baseblock = 0; for (u = baseblock; u < limitblock; u++) { NandfsTags tags; LogfsLowLevelReadResult e; int p; int lim; lim = xcount + 3; for (p = 0; p < lim; p++) { errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e); if (errmsg) goto error; if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot) break; if (trace > 1) print("block %lud/%d: 0x%.lux\n", u, p, tags.path); switch (p) { case 1: possiblebaseblock = tags.path; break; case 2: possiblesize = tags.path; break; default: xdata[p - 3] = tags.path; break; } } if (p == lim) break; } if (u >= limitblock) { errmsg = "no valid boot blocks found"; goto error; } if (possiblebaseblock < baseblock || possiblebaseblock >= limitblock || possiblebaseblock + possiblesize > limitblock || possiblesize == 0) { errmsg = "embedded parameters out of range"; goto error; } baseblock = possiblebaseblock; limitblock = possiblebaseblock + possiblesize; if (trace > 0) { int x; print("nandfs filesystem detected: base %lud limit %lud", baseblock, limitblock); for (x = 0; x < xcount; x++) print(" data%d %ld", x, xdata[x]); print("\n"); } blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData)); if (blockdata == nil) { errmsg = Enomem; goto error; } /* * sanity check * check the partition until 10 good blocks have been found * check that bad blocks represent 10% or less */ badones = goodones = 0; ppb = 1 << nandfs->ll.l2pagesperblock; for (u = baseblock; u < limitblock; u++) { LogfsLowLevelReadResult firste, laste; NandfsTags firsttags, lasttags; errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste); if (errmsg) goto error; errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste); if (errmsg) goto error; if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) continue; if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic && lasttags.magic == LogfsMagic) goodones++; else badones++; if (badones == 0 && goodones >= 10) break; } if (badones * 10 > goodones) { errmsg = "most likely not a Log Filesystem"; goto error; } for (u = baseblock; u < limitblock; u++) { int erased, partial; LogfsLowLevelReadResult firste, laste; NandfsTags firsttags, lasttags, newtags; int markedbad; errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste); if (errmsg) goto error; errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste); if (errmsg) goto error; if (trace > 1) print("%lud: ", u); if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) { if (trace > 1) print("bad\n"); blockdata[u - baseblock].tag = LogfsTbad; continue; } newtags = firsttags; erased = 0; partial = 0; if (firsttags.tag != lasttags.tag) { partial = 1; if (trace > 1) print("partially written\n"); /* * partially written block * if Tboot, then it is either * a failure during logfsformat() - well, we never got started, so give up * a failure during blocktransfer() - erase it as the transfer was not completed * tell the difference by the presence of another block with the same path * if Tnone, then it's a no brainer * if anything else, leave alone */ if (newtags.tag == LogfsTnone) { newtags.tag = LogfsTnone; newtags.path = NandfsPathMask; errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); if (errmsg) goto error; if (markedbad) { blockdata[u - baseblock].tag = LogfsTbad; continue; } /* now erased */ erased = 1; partial = 0; } } if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) { if (trace > 1) print("probably erased"); /* * finding erased blocks at this stage is a rare event, so * erase again just in case */ newtags.tag = LogfsTnone; newtags.path = NandfsPathMask; newtags.nerase = 1; // what do I do here? errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); if (errmsg) goto error; if (markedbad) { blockdata[u - baseblock].tag = LogfsTbad; continue; } erased = 1; } if (erased) { newtags.magic = 'V'; errmsg = nandfseraseblock(nandfs, u, nil, &markedbad); if (errmsg) goto error; if (markedbad) { blockdata[u - baseblock].tag = LogfsTbad; continue; } } switch (newtags.tag) { case LogfsTboot: case LogfsTnone: case LogfsTdata: case LogfsTlog: blockdata[u - baseblock].path = newtags.path; blockdata[u - baseblock].tag = newtags.tag; blockdata[u - baseblock].nerase = newtags.nerase; blockdata[u - baseblock].partial = partial; if (trace > 1) print("%s 0x%.8lux %lud\n", logfstagname(blockdata[u - baseblock].tag), blockdata[u - baseblock].path, blockdata[u - baseblock].nerase); continue; } break; } nandfs->ll.blocks = u - baseblock; nandfs->baseblock = baseblock; nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData)); if (nandfs->blockdata == nil) { errmsg = Enomem; goto error; } nandfs->trace = trace; memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks); nandfsfreemem(blockdata); if (trace > 0) print("nandfsopen: success\n"); return nil; error: nandfsfreemem(blockdata); return errmsg; }