ref: a600cca5ff367ca7e7c64a14a8e87ba376780f6d
dir: /libnandfs/open.c/
#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;
}