diff options
Diffstat (limited to 'libnandfs/open.c')
| -rw-r--r-- | libnandfs/open.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/libnandfs/open.c b/libnandfs/open.c new file mode 100644 index 00000000..12b49849 --- /dev/null +++ b/libnandfs/open.c @@ -0,0 +1,253 @@ +#include "lib9.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; +} |
