summaryrefslogtreecommitdiff
path: root/libnandfs/open.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libnandfs/open.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libnandfs/open.c')
-rw-r--r--libnandfs/open.c253
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;
+}