forsyth20121205-174063a80cc13 years agoHistory
253 lines · 6.4 KB · C
RawDownload
#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;}