xref: /inferno-os/libnandfs/open.c (revision dea4b9f1bb02529d02b0389c1f6b0e514ed7deff)
1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "nandfs.h"
4 #include "local.h"
5 
6 char *
7 nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata)
8 {
9 	NandfsBlockData *blockdata = nil;
10 	long u;
11 	ulong badones, goodones;
12 	char *errmsg;
13 	long possiblebaseblock, possiblesize;
14 	long baseblock, limitblock;
15 	int ppb;
16 
17 	if (trace > 1)
18 		print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock);
19 
20 	if (nandfs->blockdata)
21 		return Eperm;
22 
23 	if (base % nandfs->rawblocksize)
24 		return Ebadarg;
25 	baseblock = base / nandfs->rawblocksize;
26 
27 	if (limit == 0)
28 		limitblock = nandfs->limitblock;
29 	else if (limit % nandfs->rawblocksize)
30 		return Ebadarg;
31 	else
32 		limitblock = limit / nandfs->rawblocksize;
33 
34 	if (trace > 1)
35 		print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock);
36 
37 	possiblebaseblock = 0;
38 	possiblesize = 0;
39 
40 	/*
41 	 * search for Tboot block which will reveal the parameters
42 	 */
43 	nandfs->baseblock = 0;
44 
45 	for (u = baseblock; u < limitblock; u++) {
46 		NandfsTags tags;
47 		LogfsLowLevelReadResult e;
48 		int p;
49 		int lim;
50 
51 		lim = xcount + 3;
52 
53 		for (p = 0; p < lim; p++) {
54 			errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e);
55 			if (errmsg)
56 				goto error;
57 			if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot)
58 				break;
59 			if (trace > 1)
60 				print("block %lud/%d: 0x%.lux\n", u, p, tags.path);
61 			switch (p) {
62 			case 1:
63 				possiblebaseblock = tags.path;
64 				break;
65 			case 2:
66 				possiblesize = tags.path;
67 				break;
68 			default:
69 				xdata[p - 3] = tags.path;
70 				break;
71 			}
72 		}
73 		if (p == lim)
74 			break;
75 	}
76 
77 	if (u >= limitblock) {
78 		errmsg = "no valid boot blocks found";
79 		goto error;
80 	}
81 
82 	if (possiblebaseblock < baseblock
83 		|| possiblebaseblock >= limitblock
84 		|| possiblebaseblock + possiblesize > limitblock
85 		|| possiblesize == 0) {
86 		errmsg = "embedded parameters out of range";
87 		goto error;
88 	}
89 
90 	baseblock = possiblebaseblock;
91 	limitblock = possiblebaseblock + possiblesize;
92 
93 	if (trace > 0) {
94 		int x;
95 		print("nandfs filesystem detected: base %lud limit %lud",
96 			baseblock, limitblock);
97 		for (x = 0; x < xcount; x++)
98 			print(" data%d %ld", x, xdata[x]);
99 		print("\n");
100 	}
101 
102 	blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData));
103 	if (blockdata == nil) {
104 		errmsg = Enomem;
105 		goto error;
106 	}
107 	/*
108 	 * sanity check
109 	 * check the partition until 10 good blocks have been found
110 	 * check that bad blocks represent 10% or less
111 	 */
112 
113 	badones = goodones = 0;
114 	ppb = 1 << nandfs->ll.l2pagesperblock;
115 	for (u = baseblock; u < limitblock; u++) {
116 		LogfsLowLevelReadResult firste, laste;
117 		NandfsTags firsttags, lasttags;
118 		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
119 		if (errmsg)
120 			goto error;
121 		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
122 		if (errmsg)
123 			goto error;
124 		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad)
125 			continue;
126 		if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic &&
127 			lasttags.magic == LogfsMagic)
128 			goodones++;
129 		else
130 			badones++;
131 		if (badones == 0 && goodones >= 10)
132 			break;
133 	}
134 
135 	if (badones * 10 > goodones) {
136 		errmsg = "most likely not a Log Filesystem";
137 		goto error;
138 	}
139 
140 	for (u = baseblock; u < limitblock; u++) {
141 		int erased, partial;
142 		LogfsLowLevelReadResult firste, laste;
143 		NandfsTags firsttags, lasttags, newtags;
144 		int markedbad;
145 		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
146 		if (errmsg)
147 			goto error;
148 		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
149 		if (errmsg)
150 			goto error;
151 		if (trace > 1)
152 			print("%lud: ", u);
153 		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) {
154 			if (trace > 1)
155 				print("bad\n");
156 			blockdata[u - baseblock].tag = LogfsTbad;
157 			continue;
158 		}
159 		newtags = firsttags;
160 		erased = 0;
161 		partial = 0;
162 		if (firsttags.tag != lasttags.tag) {
163 			partial = 1;
164 			if (trace > 1)
165 				print("partially written\n");
166 			/*
167 			 * partially written block
168 			 * if Tboot, then it is either
169 			 * 	a failure during logfsformat() - well, we never got started, so give up
170 			 *	a failure during blocktransfer() - erase it as the transfer was not completed
171 			 *	tell the difference by the presence of another block with the same path
172 			 * if Tnone, then it's a no brainer
173 			 * if anything else, leave alone
174 			 */
175 			if (newtags.tag == LogfsTnone) {
176 				newtags.tag = LogfsTnone;
177 				newtags.path = NandfsPathMask;
178 				errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
179 				if (errmsg)
180 					goto error;
181 				if (markedbad) {
182 					blockdata[u - baseblock].tag = LogfsTbad;
183 					continue;
184 				}
185 				/* now erased */
186 				erased = 1;
187 				partial = 0;
188 			}
189 		}
190 		if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) {
191 			if (trace > 1)
192 				print("probably erased");
193 			/*
194 			 * finding erased blocks at this stage is a rare event, so
195 			 * erase again just in case
196 			 */
197 			newtags.tag = LogfsTnone;
198 			newtags.path = NandfsPathMask;
199 			newtags.nerase = 1;		// what do I do here?
200 			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
201 			if (errmsg)
202 				goto error;
203 			if (markedbad) {
204 				blockdata[u - baseblock].tag = LogfsTbad;
205 				continue;
206 			}
207 			erased = 1;
208 		}
209 		if (erased) {
210 			newtags.magic = 'V';
211 			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
212 			if (errmsg)
213 				goto error;
214 			if (markedbad) {
215 				blockdata[u - baseblock].tag = LogfsTbad;
216 				continue;
217 			}
218 		}
219 		switch (newtags.tag) {
220 		case LogfsTboot:
221 		case LogfsTnone:
222 		case LogfsTdata:
223 		case LogfsTlog:
224 			blockdata[u - baseblock].path = newtags.path;
225 			blockdata[u - baseblock].tag = newtags.tag;
226 			blockdata[u - baseblock].nerase = newtags.nerase;
227 			blockdata[u - baseblock].partial = partial;
228 			if (trace > 1)
229 				print("%s 0x%.8lux %lud\n",
230 					logfstagname(blockdata[u - baseblock].tag),
231 					blockdata[u - baseblock].path,
232 					blockdata[u - baseblock].nerase);
233 			continue;
234 		}
235 		break;
236 	}
237 	nandfs->ll.blocks = u - baseblock;
238 	nandfs->baseblock = baseblock;
239 	nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData));
240 	if (nandfs->blockdata == nil) {
241 		errmsg = Enomem;
242 		goto error;
243 	}
244 	nandfs->trace = trace;
245 	memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks);
246 	nandfsfreemem(blockdata);
247 	if (trace > 0)
248 		print("nandfsopen: success\n");
249 	return nil;
250 error:
251 	nandfsfreemem(blockdata);
252 	return errmsg;
253 }
254