xref: /inferno-os/libnandfs/open.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "logfs.h"
337da2899SCharles.Forsyth #include "nandfs.h"
437da2899SCharles.Forsyth #include "local.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth char *
nandfsopen(Nandfs * nandfs,long base,long limit,int trace,int xcount,long * xdata)737da2899SCharles.Forsyth nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata)
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth 	NandfsBlockData *blockdata = nil;
1037da2899SCharles.Forsyth 	long u;
1137da2899SCharles.Forsyth 	ulong badones, goodones;
1237da2899SCharles.Forsyth 	char *errmsg;
1337da2899SCharles.Forsyth 	long possiblebaseblock, possiblesize;
1437da2899SCharles.Forsyth 	long baseblock, limitblock;
1537da2899SCharles.Forsyth 	int ppb;
1637da2899SCharles.Forsyth 
1737da2899SCharles.Forsyth 	if (trace > 1)
1837da2899SCharles.Forsyth 		print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock);
1937da2899SCharles.Forsyth 
2037da2899SCharles.Forsyth 	if (nandfs->blockdata)
2137da2899SCharles.Forsyth 		return Eperm;
2237da2899SCharles.Forsyth 
2337da2899SCharles.Forsyth 	if (base % nandfs->rawblocksize)
2437da2899SCharles.Forsyth 		return Ebadarg;
2537da2899SCharles.Forsyth 	baseblock = base / nandfs->rawblocksize;
2637da2899SCharles.Forsyth 
2737da2899SCharles.Forsyth 	if (limit == 0)
2837da2899SCharles.Forsyth 		limitblock = nandfs->limitblock;
2937da2899SCharles.Forsyth 	else if (limit % nandfs->rawblocksize)
3037da2899SCharles.Forsyth 		return Ebadarg;
3137da2899SCharles.Forsyth 	else
3237da2899SCharles.Forsyth 		limitblock = limit / nandfs->rawblocksize;
3337da2899SCharles.Forsyth 
3437da2899SCharles.Forsyth 	if (trace > 1)
3537da2899SCharles.Forsyth 		print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock);
3637da2899SCharles.Forsyth 
3737da2899SCharles.Forsyth 	possiblebaseblock = 0;
3837da2899SCharles.Forsyth 	possiblesize = 0;
3937da2899SCharles.Forsyth 
4037da2899SCharles.Forsyth 	/*
4137da2899SCharles.Forsyth 	 * search for Tboot block which will reveal the parameters
4237da2899SCharles.Forsyth 	 */
4337da2899SCharles.Forsyth 	nandfs->baseblock = 0;
4437da2899SCharles.Forsyth 
4537da2899SCharles.Forsyth 	for (u = baseblock; u < limitblock; u++) {
4637da2899SCharles.Forsyth 		NandfsTags tags;
4737da2899SCharles.Forsyth 		LogfsLowLevelReadResult e;
4837da2899SCharles.Forsyth 		int p;
4937da2899SCharles.Forsyth 		int lim;
5037da2899SCharles.Forsyth 
5137da2899SCharles.Forsyth 		lim = xcount + 3;
5237da2899SCharles.Forsyth 
5337da2899SCharles.Forsyth 		for (p = 0; p < lim; p++) {
5437da2899SCharles.Forsyth 			errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e);
5537da2899SCharles.Forsyth 			if (errmsg)
5637da2899SCharles.Forsyth 				goto error;
5737da2899SCharles.Forsyth 			if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot)
5837da2899SCharles.Forsyth 				break;
5937da2899SCharles.Forsyth 			if (trace > 1)
6037da2899SCharles.Forsyth 				print("block %lud/%d: 0x%.lux\n", u, p, tags.path);
6137da2899SCharles.Forsyth 			switch (p) {
6237da2899SCharles.Forsyth 			case 1:
6337da2899SCharles.Forsyth 				possiblebaseblock = tags.path;
6437da2899SCharles.Forsyth 				break;
6537da2899SCharles.Forsyth 			case 2:
6637da2899SCharles.Forsyth 				possiblesize = tags.path;
6737da2899SCharles.Forsyth 				break;
6837da2899SCharles.Forsyth 			default:
6937da2899SCharles.Forsyth 				xdata[p - 3] = tags.path;
7037da2899SCharles.Forsyth 				break;
7137da2899SCharles.Forsyth 			}
7237da2899SCharles.Forsyth 		}
7337da2899SCharles.Forsyth 		if (p == lim)
7437da2899SCharles.Forsyth 			break;
7537da2899SCharles.Forsyth 	}
7637da2899SCharles.Forsyth 
7737da2899SCharles.Forsyth 	if (u >= limitblock) {
7837da2899SCharles.Forsyth 		errmsg = "no valid boot blocks found";
7937da2899SCharles.Forsyth 		goto error;
8037da2899SCharles.Forsyth 	}
8137da2899SCharles.Forsyth 
8237da2899SCharles.Forsyth 	if (possiblebaseblock < baseblock
8337da2899SCharles.Forsyth 		|| possiblebaseblock >= limitblock
8437da2899SCharles.Forsyth 		|| possiblebaseblock + possiblesize > limitblock
8537da2899SCharles.Forsyth 		|| possiblesize == 0) {
8637da2899SCharles.Forsyth 		errmsg = "embedded parameters out of range";
8737da2899SCharles.Forsyth 		goto error;
8837da2899SCharles.Forsyth 	}
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth 	baseblock = possiblebaseblock;
9137da2899SCharles.Forsyth 	limitblock = possiblebaseblock + possiblesize;
9237da2899SCharles.Forsyth 
9337da2899SCharles.Forsyth 	if (trace > 0) {
9437da2899SCharles.Forsyth 		int x;
9537da2899SCharles.Forsyth 		print("nandfs filesystem detected: base %lud limit %lud",
9637da2899SCharles.Forsyth 			baseblock, limitblock);
9737da2899SCharles.Forsyth 		for (x = 0; x < xcount; x++)
9837da2899SCharles.Forsyth 			print(" data%d %ld", x, xdata[x]);
9937da2899SCharles.Forsyth 		print("\n");
10037da2899SCharles.Forsyth 	}
10137da2899SCharles.Forsyth 
10237da2899SCharles.Forsyth 	blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData));
10337da2899SCharles.Forsyth 	if (blockdata == nil) {
10437da2899SCharles.Forsyth 		errmsg = Enomem;
10537da2899SCharles.Forsyth 		goto error;
10637da2899SCharles.Forsyth 	}
10737da2899SCharles.Forsyth 	/*
10837da2899SCharles.Forsyth 	 * sanity check
10937da2899SCharles.Forsyth 	 * check the partition until 10 good blocks have been found
11037da2899SCharles.Forsyth 	 * check that bad blocks represent 10% or less
11137da2899SCharles.Forsyth 	 */
11237da2899SCharles.Forsyth 
11337da2899SCharles.Forsyth 	badones = goodones = 0;
11437da2899SCharles.Forsyth 	ppb = 1 << nandfs->ll.l2pagesperblock;
11537da2899SCharles.Forsyth 	for (u = baseblock; u < limitblock; u++) {
11637da2899SCharles.Forsyth 		LogfsLowLevelReadResult firste, laste;
11737da2899SCharles.Forsyth 		NandfsTags firsttags, lasttags;
11837da2899SCharles.Forsyth 		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
11937da2899SCharles.Forsyth 		if (errmsg)
12037da2899SCharles.Forsyth 			goto error;
12137da2899SCharles.Forsyth 		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
12237da2899SCharles.Forsyth 		if (errmsg)
12337da2899SCharles.Forsyth 			goto error;
12437da2899SCharles.Forsyth 		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad)
12537da2899SCharles.Forsyth 			continue;
12637da2899SCharles.Forsyth 		if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic &&
12737da2899SCharles.Forsyth 			lasttags.magic == LogfsMagic)
12837da2899SCharles.Forsyth 			goodones++;
12937da2899SCharles.Forsyth 		else
13037da2899SCharles.Forsyth 			badones++;
13137da2899SCharles.Forsyth 		if (badones == 0 && goodones >= 10)
13237da2899SCharles.Forsyth 			break;
13337da2899SCharles.Forsyth 	}
13437da2899SCharles.Forsyth 
13537da2899SCharles.Forsyth 	if (badones * 10 > goodones) {
13637da2899SCharles.Forsyth 		errmsg = "most likely not a Log Filesystem";
13737da2899SCharles.Forsyth 		goto error;
13837da2899SCharles.Forsyth 	}
13937da2899SCharles.Forsyth 
14037da2899SCharles.Forsyth 	for (u = baseblock; u < limitblock; u++) {
14137da2899SCharles.Forsyth 		int erased, partial;
14237da2899SCharles.Forsyth 		LogfsLowLevelReadResult firste, laste;
14337da2899SCharles.Forsyth 		NandfsTags firsttags, lasttags, newtags;
14437da2899SCharles.Forsyth 		int markedbad;
14537da2899SCharles.Forsyth 		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
14637da2899SCharles.Forsyth 		if (errmsg)
14737da2899SCharles.Forsyth 			goto error;
14837da2899SCharles.Forsyth 		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
14937da2899SCharles.Forsyth 		if (errmsg)
15037da2899SCharles.Forsyth 			goto error;
15137da2899SCharles.Forsyth 		if (trace > 1)
15237da2899SCharles.Forsyth 			print("%lud: ", u);
15337da2899SCharles.Forsyth 		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) {
15437da2899SCharles.Forsyth 			if (trace > 1)
15537da2899SCharles.Forsyth 				print("bad\n");
15637da2899SCharles.Forsyth 			blockdata[u - baseblock].tag = LogfsTbad;
15737da2899SCharles.Forsyth 			continue;
15837da2899SCharles.Forsyth 		}
15937da2899SCharles.Forsyth 		newtags = firsttags;
16037da2899SCharles.Forsyth 		erased = 0;
16137da2899SCharles.Forsyth 		partial = 0;
16237da2899SCharles.Forsyth 		if (firsttags.tag != lasttags.tag) {
16337da2899SCharles.Forsyth 			partial = 1;
16437da2899SCharles.Forsyth 			if (trace > 1)
16537da2899SCharles.Forsyth 				print("partially written\n");
16637da2899SCharles.Forsyth 			/*
16737da2899SCharles.Forsyth 			 * partially written block
16837da2899SCharles.Forsyth 			 * if Tboot, then it is either
16937da2899SCharles.Forsyth 			 * 	a failure during logfsformat() - well, we never got started, so give up
17037da2899SCharles.Forsyth 			 *	a failure during blocktransfer() - erase it as the transfer was not completed
17137da2899SCharles.Forsyth 			 *	tell the difference by the presence of another block with the same path
17237da2899SCharles.Forsyth 			 * if Tnone, then it's a no brainer
17337da2899SCharles.Forsyth 			 * if anything else, leave alone
17437da2899SCharles.Forsyth 			 */
17537da2899SCharles.Forsyth 			if (newtags.tag == LogfsTnone) {
17637da2899SCharles.Forsyth 				newtags.tag = LogfsTnone;
17737da2899SCharles.Forsyth 				newtags.path = NandfsPathMask;
17837da2899SCharles.Forsyth 				errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
17937da2899SCharles.Forsyth 				if (errmsg)
18037da2899SCharles.Forsyth 					goto error;
18137da2899SCharles.Forsyth 				if (markedbad) {
18237da2899SCharles.Forsyth 					blockdata[u - baseblock].tag = LogfsTbad;
18337da2899SCharles.Forsyth 					continue;
18437da2899SCharles.Forsyth 				}
18537da2899SCharles.Forsyth 				/* now erased */
18637da2899SCharles.Forsyth 				erased = 1;
18737da2899SCharles.Forsyth 				partial = 0;
18837da2899SCharles.Forsyth 			}
18937da2899SCharles.Forsyth 		}
19037da2899SCharles.Forsyth 		if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) {
19137da2899SCharles.Forsyth 			if (trace > 1)
19237da2899SCharles.Forsyth 				print("probably erased");
19337da2899SCharles.Forsyth 			/*
19437da2899SCharles.Forsyth 			 * finding erased blocks at this stage is a rare event, so
19537da2899SCharles.Forsyth 			 * erase again just in case
19637da2899SCharles.Forsyth 			 */
19737da2899SCharles.Forsyth 			newtags.tag = LogfsTnone;
19837da2899SCharles.Forsyth 			newtags.path = NandfsPathMask;
19937da2899SCharles.Forsyth 			newtags.nerase = 1;		// what do I do here?
20037da2899SCharles.Forsyth 			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
20137da2899SCharles.Forsyth 			if (errmsg)
20237da2899SCharles.Forsyth 				goto error;
20337da2899SCharles.Forsyth 			if (markedbad) {
20437da2899SCharles.Forsyth 				blockdata[u - baseblock].tag = LogfsTbad;
20537da2899SCharles.Forsyth 				continue;
20637da2899SCharles.Forsyth 			}
20737da2899SCharles.Forsyth 			erased = 1;
20837da2899SCharles.Forsyth 		}
20937da2899SCharles.Forsyth 		if (erased) {
21037da2899SCharles.Forsyth 			newtags.magic = 'V';
21137da2899SCharles.Forsyth 			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
21237da2899SCharles.Forsyth 			if (errmsg)
21337da2899SCharles.Forsyth 				goto error;
21437da2899SCharles.Forsyth 			if (markedbad) {
21537da2899SCharles.Forsyth 				blockdata[u - baseblock].tag = LogfsTbad;
21637da2899SCharles.Forsyth 				continue;
21737da2899SCharles.Forsyth 			}
21837da2899SCharles.Forsyth 		}
21937da2899SCharles.Forsyth 		switch (newtags.tag) {
22037da2899SCharles.Forsyth 		case LogfsTboot:
22137da2899SCharles.Forsyth 		case LogfsTnone:
22237da2899SCharles.Forsyth 		case LogfsTdata:
22337da2899SCharles.Forsyth 		case LogfsTlog:
22437da2899SCharles.Forsyth 			blockdata[u - baseblock].path = newtags.path;
22537da2899SCharles.Forsyth 			blockdata[u - baseblock].tag = newtags.tag;
22637da2899SCharles.Forsyth 			blockdata[u - baseblock].nerase = newtags.nerase;
22737da2899SCharles.Forsyth 			blockdata[u - baseblock].partial = partial;
22837da2899SCharles.Forsyth 			if (trace > 1)
22937da2899SCharles.Forsyth 				print("%s 0x%.8lux %lud\n",
23037da2899SCharles.Forsyth 					logfstagname(blockdata[u - baseblock].tag),
23137da2899SCharles.Forsyth 					blockdata[u - baseblock].path,
23237da2899SCharles.Forsyth 					blockdata[u - baseblock].nerase);
23337da2899SCharles.Forsyth 			continue;
23437da2899SCharles.Forsyth 		}
23537da2899SCharles.Forsyth 		break;
23637da2899SCharles.Forsyth 	}
23737da2899SCharles.Forsyth 	nandfs->ll.blocks = u - baseblock;
23837da2899SCharles.Forsyth 	nandfs->baseblock = baseblock;
23937da2899SCharles.Forsyth 	nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData));
24037da2899SCharles.Forsyth 	if (nandfs->blockdata == nil) {
24137da2899SCharles.Forsyth 		errmsg = Enomem;
24237da2899SCharles.Forsyth 		goto error;
24337da2899SCharles.Forsyth 	}
24437da2899SCharles.Forsyth 	nandfs->trace = trace;
24537da2899SCharles.Forsyth 	memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks);
24637da2899SCharles.Forsyth 	nandfsfreemem(blockdata);
24737da2899SCharles.Forsyth 	if (trace > 0)
24837da2899SCharles.Forsyth 		print("nandfsopen: success\n");
24937da2899SCharles.Forsyth 	return nil;
25037da2899SCharles.Forsyth error:
25137da2899SCharles.Forsyth 	nandfsfreemem(blockdata);
25237da2899SCharles.Forsyth 	return errmsg;
25337da2899SCharles.Forsyth }
254