1 | /************************************************************************** |
---|
2 | * |
---|
3 | * Copyright (c) 2013 Alcatel-Lucent |
---|
4 | * |
---|
5 | * Alcatel Lucent licenses this file to You under the Apache License, |
---|
6 | * Version 2.0 (the "License"); you may not use this file except in |
---|
7 | * compliance with the License. A copy of the License is contained the |
---|
8 | * file LICENSE at the top level of this repository. |
---|
9 | * You may also obtain a copy of the License at: |
---|
10 | * |
---|
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
12 | * |
---|
13 | * Unless required by applicable law or agreed to in writing, software |
---|
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
16 | * See the License for the specific language governing permissions and |
---|
17 | * limitations under the License. |
---|
18 | * |
---|
19 | ************************************************************************** |
---|
20 | * |
---|
21 | * tfsclean1.c: |
---|
22 | * |
---|
23 | * This is one of several different versions of tfsclean(). This version |
---|
24 | * is by far the most complex, but offers power-hit safety and minimal |
---|
25 | * flash overhead. It uses a "spare" sector to backup the |
---|
26 | * "one-sector-at-a-time" defragmentation process. |
---|
27 | * |
---|
28 | * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) |
---|
29 | * |
---|
30 | */ |
---|
31 | #include "config.h" |
---|
32 | #include "cpu.h" |
---|
33 | #include "stddefs.h" |
---|
34 | #include "genlib.h" |
---|
35 | #include "tfs.h" |
---|
36 | #include "tfsprivate.h" |
---|
37 | #include "flash.h" |
---|
38 | #include "monflags.h" |
---|
39 | #include "warmstart.h" |
---|
40 | |
---|
41 | #if INCLUDE_TFS |
---|
42 | |
---|
43 | #if !INCLUDE_FLASH |
---|
44 | #error: If flash is not included, then use tfsclean2.c |
---|
45 | #endif |
---|
46 | |
---|
47 | #if DEFRAG_TEST_ENABLED |
---|
48 | void |
---|
49 | defragExitTestPoint(int val) |
---|
50 | { |
---|
51 | if ((DefragTestType == DEFRAG_TEST_EXIT) && (DefragTestPoint == val)) { |
---|
52 | printf("\n+++++++++ EXIT @ TEST POINT(%d)\n",val); |
---|
53 | CommandLoop(); |
---|
54 | } |
---|
55 | } |
---|
56 | #else |
---|
57 | #define defragExitTestPoint(val) |
---|
58 | #endif |
---|
59 | |
---|
60 | /* Variables for testing tfsclean(): |
---|
61 | * They are set up through arguments to "tfs clean" in tfscli.c. |
---|
62 | */ |
---|
63 | int DefragTestType; |
---|
64 | int DefragTestPoint; |
---|
65 | int DefragTestSector; |
---|
66 | |
---|
67 | /* defragTick(): |
---|
68 | * Used to show progress, just to let the user know that we aren't |
---|
69 | * dead in the water. |
---|
70 | */ |
---|
71 | static void |
---|
72 | defragTick(int verbose) |
---|
73 | { |
---|
74 | static int tick; |
---|
75 | static char clockhand[] = { '|', '/', '-', '\\' }; |
---|
76 | |
---|
77 | if (!verbose && (!MFLAGS_NODEFRAGPRN())) { |
---|
78 | if (tick > 3) |
---|
79 | tick = 0; |
---|
80 | printf("%c\b",clockhand[tick++]); |
---|
81 | } |
---|
82 | } |
---|
83 | |
---|
84 | /* defragCrcTable(): |
---|
85 | * Return a pointer to the crc table for the specified TFS device. |
---|
86 | */ |
---|
87 | struct sectorcrc * |
---|
88 | defragCrcTable(TDEV *tdp) |
---|
89 | { |
---|
90 | return((struct sectorcrc *)(tdp->end+1) - tdp->sectorcount); |
---|
91 | } |
---|
92 | |
---|
93 | /* defragSerase(): |
---|
94 | * Common function to call from within tfsclean() to erase a sector |
---|
95 | * and generate an error message if necessary. |
---|
96 | * |
---|
97 | * If DEFRAG_TEST_ENABLED is defined and the type/sector/point criteria |
---|
98 | * is met, then instead of erasing the sector; just change the first non-zero |
---|
99 | * byte to zero to corrupt it. This essentially makes it a corrupted erase. |
---|
100 | */ |
---|
101 | static int |
---|
102 | defragSerase(int tag, int snum) |
---|
103 | { |
---|
104 | int ret = 0; |
---|
105 | |
---|
106 | #if DEFRAG_TEST_ENABLED |
---|
107 | int ssize; |
---|
108 | uchar *sbase, *send, zero; |
---|
109 | |
---|
110 | printf(" serase_%02d(%02d)\n",tag,snum); |
---|
111 | |
---|
112 | if ((DefragTestType == DEFRAG_TEST_SERASE) && |
---|
113 | (DefragTestSector == snum) && (DefragTestPoint == tag)) { |
---|
114 | sectortoaddr(snum,&ssize,&sbase); |
---|
115 | send = sbase+ssize; |
---|
116 | zero = 0; |
---|
117 | while(sbase < send) { |
---|
118 | if (*sbase != 0) { |
---|
119 | tfsflashwrite((ulong *)sbase,(ulong *)&zero,1); |
---|
120 | break; |
---|
121 | } |
---|
122 | sbase++; |
---|
123 | } |
---|
124 | printf("DEFRAG_TEST_SERASE activated @ %d sector %d\n",tag,snum); |
---|
125 | CommandLoop(); |
---|
126 | } |
---|
127 | else |
---|
128 | #endif |
---|
129 | ret = tfsflasherase(snum); |
---|
130 | if (ret <= 0) { |
---|
131 | printf("tfsclean() serase erase failed: %d,%d,%d\n",snum,tag,ret); |
---|
132 | } |
---|
133 | return(ret); |
---|
134 | } |
---|
135 | |
---|
136 | /* defragFwrite(): |
---|
137 | * Common function to call from within tfsclean() to write to flash |
---|
138 | * and generate an error message if necessary. |
---|
139 | * If DEFRAG_TEST_ENABLED is defined and the test type is set to |
---|
140 | * DEFRAG_TEST_FWRITE, then use APPRAMBASE as the source of the data |
---|
141 | * so that the end result is an errored flash write. |
---|
142 | */ |
---|
143 | static int |
---|
144 | defragFwrite(int tag, uchar *dest,uchar *src,int size) |
---|
145 | { |
---|
146 | int ret = 0; |
---|
147 | |
---|
148 | #if DEFRAG_TEST_ENABLED |
---|
149 | int snum; |
---|
150 | |
---|
151 | addrtosector((char *)dest,&snum,0,0); |
---|
152 | printf(" fwrite_%02d(%d,0x%lx,0x%lx,%d)\n", |
---|
153 | tag,snum,(ulong)dest,(ulong)src,size); |
---|
154 | |
---|
155 | if ((DefragTestType == DEFRAG_TEST_FWRITE) && |
---|
156 | (DefragTestSector == snum) && (DefragTestPoint == tag)) { |
---|
157 | tfsflashwrite((ulong *)dest,(ulong *)getAppRamStart(),size/2); |
---|
158 | printf("DEFRAG_TEST_FWRITE activated @ %d sector %d\n",tag,snum); |
---|
159 | CommandLoop(); |
---|
160 | } |
---|
161 | else |
---|
162 | #endif |
---|
163 | ret = tfsflashwrite(dest,src,size); |
---|
164 | if (ret != TFS_OKAY) { |
---|
165 | printf("tfsclean() fwrite failed: 0x%lx,0x%lx,%d,%d\n", |
---|
166 | (ulong)dest,(ulong)src,size,tag); |
---|
167 | } |
---|
168 | return(ret); |
---|
169 | } |
---|
170 | |
---|
171 | /* defragGetSpantype(): |
---|
172 | * With the incoming sector base and end (s_base, s_end), |
---|
173 | * determine the type of span that the incoming file (f_base, f_end) |
---|
174 | * has across it. There are six different ways the spanning can |
---|
175 | * occur: |
---|
176 | * 1. begin and end in previous active sector (bpep); |
---|
177 | * 2. begin in previously active sector, end in this one (bpec); |
---|
178 | * 3. begin in previously active sector, end in later one (bpel); |
---|
179 | * 4. begin and end in this active sector (bcec); |
---|
180 | * 5. begin in this active sector, end in later one (bcel); |
---|
181 | * 6. begin and end in later active sector (blel); |
---|
182 | */ |
---|
183 | static int |
---|
184 | defragGetSpantype(char *s_base,char *s_end,char *f_base,char *f_end) |
---|
185 | { |
---|
186 | int spantype; |
---|
187 | |
---|
188 | if (f_base < s_base) { |
---|
189 | if ((f_end > s_base) && (f_end <= s_end)) |
---|
190 | spantype = SPANTYPE_BPEC; |
---|
191 | else if (f_end > s_end) |
---|
192 | spantype = SPANTYPE_BPEL; |
---|
193 | else |
---|
194 | spantype = SPANTYPE_BPEP; |
---|
195 | } |
---|
196 | else { |
---|
197 | if (f_base > s_end) |
---|
198 | spantype = SPANTYPE_BLEL; |
---|
199 | else if (f_end <= s_end) |
---|
200 | spantype = SPANTYPE_BCEC; |
---|
201 | else |
---|
202 | spantype = SPANTYPE_BCEL; |
---|
203 | } |
---|
204 | return(spantype); |
---|
205 | } |
---|
206 | |
---|
207 | /* defragGetSpantypeStr(): |
---|
208 | * Return a string that corresponds to the incoming state value. |
---|
209 | */ |
---|
210 | static char * |
---|
211 | defragGetSpantypeStr(int spantype) |
---|
212 | { |
---|
213 | char *str; |
---|
214 | |
---|
215 | switch(spantype) { |
---|
216 | case SPANTYPE_BPEC: |
---|
217 | str = "BPEC"; |
---|
218 | break; |
---|
219 | case SPANTYPE_BLEL: |
---|
220 | str = "BLEL"; |
---|
221 | break; |
---|
222 | case SPANTYPE_BPEL: |
---|
223 | str = "BPEL"; |
---|
224 | break; |
---|
225 | case SPANTYPE_BPEP: |
---|
226 | str = "BPEP"; |
---|
227 | break; |
---|
228 | case SPANTYPE_BCEC: |
---|
229 | str = "BCEC"; |
---|
230 | break; |
---|
231 | case SPANTYPE_BCEL: |
---|
232 | str = "BCEL"; |
---|
233 | break; |
---|
234 | default: |
---|
235 | str = "???"; |
---|
236 | break; |
---|
237 | } |
---|
238 | return(str); |
---|
239 | } |
---|
240 | |
---|
241 | /* defragEraseSpare(): |
---|
242 | * Erase the spare sector associated with the incoming TFS device. |
---|
243 | * The underlying flash driver SHOULD have a check so that it only |
---|
244 | * erases the sector if the sector is not already erased, so this |
---|
245 | * extra check (call to flasherased()) may not be necessary in |
---|
246 | * most cases. |
---|
247 | */ |
---|
248 | static int |
---|
249 | defragEraseSpare(TDEV *tdp) |
---|
250 | { |
---|
251 | int snum, ssize; |
---|
252 | uchar *sbase; |
---|
253 | |
---|
254 | if (addrtosector((unsigned char *)tdp->spare,&snum,&ssize,&sbase) < 0) |
---|
255 | return(TFSERR_FLASHFAILURE); |
---|
256 | |
---|
257 | if (!flasherased(sbase,sbase+(ssize-1))) { |
---|
258 | if (defragSerase(1,snum) < 0) { |
---|
259 | return(TFSERR_FLASHFAILURE); |
---|
260 | } |
---|
261 | } |
---|
262 | return(TFS_OKAY); |
---|
263 | } |
---|
264 | |
---|
265 | /* defragValidDSI(): |
---|
266 | * Test to see if we have a valid defrag state information (DSI) |
---|
267 | * area. The DSI area, working back from tdp->end, consists of a |
---|
268 | * table of 32-bit crcs (one per sector), a table of defraghdr |
---|
269 | * structures (one per active file) and a 32-bit crc of the DSI |
---|
270 | * itself. Knowing this format, we can easily step backwards into |
---|
271 | * the DSI space to see if it all makes sense. |
---|
272 | * If the table is 100% valid, then we will be able to step |
---|
273 | * backwards through the DSI to find the 32-bit crc of the DSI area. |
---|
274 | * If it matches, then we can be sure that the DSI is valid. |
---|
275 | * Return total number of files in header if the defrag header |
---|
276 | * table appears to be sane, else 0. |
---|
277 | */ |
---|
278 | static int |
---|
279 | defragValidDSI(TDEV *tdp, struct sectorcrc **scp) |
---|
280 | { |
---|
281 | int ftot, valid, lastssize; |
---|
282 | uchar *lastsbase; |
---|
283 | struct sectorcrc *crctbl; |
---|
284 | ulong hdrcrc, *crc; |
---|
285 | struct defraghdr *dhp, dfhcpy; |
---|
286 | |
---|
287 | ftot = valid = 0; |
---|
288 | crctbl = defragCrcTable(tdp); |
---|
289 | dhp = (struct defraghdr *)crctbl - 1; |
---|
290 | /* next line was <dfhcpy = *dhp> ... */ |
---|
291 | memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr)); |
---|
292 | hdrcrc = dfhcpy.crc; |
---|
293 | dfhcpy.crc = 0; |
---|
294 | if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) { |
---|
295 | ftot = dhp->idx + 1; |
---|
296 | dhp = (struct defraghdr *)crctbl - ftot; |
---|
297 | crc = (ulong *)dhp - 1; |
---|
298 | if (crc32((uchar *)dhp,(uchar *)tdp->end-(uchar *)dhp) == *crc) { |
---|
299 | if (scp) |
---|
300 | *scp = crctbl; |
---|
301 | return(ftot); |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | /* It's possible that the DSI space has been relocated to the spare |
---|
306 | * sector, so check for that here... |
---|
307 | */ |
---|
308 | addrtosector((unsigned char *)tdp->end,0,&lastssize,&lastsbase); |
---|
309 | |
---|
310 | crctbl = ((struct sectorcrc *)(tdp->spare+lastssize) - tdp->sectorcount); |
---|
311 | dhp = (struct defraghdr *)crctbl - 1; |
---|
312 | /* next line was <dfhcpy = *dhp> ... */ |
---|
313 | memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr)); |
---|
314 | hdrcrc = dfhcpy.crc; |
---|
315 | dfhcpy.crc = 0; |
---|
316 | if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) { |
---|
317 | ftot = dhp->idx + 1; |
---|
318 | dhp = (struct defraghdr *)crctbl - ftot; |
---|
319 | crc = (ulong *)dhp - 1; |
---|
320 | if (crc32((uchar *)dhp, |
---|
321 | (uchar *)(tdp->spare+lastssize-1) - (uchar *)dhp) == *crc) { |
---|
322 | #if DEFRAG_TEST_ENABLED |
---|
323 | printf("TFS: DSI in spare\n"); |
---|
324 | #endif |
---|
325 | if (scp) |
---|
326 | *scp = crctbl; |
---|
327 | return(ftot); |
---|
328 | } |
---|
329 | } |
---|
330 | return(0); |
---|
331 | } |
---|
332 | |
---|
333 | /* defragSectorInSpare(): |
---|
334 | * For each sector, run a CRC32 on the content of the spare |
---|
335 | * using the size of the sector in question. If the calculated |
---|
336 | * crc matches that of the table, then we have located the sector |
---|
337 | * that has been copied to the spare. |
---|
338 | * This is a pain in the butt because we can't just run a CRC32 on |
---|
339 | * the spare sector itself because the size of the spare may not match |
---|
340 | * the size of the sector that was copied to it. The source sector |
---|
341 | * might have been smaller; hence when we calculate the CRC32, we need |
---|
342 | * to use the size of the potential source sector. |
---|
343 | */ |
---|
344 | static int |
---|
345 | defragSectorInSpare(TDEV *tdp, struct sectorcrc *crctbl) |
---|
346 | { |
---|
347 | uchar *sbase; |
---|
348 | struct defraghdr *dhp; |
---|
349 | int i, ssize, snum, ftot; |
---|
350 | |
---|
351 | sbase = (uchar *)tdp->start; |
---|
352 | dhp = (struct defraghdr *)crctbl - 1; |
---|
353 | ftot = dhp->idx + 1; |
---|
354 | |
---|
355 | for(i=0;i<tdp->sectorcount;i++) { |
---|
356 | addrtosector(sbase,&snum,&ssize,0); |
---|
357 | if (i == tdp->sectorcount - 1) { |
---|
358 | ssize -= /* CRC table */ |
---|
359 | (tdp->sectorcount * sizeof(struct sectorcrc)); |
---|
360 | ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ |
---|
361 | ssize -= 4; /* Crc of the tables */ |
---|
362 | } |
---|
363 | if (crc32((uchar *)tdp->spare,ssize) == crctbl[i].precrc) |
---|
364 | return(snum); |
---|
365 | sbase += ssize; |
---|
366 | } |
---|
367 | return(-1); |
---|
368 | } |
---|
369 | |
---|
370 | /* defragTouchedSectors(): |
---|
371 | * Step through the crc table and TFS flash space to find the first |
---|
372 | * and last sectors that have been touched by defragmentation. |
---|
373 | * This is used by defragGetState() to recover from an interrupted |
---|
374 | * defragmentation, so a few verbose messages are useful to indicate |
---|
375 | * status to the user. |
---|
376 | */ |
---|
377 | void |
---|
378 | defragTouchedSectors(TDEV *tdp,int *first, int *last) |
---|
379 | { |
---|
380 | uchar *sbase; |
---|
381 | struct defraghdr *dhp; |
---|
382 | struct sectorcrc *crctbl; |
---|
383 | int i, ssize, snum, ftot; |
---|
384 | |
---|
385 | *first = -1; |
---|
386 | *last = -1; |
---|
387 | sbase = (uchar *)tdp->start; |
---|
388 | crctbl = defragCrcTable(tdp); |
---|
389 | dhp = (struct defraghdr *)crctbl - 1; |
---|
390 | ftot = dhp->idx + 1; |
---|
391 | |
---|
392 | printf("TFS: calculating per-sector crcs... "); |
---|
393 | for(i=0;i<tdp->sectorcount;i++) { |
---|
394 | addrtosector(sbase,&snum,&ssize,0); |
---|
395 | if (i == tdp->sectorcount - 1) { |
---|
396 | ssize -= /* CRC table */ |
---|
397 | (tdp->sectorcount * sizeof(struct sectorcrc)); |
---|
398 | ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ |
---|
399 | ssize -= 4; /* Crc of the tables */ |
---|
400 | } |
---|
401 | if (crc32(sbase,ssize) != crctbl[i].precrc) { |
---|
402 | if (*first == -1) |
---|
403 | *first = snum; |
---|
404 | *last = snum; |
---|
405 | } |
---|
406 | sbase += ssize; |
---|
407 | defragTick(0); |
---|
408 | } |
---|
409 | printf("done\n"); |
---|
410 | return; |
---|
411 | } |
---|
412 | |
---|
413 | /* defragPostCrcCheck(): |
---|
414 | * Return 1 if the post-crc check of the incoming sector number passes; |
---|
415 | * else 0. |
---|
416 | */ |
---|
417 | int |
---|
418 | defragPostCrcCheck(TDEV *tdp, int isnum) |
---|
419 | { |
---|
420 | uchar *sbase; |
---|
421 | struct defraghdr *dhp; |
---|
422 | struct sectorcrc *crctbl; |
---|
423 | int ftot, i, snum, ssize, lastsnum, lastssize; |
---|
424 | |
---|
425 | sbase = (uchar *)tdp->start; |
---|
426 | crctbl = defragCrcTable(tdp); |
---|
427 | dhp = (struct defraghdr *)crctbl - 1; |
---|
428 | ftot = dhp->idx + 1; |
---|
429 | |
---|
430 | addrtosector((uchar *)tdp->end,&lastsnum,&lastssize,0); |
---|
431 | |
---|
432 | for(i=0;i<tdp->sectorcount;i++) { |
---|
433 | addrtosector(sbase,&snum,&ssize,0); |
---|
434 | if (snum == isnum) |
---|
435 | break; |
---|
436 | sbase += ssize; |
---|
437 | } |
---|
438 | if (isnum == lastsnum) { |
---|
439 | ssize -= (tdp->sectorcount * sizeof(struct sectorcrc)); |
---|
440 | ssize -= (ftot * DEFRAGHDRSIZ); |
---|
441 | ssize -= 4; |
---|
442 | } |
---|
443 | if (crctbl[i].postcrc == crc32(sbase,ssize)) |
---|
444 | return(1); |
---|
445 | else |
---|
446 | return(0); |
---|
447 | } |
---|
448 | |
---|
449 | /* defragGetStateStr(): |
---|
450 | * Return a string that corresponds to the incoming state value. |
---|
451 | */ |
---|
452 | static char * |
---|
453 | defragGetStateStr(int state) |
---|
454 | { |
---|
455 | char *str; |
---|
456 | |
---|
457 | switch(state) { |
---|
458 | case SECTOR_DEFRAG_INACTIVE: |
---|
459 | str = "SectorDefragInactive"; |
---|
460 | break; |
---|
461 | case SECTOR_DEFRAG_ABORT_RESTART: |
---|
462 | str = "DefragRestartAborted"; |
---|
463 | break; |
---|
464 | case SCANNING_ACTIVE_SECTOR_1: |
---|
465 | str = "ScanningActiveSector1"; |
---|
466 | break; |
---|
467 | case SCANNING_ACTIVE_SECTOR_2: |
---|
468 | str = "ScanningActiveSector2"; |
---|
469 | break; |
---|
470 | case SCANNING_ACTIVE_SECTOR_3: |
---|
471 | str = "ScanningActiveSector3"; |
---|
472 | break; |
---|
473 | case SCANNING_ACTIVE_SECTOR_4: |
---|
474 | str = "ScanningActiveSector4"; |
---|
475 | break; |
---|
476 | case SCANNING_ACTIVE_SECTOR_5: |
---|
477 | str = "ScanningActiveSector5"; |
---|
478 | break; |
---|
479 | case SECTOR_DEFRAG_ALMOST_DONE: |
---|
480 | str = "DefragAlmostDone"; |
---|
481 | break; |
---|
482 | default: |
---|
483 | str = "???"; |
---|
484 | break; |
---|
485 | } |
---|
486 | return(str); |
---|
487 | } |
---|
488 | |
---|
489 | /* defragRestart(): |
---|
490 | * Poll the console allowing the user to abort the auto-restart of |
---|
491 | * the defragmentation. If a character is received on the console, |
---|
492 | * then return 0 indicating that the defrag should not be restarted; |
---|
493 | * else return 1. |
---|
494 | */ |
---|
495 | int |
---|
496 | defragRestart(int state,int snum) |
---|
497 | { |
---|
498 | printf("TFS defrag restart state: %s sector %d\n", |
---|
499 | defragGetStateStr(state),snum); |
---|
500 | if (pollConsole("Hit any key to abort...")) |
---|
501 | return(0); |
---|
502 | return(1); |
---|
503 | } |
---|
504 | |
---|
505 | /* defragGetState(): |
---|
506 | * Step through the files in the specified device and check for |
---|
507 | * sanity. Return SECTOR_DEFRAG_INACTIVE if it is determined that |
---|
508 | * a defragmentation was not in progress; otherwise, return one of |
---|
509 | * several different defrag state values depending on what is found |
---|
510 | * in the TFS flash area. |
---|
511 | * |
---|
512 | * NOTE: |
---|
513 | * As of Jan 2008, the code wrapped within the ifdef/endif |
---|
514 | * ENABLE_FLASHERASED_CHECK_AT_STARTUP is not used by default |
---|
515 | * (the macro must be defined in config.h to pull it in). |
---|
516 | * This change has been determined to be safe and allows startup |
---|
517 | * to be much faster for systems that have a lot of empty TFS |
---|
518 | * space. The code was used to verify that all flash space after |
---|
519 | * the last stored file in TFS was actually erased. If not, then |
---|
520 | * it erases it. |
---|
521 | * This turns out to not really be necessary because if tfsadd() |
---|
522 | * runs and finds that the area it needs isn't erased, it will |
---|
523 | * automatically fall into a tfsclean anyway. As a result, to |
---|
524 | * make startup quicker, this code is not enabled by default. If |
---|
525 | * it is needed, then just define the macro in config.h. |
---|
526 | * |
---|
527 | * As of Mar 2011, thanks to input from Jamie Randall, I'm essentially |
---|
528 | * undoing the previous change by defining the |
---|
529 | * ENABLE_FLASHERASED_CHECK_AT_STARTUP right here. Turns out that |
---|
530 | * while removal of this snippet of code does make bootup faster for |
---|
531 | * those cases where the flash has a large number of sectors, it does |
---|
532 | * cause powersafe defrag to fail in certain cases if a hit occurs. |
---|
533 | * |
---|
534 | */ |
---|
535 | #define ENABLE_FLASHERASED_CHECK_AT_STARTUP /* see note above */ |
---|
536 | |
---|
537 | static int |
---|
538 | defragGetState(TDEV *tdp, int *activesnum) |
---|
539 | { |
---|
540 | TFILE *tfp; |
---|
541 | struct defraghdr *dhp; |
---|
542 | struct sectorcrc *crctbl; |
---|
543 | int snum_in_spare, firstsnum; |
---|
544 | int first_touched_snum, last_touched_snum; |
---|
545 | int break_cause, break1_cause, spare_is_erased, ftot, ftot1, errstate; |
---|
546 | |
---|
547 | /* Establish state of spare sector: |
---|
548 | */ |
---|
549 | spare_is_erased = flasherased((uchar *)tdp->spare, |
---|
550 | (uchar *)tdp->spare+tdp->sparesize-1); |
---|
551 | |
---|
552 | ftot = 0; |
---|
553 | break_cause = break1_cause = 0; |
---|
554 | for(tfp=(TFILE *)tdp->start; tfp < (TFILE *)tdp->end; tfp=tfp->next) { |
---|
555 | /* If we are legally at the end of file storage space, then we |
---|
556 | * will hit a header size that is ERASED16. If we reach this |
---|
557 | * point and the remaining space dedicated to file storage is |
---|
558 | * erased and the spare is erased, it is safe to assume that we |
---|
559 | * were not in the middle of a defrag. |
---|
560 | */ |
---|
561 | if (tfp->hdrsize == ERASED16) { |
---|
562 | #ifdef ENABLE_FLASHERASED_CHECK_AT_STARTUP /* (see note above) */ |
---|
563 | /* Is space from last file to end of TFS space erased? */ |
---|
564 | if (!flasherased((uchar *)tfp,(uchar *)tdp->end)) { |
---|
565 | break_cause = 1; |
---|
566 | break; |
---|
567 | } |
---|
568 | if (!spare_is_erased) { |
---|
569 | break_cause = 2; |
---|
570 | break; |
---|
571 | } |
---|
572 | #if DEFRAG_TEST_ENABLED |
---|
573 | printf("\ndefragGetState: inactive_1\n"); |
---|
574 | #endif |
---|
575 | #endif |
---|
576 | return(SECTOR_DEFRAG_INACTIVE); |
---|
577 | } |
---|
578 | |
---|
579 | /* If the crc32 of the header is corrupt, or if the next pointer |
---|
580 | * doesn't make any sense, then we must assume that a defrag |
---|
581 | * was in progress... |
---|
582 | */ |
---|
583 | if (tfshdrcrc(tfp) != tfp->hdrcrc) { |
---|
584 | break; |
---|
585 | } |
---|
586 | |
---|
587 | if (!(tfp->next) || (tfp->next <= (TFILE *)tdp->start) || |
---|
588 | (tfp->next >= (TFILE *)tdp->end)) { |
---|
589 | break; |
---|
590 | } |
---|
591 | if (TFS_FILEEXISTS(tfp)) |
---|
592 | ftot++; |
---|
593 | } |
---|
594 | /* If we are here, then something is not "perfect" with the flash |
---|
595 | * space used by TFS. If break_cause is non-zero, there is a chance |
---|
596 | * that the only problem is that a file-write was interrupted and |
---|
597 | * we did not actually interrupt an in-progress-defrag. An interrupted |
---|
598 | * file write would place some incomplete data after the last file. |
---|
599 | */ |
---|
600 | ftot1 = defragValidDSI(tdp,&crctbl); |
---|
601 | |
---|
602 | /* If we don't have valid defrag state info (DSI), then we can assume |
---|
603 | * that the files in TFS have not yet been touched (since if we had |
---|
604 | * touched them, we would have already successfully created the DSI). |
---|
605 | * This being the case, then we will not continue with any defrag, |
---|
606 | * let TFS clean things up when the space is needed. |
---|
607 | */ |
---|
608 | if (!ftot1) { |
---|
609 | if (break_cause) { |
---|
610 | /* Hmmm... Should something be done here? */ |
---|
611 | } |
---|
612 | #if DEFRAG_TEST_ENABLED |
---|
613 | printf("\ndefragGetState: inactive_2\n"); |
---|
614 | #endif |
---|
615 | return(SECTOR_DEFRAG_INACTIVE); |
---|
616 | } |
---|
617 | |
---|
618 | /* If we get here, then we have a valid defrag header table, so we |
---|
619 | * can use it and the state of each of the sectors to figure out |
---|
620 | * where we are in the defragmentation process. We need to determine |
---|
621 | * which sector was being worked on at the point in time when the |
---|
622 | * defragmentation was interrupted. A sector is in the "touched" |
---|
623 | * state if a crc32 on its content does not match the crc32 stored |
---|
624 | * in the crc table above the defrag header table. |
---|
625 | * |
---|
626 | * Here we step through the defrag header table and see if each file |
---|
627 | * in the header table exists in TFS. If all files exist, then we |
---|
628 | * must have been very close to completion of the defrag process. |
---|
629 | */ |
---|
630 | printf("TFS: scanning DSI space... "); |
---|
631 | dhp = (struct defraghdr *)crctbl - ftot1; |
---|
632 | while(dhp < (struct defraghdr *)crctbl) { |
---|
633 | tfp = (TFILE *)dhp->nda; |
---|
634 | if (tfp->hdrcrc != dhp->ohdrcrc) |
---|
635 | break; |
---|
636 | |
---|
637 | if (tfshdrcrc(tfp) != tfp->hdrcrc) { |
---|
638 | break1_cause = 1; |
---|
639 | break; |
---|
640 | } |
---|
641 | if (crc32((uchar *)(tfp+1),tfp->filsize) != tfp->filcrc) { |
---|
642 | break1_cause = 2; |
---|
643 | break; |
---|
644 | } |
---|
645 | dhp++; |
---|
646 | defragTick(0); |
---|
647 | } |
---|
648 | printf("done\n"); |
---|
649 | |
---|
650 | /* If we stepped through the entire table, then we've completed the |
---|
651 | * file relocation process, but we still have to clean up... |
---|
652 | */ |
---|
653 | if (dhp >= (struct defraghdr *)crctbl) { |
---|
654 | if (defragRestart(SECTOR_DEFRAG_ALMOST_DONE,0)) { |
---|
655 | return(SECTOR_DEFRAG_ALMOST_DONE); |
---|
656 | } |
---|
657 | else { |
---|
658 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
659 | } |
---|
660 | } |
---|
661 | |
---|
662 | if (addrtosector((unsigned char *)tdp->start,&firstsnum,0,0) < 0) { |
---|
663 | errstate = 50; |
---|
664 | goto state_error; |
---|
665 | } |
---|
666 | defragTouchedSectors(tdp,&first_touched_snum,&last_touched_snum); |
---|
667 | |
---|
668 | /* If there are no touched sectors, then we will not continue with |
---|
669 | * the defrag because we didn't start relocation of any of the files |
---|
670 | * yet. |
---|
671 | */ |
---|
672 | if (first_touched_snum == -1) { |
---|
673 | #if DEFRAG_TEST_ENABLED |
---|
674 | printf("\ndefragGetState: inactive_3\n"); |
---|
675 | #endif |
---|
676 | return(SECTOR_DEFRAG_INACTIVE); |
---|
677 | } |
---|
678 | |
---|
679 | if (spare_is_erased) |
---|
680 | snum_in_spare = -1; |
---|
681 | else |
---|
682 | snum_in_spare = defragSectorInSpare(tdp,crctbl); |
---|
683 | |
---|
684 | #if DEFRAG_TEST_ENABLED |
---|
685 | printf("\ndefragGetState info: %d %d %d\n", |
---|
686 | first_touched_snum, last_touched_snum, snum_in_spare); |
---|
687 | #endif |
---|
688 | |
---|
689 | /* At this point we know what sector was the last to be touched. |
---|
690 | * What we don't know is whether or not the "touch" was completed. |
---|
691 | * So we don't know if the active sector is last_touched_snum or |
---|
692 | * last_touched_snum+1. |
---|
693 | * The only useful piece of data we 'might' have is the fact that |
---|
694 | * the spare may contain the content of the last touched sector. |
---|
695 | */ |
---|
696 | |
---|
697 | /* If the spare is erased, it may be because defrag was just getting |
---|
698 | * ready to start working on the next sector (meaning that the active |
---|
699 | * sector is last_touched_snum+1) or the sector was in the process of |
---|
700 | * being modified. We use the post-crc in the DHT to determine what |
---|
701 | * the active sector is... |
---|
702 | */ |
---|
703 | if (spare_is_erased) { |
---|
704 | if (last_touched_snum >= 0) { |
---|
705 | if (defragPostCrcCheck(tdp,last_touched_snum)) { |
---|
706 | *activesnum = last_touched_snum + 1; |
---|
707 | |
---|
708 | if (defragRestart(SCANNING_ACTIVE_SECTOR_1,*activesnum)) |
---|
709 | return(SCANNING_ACTIVE_SECTOR_1); |
---|
710 | else |
---|
711 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
712 | } |
---|
713 | else { |
---|
714 | if (defragSerase(2,last_touched_snum) < 0) { |
---|
715 | errstate = 51; |
---|
716 | goto state_error; |
---|
717 | } |
---|
718 | *activesnum = last_touched_snum; |
---|
719 | |
---|
720 | if (defragRestart(SCANNING_ACTIVE_SECTOR_2,*activesnum)) |
---|
721 | return(SCANNING_ACTIVE_SECTOR_2); |
---|
722 | else |
---|
723 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
724 | } |
---|
725 | |
---|
726 | } |
---|
727 | else { |
---|
728 | errstate = 52; |
---|
729 | goto state_error; |
---|
730 | } |
---|
731 | } |
---|
732 | |
---|
733 | /* If the sector copied to spare is one greater than the last touched |
---|
734 | * sector, then the active sector is last_touched_snum+1 and it was |
---|
735 | * just copied to the spare. In this case we erase the spare and |
---|
736 | * return indicating the active sector. |
---|
737 | */ |
---|
738 | if (snum_in_spare == last_touched_snum+1) { |
---|
739 | if (defragEraseSpare(tdp) < 0) { |
---|
740 | errstate = 53; |
---|
741 | goto state_error; |
---|
742 | } |
---|
743 | *activesnum = snum_in_spare; |
---|
744 | |
---|
745 | if (defragRestart(SCANNING_ACTIVE_SECTOR_3,*activesnum)) |
---|
746 | return(SCANNING_ACTIVE_SECTOR_3); |
---|
747 | else |
---|
748 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
749 | } |
---|
750 | |
---|
751 | /* If the spare is not erased, but it does not match any of the |
---|
752 | * sector CRCs, then we must have been in the process of copying |
---|
753 | * the active sector to the spare, so we can erase it and return |
---|
754 | * to the SCANNING_ACTIVE_SECTOR state. |
---|
755 | */ |
---|
756 | if (snum_in_spare == -1) { |
---|
757 | if (last_touched_snum >= 0) { |
---|
758 | *activesnum = last_touched_snum + 1; |
---|
759 | |
---|
760 | if (!defragRestart(SCANNING_ACTIVE_SECTOR_4,*activesnum)) |
---|
761 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
762 | |
---|
763 | if (defragEraseSpare(tdp) < 0) { |
---|
764 | errstate = 54; |
---|
765 | goto state_error; |
---|
766 | } |
---|
767 | return(SCANNING_ACTIVE_SECTOR_4); |
---|
768 | } |
---|
769 | else { |
---|
770 | errstate = 55; |
---|
771 | goto state_error; |
---|
772 | } |
---|
773 | } |
---|
774 | |
---|
775 | /* If the sector copied to spare is the number of the last touched |
---|
776 | * sector, then we were in the middle of modifying the sector, so |
---|
777 | * we have to erase that sector, copy the spare to it and return |
---|
778 | * to the scanning state. |
---|
779 | */ |
---|
780 | if (snum_in_spare == last_touched_snum) { |
---|
781 | int ssize; |
---|
782 | uchar *sbase; |
---|
783 | |
---|
784 | *activesnum = snum_in_spare; |
---|
785 | |
---|
786 | if (!defragRestart(SCANNING_ACTIVE_SECTOR_5,*activesnum)) |
---|
787 | return(SECTOR_DEFRAG_ABORT_RESTART); |
---|
788 | |
---|
789 | if (defragSerase(3,snum_in_spare) < 0) { |
---|
790 | errstate = 56; |
---|
791 | goto state_error; |
---|
792 | } |
---|
793 | if (sectortoaddr(snum_in_spare,&ssize,&sbase) < 0) { |
---|
794 | errstate = 57; |
---|
795 | goto state_error; |
---|
796 | } |
---|
797 | if (defragFwrite(1,sbase,(uchar *)tdp->spare,ssize) < 0) { |
---|
798 | errstate = 58; |
---|
799 | goto state_error; |
---|
800 | } |
---|
801 | if (defragEraseSpare(tdp) < 0) { |
---|
802 | errstate = 59; |
---|
803 | goto state_error; |
---|
804 | } |
---|
805 | return(SCANNING_ACTIVE_SECTOR_5); |
---|
806 | } |
---|
807 | |
---|
808 | /* If we got here, then we are confused, so don't do any defrag |
---|
809 | * continuation... |
---|
810 | */ |
---|
811 | errstate = 90; |
---|
812 | |
---|
813 | state_error: |
---|
814 | printf("DEFRAG_STATE_ERROR: #%d.\n",errstate); |
---|
815 | return(SECTOR_DEFRAG_INACTIVE); |
---|
816 | } |
---|
817 | |
---|
818 | /* inSector(): |
---|
819 | * We are trying to figure out if the address space that we want to copy |
---|
820 | * from is within the active sector. If it is, then we need to adjust |
---|
821 | * our pointers so that we retrieve the at least some of data from the |
---|
822 | * spare. |
---|
823 | * If the range specified by 'i_base' and 'i_size' overlays (in any way) |
---|
824 | * the address space used by the sector specified by 'snum', |
---|
825 | * then return the address in the spare and the size of the overlay. |
---|
826 | */ |
---|
827 | static int |
---|
828 | inSector(TDEV *tdp,int snum,uchar *i_base,int i_size,uchar **saddr,int *ovlysz) |
---|
829 | { |
---|
830 | int s_size; |
---|
831 | uchar *s_base, *s_end, *i_end; |
---|
832 | |
---|
833 | /* Retrieve information about the sector: */ |
---|
834 | if (sectortoaddr(snum,&s_size,&s_base) == -1) |
---|
835 | return(TFSERR_MEMFAIL); |
---|
836 | |
---|
837 | i_end = i_base + i_size; |
---|
838 | s_end = s_base + s_size; |
---|
839 | |
---|
840 | if ((i_end < s_base) || (i_base > s_end)) { |
---|
841 | *ovlysz = 0; |
---|
842 | return(0); |
---|
843 | } |
---|
844 | |
---|
845 | if (i_base < s_base) { |
---|
846 | if (i_end > s_end) { |
---|
847 | *ovlysz = s_size; |
---|
848 | } |
---|
849 | else { |
---|
850 | *ovlysz = (i_size - (s_base - i_base)); |
---|
851 | } |
---|
852 | *saddr = (uchar *)tdp->spare; |
---|
853 | } |
---|
854 | else { |
---|
855 | if (i_end > s_end) { |
---|
856 | *ovlysz = (i_size - (i_end - s_end)); |
---|
857 | } |
---|
858 | else { |
---|
859 | *ovlysz = i_size; |
---|
860 | } |
---|
861 | *saddr = (uchar *)tdp->spare + (i_base - s_base); |
---|
862 | } |
---|
863 | return(0); |
---|
864 | } |
---|
865 | |
---|
866 | /* struct fillinfo & FILLMODE definitions: |
---|
867 | * Structure used by the "Fill" functions below. |
---|
868 | */ |
---|
869 | #define FILLMODE_FWRITE 1 /* Do the flash write */ |
---|
870 | #define FILLMODE_SPAREOVERLAP 2 /* Determine if there is SPARE overlap */ |
---|
871 | #define FILLMODE_CRCONLY 3 /* Calculate a 32-bit crc on the data */ |
---|
872 | |
---|
873 | struct fillinfo { |
---|
874 | struct defraghdr *dhp; /* pointer to defrag header table */ |
---|
875 | TDEV *tdp; /* pointer to TFS device */ |
---|
876 | ulong crc; /* used in FILLMODE_CRCONLY mode */ |
---|
877 | int crcsz; /* size of crc calculation */ |
---|
878 | int fhdr; /* set if we're working on a file header */ |
---|
879 | int asnum; /* the active sector */ |
---|
880 | int mode; /* see FILLMODE_xxx definitions */ |
---|
881 | }; |
---|
882 | |
---|
883 | /* defragFillFlash(): |
---|
884 | * This function is called by the defragFillActiveSector() function |
---|
885 | * below. It covers the four different cases of a file spanning over |
---|
886 | * the active sector, plus it deals with the possibility that the source |
---|
887 | * of the file data may be the same sector as the active one (meaning that |
---|
888 | * the source is taken from the spare). It is within this function that |
---|
889 | * the active sector is actually modified and it assumes that the portion |
---|
890 | * of the active sector to be written to is already erased. |
---|
891 | * |
---|
892 | * |
---|
893 | * SPANTYPE_BCEC: |
---|
894 | * In this case, the file starts in the active sector and ends in |
---|
895 | * the active sector... |
---|
896 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
897 | * | | | | | | | | |
---|
898 | * | | |<-active->| | | | SPARE | |
---|
899 | * | | | sector | | | | SECTOR | |
---|
900 | * | | | | | | | | |
---|
901 | * | | | newfile | | | | | |
---|
902 | * | | | |<-->| | | | | | |
---|
903 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
904 | * |
---|
905 | * |
---|
906 | * SPANTYPE_BPEC: |
---|
907 | * In this case, the file starts in a sector prior to the currently active |
---|
908 | * sector and ends in the active sector... |
---|
909 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
910 | * | | | | | | | | |
---|
911 | * | | | |<-active->| | | SPARE | |
---|
912 | * | | | | sector | | | SECTOR | |
---|
913 | * | | | | | | | | |
---|
914 | * | | |<----newfile----->| | | | | |
---|
915 | * | | | | | | | | |
---|
916 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
917 | * |
---|
918 | * |
---|
919 | * SPANTYPE_BPEL: |
---|
920 | * In this case, the file starts in some sector prior to the currently |
---|
921 | * active sector and ends in some sector after the currently active |
---|
922 | * sector... |
---|
923 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
924 | * | | | | | | | | |
---|
925 | * | | |<-active->| | | | SPARE | |
---|
926 | * | | | sector | | | | SECTOR | |
---|
927 | * | | | | | | | | |
---|
928 | * | |<---------- newfile------------------->| | | | |
---|
929 | * | | | | | | | | |
---|
930 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
931 | * |
---|
932 | * |
---|
933 | * SPANTYPE_BCEL: |
---|
934 | * In this case, the file starts in the active sector and ends in |
---|
935 | * a later sector. |
---|
936 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
937 | * | | | | | | | | |
---|
938 | * | |<-active->| | | | | SPARE | |
---|
939 | * | | sector | | | | | SECTOR | |
---|
940 | * | | | | | | | | |
---|
941 | * | | |<----newfile----->| | | | | |
---|
942 | * | | ****| | | | | | |
---|
943 | * -----------|----------|----------|----------|---------|---------|---------- |
---|
944 | */ |
---|
945 | static int |
---|
946 | defragFillFlash(struct fillinfo *fip,int spantype,char **activeaddr,int verbose) |
---|
947 | { |
---|
948 | char *hp; |
---|
949 | TFILE nfhdr; |
---|
950 | struct defraghdr *dhp; |
---|
951 | int ohdroffset, nhdroffset; |
---|
952 | uchar *ovly, *src, *activesbase; |
---|
953 | int ovlysz, srcsz, activessize; |
---|
954 | |
---|
955 | src = 0; |
---|
956 | ovly = 0; |
---|
957 | srcsz = 0; |
---|
958 | nhdroffset = ohdroffset = 0; |
---|
959 | dhp = fip->dhp; |
---|
960 | |
---|
961 | if (verbose >= 2) { |
---|
962 | printf(" defragFillFlash %s %s (%s %d)\n",fip->fhdr ? "hdr" : "dat", |
---|
963 | defragGetSpantypeStr(spantype), dhp->fname,fip->asnum); |
---|
964 | } |
---|
965 | |
---|
966 | if (spantype == SPANTYPE_BCEC) { |
---|
967 | if (fip->fhdr) { |
---|
968 | src = (uchar *)dhp->ohdr; |
---|
969 | srcsz = TFSHDRSIZ; |
---|
970 | } |
---|
971 | else { |
---|
972 | src = (uchar *)dhp->ohdr+TFSHDRSIZ; |
---|
973 | srcsz = dhp->filsize; |
---|
974 | } |
---|
975 | } |
---|
976 | else if (spantype == SPANTYPE_BPEC) { |
---|
977 | if (fip->fhdr) { |
---|
978 | /* Calculate the offset into the header at which point a |
---|
979 | * sector boundary occurs. Do this for both the old (before |
---|
980 | * defrag relocation) and new (after defrag relocation) |
---|
981 | * location of the header. |
---|
982 | */ |
---|
983 | /* Changed as of Dec 2010, based on error found by Leon... |
---|
984 | * We need to figure out how the header overlaps the sector |
---|
985 | * boundary. Prior to 12/2010, this code did not account for |
---|
986 | * the case where the file size spans beyond the currently |
---|
987 | * active sector. |
---|
988 | */ |
---|
989 | if ((dhp->neso > dhp->filsize) && (dhp->oeso > dhp->filsize)) { |
---|
990 | nhdroffset = TFSHDRSIZ - (dhp->neso - dhp->filsize); |
---|
991 | ohdroffset = TFSHDRSIZ - (dhp->oeso - dhp->filsize); |
---|
992 | srcsz = (dhp->oeso - dhp->filsize) + (ohdroffset - nhdroffset); |
---|
993 | src = (uchar *)dhp->ohdr + nhdroffset; |
---|
994 | } |
---|
995 | else { |
---|
996 | int ssz; |
---|
997 | int sno = dhp->nesn; |
---|
998 | int fsz = dhp->filsize; |
---|
999 | while(sno > fip->asnum) { |
---|
1000 | if (sectortoaddr(sno,&ssz,0) < 0) |
---|
1001 | return(TFSERR_MEMFAIL); |
---|
1002 | if (fsz == dhp->filsize) |
---|
1003 | fsz -= dhp->neso; |
---|
1004 | else |
---|
1005 | fsz -= ssz; |
---|
1006 | sno--; |
---|
1007 | } |
---|
1008 | if (sectortoaddr(fip->asnum,&ssz,0) < 0) |
---|
1009 | return(TFSERR_MEMFAIL); |
---|
1010 | srcsz = ssz - fsz; |
---|
1011 | src = (uchar *)dhp->ohdr; |
---|
1012 | src += (TFSHDRSIZ-srcsz); |
---|
1013 | nhdroffset = (TFSHDRSIZ-srcsz); |
---|
1014 | } |
---|
1015 | } |
---|
1016 | else { |
---|
1017 | src = (uchar *)dhp->ohdr + TFSHDRSIZ + (dhp->filsize - dhp->neso); |
---|
1018 | srcsz = dhp->neso; |
---|
1019 | } |
---|
1020 | } |
---|
1021 | else if (spantype == SPANTYPE_BCEL) { |
---|
1022 | if (sectortoaddr(fip->asnum,&activessize,&activesbase) == -1) |
---|
1023 | return(TFSERR_MEMFAIL); |
---|
1024 | |
---|
1025 | if (fip->fhdr) { |
---|
1026 | src = (uchar *)dhp->ohdr; |
---|
1027 | } |
---|
1028 | else { |
---|
1029 | src = (uchar *)dhp->ohdr+TFSHDRSIZ; |
---|
1030 | } |
---|
1031 | srcsz = (activesbase + activessize) - (uchar *)*activeaddr; |
---|
1032 | } |
---|
1033 | else if (spantype == SPANTYPE_BPEL) { |
---|
1034 | if (sectortoaddr(fip->asnum,&activessize,0) == -1) |
---|
1035 | return(TFSERR_MEMFAIL); |
---|
1036 | |
---|
1037 | if (fip->fhdr) { |
---|
1038 | src = (uchar *)dhp->ohdr; |
---|
1039 | } |
---|
1040 | else { |
---|
1041 | src = (uchar *)dhp->ohdr+TFSHDRSIZ; |
---|
1042 | } |
---|
1043 | |
---|
1044 | src += ((*activeaddr - dhp->nda) - TFSHDRSIZ); |
---|
1045 | srcsz = activessize; |
---|
1046 | } |
---|
1047 | else { |
---|
1048 | return(0); |
---|
1049 | } |
---|
1050 | |
---|
1051 | /* Do some error checking on the computed size: |
---|
1052 | */ |
---|
1053 | if (srcsz < 0) { |
---|
1054 | printf("defragFillFlash: srcsz < 0\n"); |
---|
1055 | return(TFSERR_MEMFAIL); |
---|
1056 | } |
---|
1057 | |
---|
1058 | if (fip->fhdr) { |
---|
1059 | if (srcsz > TFSHDRSIZ) { |
---|
1060 | printf("defragFillFlash: srcsz > TFSHDRSIZ\n"); |
---|
1061 | return(TFSERR_MEMFAIL); |
---|
1062 | } |
---|
1063 | } |
---|
1064 | else { |
---|
1065 | if (srcsz > dhp->filsize) { |
---|
1066 | printf("defragFillFlash: srcsz > filsize\n"); |
---|
1067 | return(TFSERR_MEMFAIL); |
---|
1068 | } |
---|
1069 | } |
---|
1070 | |
---|
1071 | /* Determine if any portion of the source was part of the sector that |
---|
1072 | * is now the active sector.. If yes (ovlysz > 0), then we must |
---|
1073 | * deal with the fact that some (or all) of the fill source is in the |
---|
1074 | * spare sector... |
---|
1075 | */ |
---|
1076 | if (inSector(fip->tdp,fip->asnum,src,srcsz,&ovly,&ovlysz) < 0) |
---|
1077 | return(TFSERR_MEMFAIL); |
---|
1078 | |
---|
1079 | /* If the mode is not FILLMODE_FWRITE, then we don't do any of the |
---|
1080 | * flash operations. We are in this function only to determine |
---|
1081 | * if we need to copy the active sector to the spare prior to |
---|
1082 | * starting the modification of the active sector. |
---|
1083 | */ |
---|
1084 | if (fip->mode == FILLMODE_FWRITE) { |
---|
1085 | if (fip->fhdr) { |
---|
1086 | hp = (char *)&nfhdr; |
---|
1087 | if (ovlysz) { |
---|
1088 | memcpy((char *)hp+nhdroffset,(char *)ovly,ovlysz); |
---|
1089 | if (ovlysz != srcsz) { |
---|
1090 | memcpy(hp+nhdroffset+ovlysz,(char *)src+ovlysz, |
---|
1091 | srcsz-ovlysz); |
---|
1092 | } |
---|
1093 | } |
---|
1094 | else { |
---|
1095 | /* next line was <nfhdr = *dhp->ohdr> ... */ |
---|
1096 | memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE)); |
---|
1097 | } |
---|
1098 | nfhdr.next = dhp->nextfile; |
---|
1099 | if (defragFwrite(2,(uchar *)*activeaddr,(uchar *)hp+nhdroffset,srcsz) == -1) |
---|
1100 | return(TFSERR_FLASHFAILURE); |
---|
1101 | } |
---|
1102 | else { |
---|
1103 | if (ovlysz) { |
---|
1104 | if (defragFwrite(3,(uchar *)*activeaddr,(uchar *)ovly,ovlysz) == -1) |
---|
1105 | return(TFSERR_FLASHFAILURE); |
---|
1106 | if (ovlysz != srcsz) { |
---|
1107 | if (defragFwrite(4,(uchar *)*activeaddr+ovlysz,(uchar *)src+ovlysz, |
---|
1108 | srcsz-ovlysz) == -1) |
---|
1109 | return(TFSERR_FLASHFAILURE); |
---|
1110 | } |
---|
1111 | } |
---|
1112 | else { |
---|
1113 | if (defragFwrite(5,(uchar *)*activeaddr,(uchar *)src,srcsz) == -1) |
---|
1114 | return(TFSERR_FLASHFAILURE); |
---|
1115 | } |
---|
1116 | } |
---|
1117 | } |
---|
1118 | else if (fip->mode == FILLMODE_CRCONLY) { |
---|
1119 | register uchar *bp; |
---|
1120 | int sz, temp; |
---|
1121 | |
---|
1122 | if (fip->fhdr) { |
---|
1123 | hp = (char *)&nfhdr; |
---|
1124 | /* next line was <nfhdr = *dhp->ohdr> ... */ |
---|
1125 | memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE)); |
---|
1126 | nfhdr.next = dhp->nextfile; |
---|
1127 | bp = (uchar *)hp + nhdroffset; |
---|
1128 | } |
---|
1129 | else { |
---|
1130 | bp = (uchar *)src; |
---|
1131 | } |
---|
1132 | sz = srcsz; |
---|
1133 | fip->crcsz += sz; |
---|
1134 | while(sz) { |
---|
1135 | temp = (fip->crc ^ *bp++) & 0x000000FFL; |
---|
1136 | fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; |
---|
1137 | sz--; |
---|
1138 | } |
---|
1139 | } |
---|
1140 | *activeaddr += srcsz; |
---|
1141 | |
---|
1142 | if ((spantype == SPANTYPE_BCEC || spantype == SPANTYPE_BPEC) && |
---|
1143 | (!fip->fhdr) && ((ulong)*activeaddr & 0xf)) { |
---|
1144 | int sz, temp, modfixsize; |
---|
1145 | |
---|
1146 | modfixsize = (TFS_FSIZEMOD - ((ulong)*activeaddr & (TFS_FSIZEMOD-1))); |
---|
1147 | *activeaddr += modfixsize; |
---|
1148 | if (fip->mode == FILLMODE_CRCONLY) { |
---|
1149 | sz = modfixsize; |
---|
1150 | fip->crcsz += sz; |
---|
1151 | while(sz) { |
---|
1152 | temp = (fip->crc ^ 0xff) & 0x000000FFL; |
---|
1153 | fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; |
---|
1154 | sz--; |
---|
1155 | } |
---|
1156 | } |
---|
1157 | } |
---|
1158 | |
---|
1159 | /* Return ovlysz so that the caller will know if this function |
---|
1160 | * needed the spare sector. This is used in the "mode = SPARE_OVERLAP" |
---|
1161 | * pass of defragFillActiveSector(). |
---|
1162 | */ |
---|
1163 | return(ovlysz); |
---|
1164 | } |
---|
1165 | |
---|
1166 | /* defragFillActiveSector(): |
---|
1167 | * This and defragFillFlash() are the workhorses of the tfsclean() function. |
---|
1168 | * The bulk of this function is used to determine if we need to do anything |
---|
1169 | * to the active sector and if so, do we need to copy the active sector to |
---|
1170 | * the spare prior to erasing it. |
---|
1171 | * The first loop in this function determines whether we need to do anything |
---|
1172 | * at all with this sector (it may not be touched by the defragmentation). |
---|
1173 | * The second loop determines if we have to copy the active sector to the |
---|
1174 | * spare prior to erasing the active sector. |
---|
1175 | * The final loop in this function does the call to defragFillFlash() |
---|
1176 | * to do the actual flash writes. |
---|
1177 | */ |
---|
1178 | static int |
---|
1179 | defragFillActiveSector(TDEV *tdp, int ftot, int snum, int verbose) |
---|
1180 | { |
---|
1181 | int firstsnum; /* number of first TFS sector */ |
---|
1182 | int activesnum; /* number of sector currently being written to */ |
---|
1183 | int activessize; /* size of active sector */ |
---|
1184 | char *activeaddr; /* offset being written to in the active sector */ |
---|
1185 | uchar *activesbase; /* base address of active sector */ |
---|
1186 | char *activesend; /* end address of active sector */ |
---|
1187 | struct defraghdr *sdhp;/* pointer into defrag hdr table in spare */ |
---|
1188 | struct defraghdr *dhp; /* pointer into defrag header table */ |
---|
1189 | int fullsize; /* size of file and header */ |
---|
1190 | char *new_dend; /* new end of data */ |
---|
1191 | char *new_dbase; /* new base of data */ |
---|
1192 | char *new_hend; /* new end of header */ |
---|
1193 | char *new_hbase; /* new base of header */ |
---|
1194 | char *new_fend; /* new end of file */ |
---|
1195 | char *new_fbase; /* new base of file */ |
---|
1196 | int new_fspan; /* span type for new file */ |
---|
1197 | int new_hspan; /* span type for new header */ |
---|
1198 | int new_dspan; /* span type for new data */ |
---|
1199 | int fillstat; /* result of defragFillFlash() function call */ |
---|
1200 | int noreloctot; /* number of files spanning the active sector */ |
---|
1201 | /* that do not have to be relocated */ |
---|
1202 | int tmptot; /* temps used for the "SPARE_OVERLAP" mode */ |
---|
1203 | char *tmpactiveaddr; |
---|
1204 | struct defraghdr *tmpdhp; |
---|
1205 | struct fillinfo finfo; |
---|
1206 | struct sectorcrc *crctbl; |
---|
1207 | int lastsnum, tot; |
---|
1208 | int copytospare; |
---|
1209 | int lastfileisnotrelocated; |
---|
1210 | |
---|
1211 | /* Retrieve number of first TFS sector: */ |
---|
1212 | if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) |
---|
1213 | return(TFSERR_MEMFAIL); |
---|
1214 | |
---|
1215 | activesnum = snum + firstsnum; |
---|
1216 | crctbl = defragCrcTable(tdp); |
---|
1217 | |
---|
1218 | /* Retrieve information about active sector: */ |
---|
1219 | if (sectortoaddr(activesnum,&activessize,&activesbase) == -1) |
---|
1220 | return(TFSERR_MEMFAIL); |
---|
1221 | |
---|
1222 | if (verbose) |
---|
1223 | printf(" Active sector: %3d @ 0x%lx\n",activesnum,(ulong)activesbase); |
---|
1224 | |
---|
1225 | if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0) |
---|
1226 | return(TFSERR_MEMFAIL); |
---|
1227 | |
---|
1228 | /* Establish a pointer to the defrag header table. |
---|
1229 | * For the case when the active sector is the last sector, the defrag |
---|
1230 | * header table will be in the spare, so we also establish a pointer |
---|
1231 | * to that space... |
---|
1232 | */ |
---|
1233 | dhp = (struct defraghdr *)crctbl; |
---|
1234 | dhp -= ftot; |
---|
1235 | sdhp = (struct defraghdr *)(tdp->spare+activessize - |
---|
1236 | (tdp->sectorcount * sizeof(struct sectorcrc))); |
---|
1237 | sdhp -= ftot; |
---|
1238 | |
---|
1239 | activeaddr = (char *)activesbase; |
---|
1240 | tmpactiveaddr = (char *)activesbase; |
---|
1241 | activesend = (char *)activesbase + activessize - 1; |
---|
1242 | |
---|
1243 | /* FIRST LOOP: |
---|
1244 | * See if we need to do anything... |
---|
1245 | * In this state, we are simply checking to see if anything is going |
---|
1246 | * to cause the currently active sector to be written to. |
---|
1247 | * If yes, then we need to copy it to the spare and start the |
---|
1248 | * modification process; else, we just return and do nothing |
---|
1249 | * to this sector. |
---|
1250 | * For each file in the defrag header table that is destined for |
---|
1251 | * the address space occupied by the currently active sector, copy |
---|
1252 | * that file (header and data) to the active sector... |
---|
1253 | * Note that it may only be a partial copy, depending on the size |
---|
1254 | * of the file and the amount of space left in the active sector. |
---|
1255 | */ |
---|
1256 | |
---|
1257 | noreloctot = 0; |
---|
1258 | new_fspan = SPANTYPE_UNDEF; |
---|
1259 | lastfileisnotrelocated = 0; |
---|
1260 | for(tot=0;tot<ftot;tot++,dhp++,sdhp++) { |
---|
1261 | fullsize = TFSHDRSIZ + dhp->filsize; |
---|
1262 | new_fbase = dhp->nda; |
---|
1263 | new_fend = (new_fbase + fullsize); |
---|
1264 | |
---|
1265 | /* We must figure out how the new version of the file will |
---|
1266 | * span across the active sector. |
---|
1267 | * See defragGetSpantype() for details. |
---|
1268 | */ |
---|
1269 | new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1270 | (char *)new_fbase,(char *)new_fend); |
---|
1271 | |
---|
1272 | /* If the file we are looking at entirely spans a sector that is |
---|
1273 | * prior to the currently active sector, then we just continue |
---|
1274 | * through the list. |
---|
1275 | * If the file entirely spans a sector that is after the |
---|
1276 | * currently active sector, then we are done with this active sector. |
---|
1277 | * If the file falls within the active sector in any way, and its |
---|
1278 | * new location does not match its old location, then we |
---|
1279 | * break out of this loop and begin the modification of this |
---|
1280 | * active sector... |
---|
1281 | */ |
---|
1282 | if (new_fspan == SPANTYPE_BLEL) |
---|
1283 | return(0); |
---|
1284 | |
---|
1285 | if (new_fspan != SPANTYPE_BPEP) { |
---|
1286 | if (dhp->nda == (char *)dhp->ohdr) { |
---|
1287 | noreloctot++; |
---|
1288 | if (tot == ftot-1) { |
---|
1289 | lastfileisnotrelocated = 1; |
---|
1290 | if (verbose > 1) |
---|
1291 | printf(" last file not relocated\n"); |
---|
1292 | } |
---|
1293 | } |
---|
1294 | else |
---|
1295 | break; |
---|
1296 | } |
---|
1297 | } |
---|
1298 | |
---|
1299 | /* If tot == ftot, then we got through the entire loop above without |
---|
1300 | * finding a file that needs to be relocated into this active sector. |
---|
1301 | * This means one of two things: either all the files fall into a |
---|
1302 | * sector prior to this active sector, or the files in this active |
---|
1303 | * sector do not need to be relocated. In either case, we simply |
---|
1304 | * return without touching this sector. |
---|
1305 | * Note that we also keep track of the possibility that the last file |
---|
1306 | * may not be relocated. If this ends up to be the case, then we are |
---|
1307 | * simply cleaning up one or more dead files after a full set of active |
---|
1308 | * files, so we should clean up the sector. |
---|
1309 | */ |
---|
1310 | if ((tot == ftot) && (lastfileisnotrelocated == 0)) |
---|
1311 | return(0); |
---|
1312 | |
---|
1313 | /* If tot != ftot, then we must subtract noreloctot from tot so that |
---|
1314 | * we establish 'tot' as the index into the first file that must be |
---|
1315 | * copied to the active sector... |
---|
1316 | */ |
---|
1317 | if (noreloctot) { |
---|
1318 | tot -= noreloctot; |
---|
1319 | dhp -= noreloctot; |
---|
1320 | sdhp -= noreloctot; |
---|
1321 | } |
---|
1322 | |
---|
1323 | /* Exit immediately before cleaning up the spare... */ |
---|
1324 | defragExitTestPoint(10000+activesnum); |
---|
1325 | |
---|
1326 | /* Since we got here, we know that we have to do some work on the |
---|
1327 | * currently active sector. We may not have to copy it to the spare, |
---|
1328 | * but we will erase the spare anyway because the sector erase is |
---|
1329 | * supposed to be smart enough to avoid the erase if it is already |
---|
1330 | * erased. This should be handled by the flash driver because in |
---|
1331 | * ALL cases the erase should be avoided if possible. |
---|
1332 | */ |
---|
1333 | if (defragEraseSpare(tdp) < 0) |
---|
1334 | return(TFSERR_FLASHFAILURE); |
---|
1335 | |
---|
1336 | /* Exit immediately after cleaning up the spare... */ |
---|
1337 | defragExitTestPoint(10001+activesnum); |
---|
1338 | |
---|
1339 | /* If the active sector is the last sector (which would contain the |
---|
1340 | * defrag header table), then we reference the copy of the table that |
---|
1341 | * is in the spare... |
---|
1342 | * Also, if this is the last sector, then we HAVE to copy it to |
---|
1343 | * spare, so we can skip the 2nd loop that attempts to determine |
---|
1344 | * if we need to do it. |
---|
1345 | */ |
---|
1346 | if (activesnum == lastsnum) { |
---|
1347 | dhp = sdhp; |
---|
1348 | copytospare = 1; |
---|
1349 | } |
---|
1350 | else { |
---|
1351 | /* SECOND LOOP: |
---|
1352 | * See if we need to copy the active sector to the spare... |
---|
1353 | * We do this by continuing the loop we started above. Notice that |
---|
1354 | * we do an almost identical loop again below this. |
---|
1355 | * On this pass through the loop we are only checking to see if it is |
---|
1356 | * necessary to copy this active sector to the spare. |
---|
1357 | */ |
---|
1358 | tmptot = tot; |
---|
1359 | tmpdhp = dhp; |
---|
1360 | copytospare = 0; |
---|
1361 | finfo.mode = FILLMODE_SPAREOVERLAP; |
---|
1362 | for(;tmptot<ftot;tmptot++,tmpdhp++) { |
---|
1363 | finfo.tdp = tdp; |
---|
1364 | finfo.dhp = tmpdhp; |
---|
1365 | finfo.asnum = activesnum; |
---|
1366 | |
---|
1367 | fullsize = TFSHDRSIZ + tmpdhp->filsize; |
---|
1368 | new_fbase = tmpdhp->nda; |
---|
1369 | new_fend = (new_fbase + fullsize); |
---|
1370 | |
---|
1371 | new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1372 | (char *)new_fbase,(char *)new_fend); |
---|
1373 | |
---|
1374 | if (new_fspan == SPANTYPE_BPEP) |
---|
1375 | continue; |
---|
1376 | else if (new_fspan == SPANTYPE_BLEL) |
---|
1377 | break; |
---|
1378 | |
---|
1379 | /* Now retrieve span information about header and data |
---|
1380 | * portions of the file (new and orig)... |
---|
1381 | */ |
---|
1382 | new_hbase = new_fbase; |
---|
1383 | new_hend = new_hbase + TFSHDRSIZ; |
---|
1384 | new_dbase = new_hbase + TFSHDRSIZ; |
---|
1385 | new_dend = new_fend; |
---|
1386 | |
---|
1387 | new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1388 | (char *)new_hbase,(char *)new_hend); |
---|
1389 | new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1390 | (char *)new_dbase,(char *)new_dend); |
---|
1391 | |
---|
1392 | /* If defragFillFlash() returns positive (with mode == |
---|
1393 | * FILLMODE_SPAREOVERLAP set above), then we know that the |
---|
1394 | * spare sector must be loaded with a copy of this active |
---|
1395 | * sector, so we can break out of this loop at that point... |
---|
1396 | */ |
---|
1397 | finfo.fhdr = 1; |
---|
1398 | fillstat = defragFillFlash(&finfo,new_hspan,&tmpactiveaddr,verbose); |
---|
1399 | if (fillstat < 0) |
---|
1400 | return(fillstat); |
---|
1401 | if (fillstat > 0) { |
---|
1402 | copytospare = 1; |
---|
1403 | break; |
---|
1404 | } |
---|
1405 | if (new_hspan == SPANTYPE_BCEL) |
---|
1406 | break; |
---|
1407 | |
---|
1408 | finfo.fhdr = 0; |
---|
1409 | fillstat = defragFillFlash(&finfo,new_dspan,&tmpactiveaddr,verbose); |
---|
1410 | if (fillstat < 0) |
---|
1411 | return(fillstat); |
---|
1412 | if (fillstat > 0) { |
---|
1413 | copytospare = 1; |
---|
1414 | break; |
---|
1415 | } |
---|
1416 | if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) |
---|
1417 | break; |
---|
1418 | } |
---|
1419 | } |
---|
1420 | |
---|
1421 | finfo.mode = FILLMODE_FWRITE; |
---|
1422 | |
---|
1423 | defragExitTestPoint(10002+activesnum); |
---|
1424 | |
---|
1425 | if (copytospare) { |
---|
1426 | defragTick(verbose); |
---|
1427 | #if DEFRAG_TEST_ENABLED |
---|
1428 | printf(" copying sector %d to spare\n",activesnum); |
---|
1429 | #endif |
---|
1430 | if (defragFwrite(6,(uchar *)tdp->spare,activesbase,activessize) == -1) { |
---|
1431 | printf("Failed to copy active %d to spare\n",activesnum); |
---|
1432 | return(TFSERR_FLASHFAILURE); |
---|
1433 | } |
---|
1434 | } |
---|
1435 | #if DEFRAG_TEST_ENABLED |
---|
1436 | else { |
---|
1437 | printf(" copy saved\n"); |
---|
1438 | } |
---|
1439 | #endif |
---|
1440 | |
---|
1441 | defragTick(verbose); |
---|
1442 | |
---|
1443 | /* We can now begin actual modification of the active sector, |
---|
1444 | * so start off by eraseing it... |
---|
1445 | */ |
---|
1446 | defragExitTestPoint(10003+activesnum); |
---|
1447 | |
---|
1448 | if (defragSerase(4,activesnum) < 0) |
---|
1449 | return(TFSERR_FLASHFAILURE); |
---|
1450 | |
---|
1451 | defragExitTestPoint(10004+activesnum); |
---|
1452 | |
---|
1453 | /* THIRD LOOP: |
---|
1454 | * Now we pass through the loop to do the real flash modifications... |
---|
1455 | */ |
---|
1456 | for(;tot<ftot;tot++,dhp++) { |
---|
1457 | finfo.tdp = tdp; |
---|
1458 | finfo.dhp = dhp; |
---|
1459 | finfo.asnum = activesnum; |
---|
1460 | |
---|
1461 | fullsize = TFSHDRSIZ + dhp->filsize; |
---|
1462 | new_fbase = dhp->nda; |
---|
1463 | new_fend = (new_fbase + fullsize); |
---|
1464 | |
---|
1465 | new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1466 | (char *)new_fbase,(char *)new_fend); |
---|
1467 | |
---|
1468 | if (new_fspan == SPANTYPE_BPEP) |
---|
1469 | continue; |
---|
1470 | else if (new_fspan == SPANTYPE_BLEL) |
---|
1471 | break; |
---|
1472 | |
---|
1473 | if (verbose) |
---|
1474 | printf(" File: %s\n",dhp->fname); |
---|
1475 | |
---|
1476 | /* Now retrieve span information about header and data |
---|
1477 | * portions of the file (new and orig)... |
---|
1478 | */ |
---|
1479 | new_hbase = new_fbase; |
---|
1480 | new_hend = new_hbase + TFSHDRSIZ; |
---|
1481 | new_dbase = new_hbase + TFSHDRSIZ; |
---|
1482 | new_dend = new_fend; |
---|
1483 | |
---|
1484 | new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1485 | (char *)new_hbase,(char *)new_hend); |
---|
1486 | new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1487 | (char *)new_dbase,(char *)new_dend); |
---|
1488 | |
---|
1489 | /* At this point we have all the information we need to copy |
---|
1490 | * the appropriate amount of the file from orignal space |
---|
1491 | * to new space. |
---|
1492 | * We have to break the write up into two parts, the header |
---|
1493 | * (new_hspan) and the data (new_dspan) so we have to look |
---|
1494 | * at the spantype for each to determine what part of the |
---|
1495 | * header and/or data we are going to copy. |
---|
1496 | * |
---|
1497 | * Also, we must consider the possibility that the source |
---|
1498 | * data may be in the spare sector. This would be the case |
---|
1499 | * if the active sector is the same sector that the original |
---|
1500 | * data was in. If the source data is in the spare sector, |
---|
1501 | * then an added complication is the fact that it may not |
---|
1502 | * all be there, we may have to copy some from the spare, |
---|
1503 | * then some from the original space. |
---|
1504 | */ |
---|
1505 | finfo.fhdr = 1; |
---|
1506 | fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose); |
---|
1507 | if (fillstat < 0) |
---|
1508 | return(fillstat); |
---|
1509 | if (new_hspan == SPANTYPE_BCEL) |
---|
1510 | break; |
---|
1511 | |
---|
1512 | finfo.fhdr = 0; |
---|
1513 | fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose); |
---|
1514 | if (fillstat < 0) |
---|
1515 | return(fillstat); |
---|
1516 | if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) |
---|
1517 | break; |
---|
1518 | defragTick(verbose); |
---|
1519 | } |
---|
1520 | return(0); |
---|
1521 | } |
---|
1522 | |
---|
1523 | static int |
---|
1524 | defragNewSectorCrc(TDEV *tdp, struct defraghdr *dht, int snum, |
---|
1525 | ulong *newcrc, int verbose) |
---|
1526 | { |
---|
1527 | int firstsnum; /* number of first TFS sector */ |
---|
1528 | int activesnum; /* number of sector currently being written to */ |
---|
1529 | int activessize; /* size of active sector */ |
---|
1530 | char *activeaddr; /* offset being written to in the active sector */ |
---|
1531 | uchar *activesbase; /* base address of active sector */ |
---|
1532 | char *activesend; /* end address of active sector */ |
---|
1533 | struct defraghdr *dhp; /* pointer into defrag header table */ |
---|
1534 | int fullsize; /* size of file and header */ |
---|
1535 | char *new_dend; /* new end of data */ |
---|
1536 | char *new_dbase; /* new base of data */ |
---|
1537 | char *new_hend; /* new end of header */ |
---|
1538 | char *new_hbase; /* new base of header */ |
---|
1539 | char *new_fend; /* new end of file */ |
---|
1540 | char *new_fbase; /* new base of file */ |
---|
1541 | int new_fspan; /* span type for new file */ |
---|
1542 | int new_hspan; /* span type for new header */ |
---|
1543 | int new_dspan; /* span type for new data */ |
---|
1544 | int fillstat; /* result of defragFillFlash() function call */ |
---|
1545 | int ftot; |
---|
1546 | struct fillinfo finfo; |
---|
1547 | struct sectorcrc *crctbl; |
---|
1548 | int lastsnum, tot, sz, temp; |
---|
1549 | |
---|
1550 | /* Retrieve number of first TFS sector: */ |
---|
1551 | if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) |
---|
1552 | return(TFSERR_MEMFAIL); |
---|
1553 | |
---|
1554 | activesnum = snum + firstsnum; |
---|
1555 | crctbl = defragCrcTable(tdp); |
---|
1556 | |
---|
1557 | /* Retrieve information about active sector: */ |
---|
1558 | if (sectortoaddr(activesnum,&activessize,&activesbase) == -1) |
---|
1559 | return(TFSERR_MEMFAIL); |
---|
1560 | |
---|
1561 | if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0) |
---|
1562 | return(TFSERR_MEMFAIL); |
---|
1563 | |
---|
1564 | dhp = (struct defraghdr *)crctbl - 1; |
---|
1565 | ftot = dhp->idx + 1; |
---|
1566 | dhp = dht; |
---|
1567 | activeaddr = (char *)activesbase; |
---|
1568 | activesend = (char *)activesbase + activessize - 1; |
---|
1569 | |
---|
1570 | finfo.tdp = tdp; |
---|
1571 | finfo.crcsz = 0; |
---|
1572 | finfo.crc = 0xffffffff; |
---|
1573 | finfo.asnum = activesnum; |
---|
1574 | finfo.mode = FILLMODE_CRCONLY; |
---|
1575 | |
---|
1576 | for(tot=0;tot<ftot;tot++,dhp++) { |
---|
1577 | finfo.dhp = dhp; |
---|
1578 | |
---|
1579 | fullsize = TFSHDRSIZ + dhp->filsize; |
---|
1580 | new_fbase = dhp->nda; |
---|
1581 | new_fend = (new_fbase + fullsize); |
---|
1582 | |
---|
1583 | new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1584 | (char *)new_fbase,(char *)new_fend); |
---|
1585 | |
---|
1586 | if (new_fspan == SPANTYPE_BPEP) |
---|
1587 | continue; |
---|
1588 | else if (new_fspan == SPANTYPE_BLEL) |
---|
1589 | break; |
---|
1590 | |
---|
1591 | /* Now retrieve span information about header and data |
---|
1592 | * portions of the file (new and orig)... |
---|
1593 | */ |
---|
1594 | new_hbase = new_fbase; |
---|
1595 | new_hend = new_hbase + TFSHDRSIZ; |
---|
1596 | new_dbase = new_hbase + TFSHDRSIZ; |
---|
1597 | new_dend = new_fend; |
---|
1598 | |
---|
1599 | new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1600 | (char *)new_hbase,(char *)new_hend); |
---|
1601 | new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, |
---|
1602 | (char *)new_dbase,(char *)new_dend); |
---|
1603 | |
---|
1604 | finfo.fhdr = 1; |
---|
1605 | fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose); |
---|
1606 | if (fillstat < 0) |
---|
1607 | return(fillstat); |
---|
1608 | if (new_hspan == SPANTYPE_BCEL) |
---|
1609 | break; |
---|
1610 | |
---|
1611 | finfo.fhdr = 0; |
---|
1612 | fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose); |
---|
1613 | if (fillstat < 0) |
---|
1614 | return(fillstat); |
---|
1615 | if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) |
---|
1616 | break; |
---|
1617 | } |
---|
1618 | sz = activessize - finfo.crcsz; |
---|
1619 | |
---|
1620 | /* If this is the last sector, then we must not include the space used |
---|
1621 | * for defrag state storage in the crc calculation. |
---|
1622 | * We deduct size of CRC table, DHT table and the crc of the DSI space... |
---|
1623 | */ |
---|
1624 | if (activesnum == lastsnum) { |
---|
1625 | sz -= (tdp->sectorcount * sizeof(struct sectorcrc)); |
---|
1626 | sz -= (ftot * DEFRAGHDRSIZ); |
---|
1627 | sz -= 4; |
---|
1628 | } |
---|
1629 | while(sz) { |
---|
1630 | temp = (finfo.crc ^ 0xff) & 0x000000FFL; |
---|
1631 | finfo.crc = ((finfo.crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; |
---|
1632 | sz--; |
---|
1633 | } |
---|
1634 | *newcrc = ~finfo.crc; |
---|
1635 | return(0); |
---|
1636 | } |
---|
1637 | |
---|
1638 | /* defragBuildCrcTable(): |
---|
1639 | * Build the table of sector crcs. |
---|
1640 | * This consists of a set of CRCs representing each sector |
---|
1641 | * before defrag starts and after defrag has completed. |
---|
1642 | * One set for each sector. This table is then used if the |
---|
1643 | * defrag process is interrupted to determine the state of |
---|
1644 | * the interrupted defragmentation process. |
---|
1645 | */ |
---|
1646 | int |
---|
1647 | defragBuildCrcTable(TDEV *tdp, struct defraghdr *dht, int verbose) |
---|
1648 | { |
---|
1649 | ulong crc; |
---|
1650 | uchar *sbase; |
---|
1651 | int i, ssize, dhstsize; |
---|
1652 | struct sectorcrc *crctbl; |
---|
1653 | |
---|
1654 | dhstsize = (ulong)(tdp->end+1) - (ulong)dht + 4; |
---|
1655 | crctbl = defragCrcTable(tdp); |
---|
1656 | |
---|
1657 | /* The pre-defrag crc table... |
---|
1658 | * This one's easy because it is simply a crc for each of the current |
---|
1659 | * sectors. |
---|
1660 | */ |
---|
1661 | sbase = (uchar *)tdp->start; |
---|
1662 | for(i=0;i<tdp->sectorcount;i++) { |
---|
1663 | if (addrtosector(sbase,0,&ssize,0) < 0) |
---|
1664 | return(-1); |
---|
1665 | |
---|
1666 | if (i == tdp->sectorcount-1) |
---|
1667 | ssize -= dhstsize; |
---|
1668 | |
---|
1669 | /* The pre-defrag crc: */ |
---|
1670 | crc = crc32(sbase,ssize); |
---|
1671 | if (defragFwrite(7,(uchar *)&crctbl[i].precrc, |
---|
1672 | (uchar *)&crc,4) == -1) { |
---|
1673 | return(-1); |
---|
1674 | } |
---|
1675 | |
---|
1676 | /* The post-defrag crc: */ |
---|
1677 | if (defragNewSectorCrc(tdp,dht,i,&crc,verbose) < 0) |
---|
1678 | return(-1); |
---|
1679 | |
---|
1680 | if (defragFwrite(8,(uchar *)&crctbl[i].postcrc, |
---|
1681 | (uchar *)&crc,4) == -1) { |
---|
1682 | return(-1); |
---|
1683 | } |
---|
1684 | |
---|
1685 | sbase += ssize; |
---|
1686 | |
---|
1687 | defragTick(0); |
---|
1688 | } |
---|
1689 | return(0); |
---|
1690 | } |
---|
1691 | |
---|
1692 | /* _tfsclean(): |
---|
1693 | * This is the front-end of the defragmentation process, following are the |
---|
1694 | * basic steps of defragmentation... |
---|
1695 | * |
---|
1696 | * Build the Defrag State Information (DSI) area: |
---|
1697 | * 1. Create a table of 32-bit CRCs, two for each sector. One is the CRC |
---|
1698 | * of the sector prior to beginning defragmentation and the other is |
---|
1699 | * what will be the CRC of the sector after defragmentation has completed. |
---|
1700 | * These CRCs are used to help recover from an interrupted defragmentation. |
---|
1701 | * 2. Create a table of struct defraghdr structures, one for each file in |
---|
1702 | * TFS that is currently active (not dead). |
---|
1703 | * 3. Create a CRC of the tables created in steps 1 & 2. |
---|
1704 | * |
---|
1705 | * The data created in steps 1-3 is stored at the end of the last sector |
---|
1706 | * used by TFS for file storage. After this is created, the actual flash |
---|
1707 | * defragmentation process starts. |
---|
1708 | * |
---|
1709 | * File relocation: |
---|
1710 | * 4. Step through each sector in TFS flash space, process each file whose |
---|
1711 | * relocated space overlaps with that sector. As each sector is being |
---|
1712 | * re-built, the original version of that sector is stored in the spare. |
---|
1713 | * |
---|
1714 | * End of flash cleanup: |
---|
1715 | * 5. Run through the remaining, now unsused, space in TFS flash and make |
---|
1716 | * sure it is erased. |
---|
1717 | * |
---|
1718 | * File check: |
---|
1719 | * 6. Run a check of all of the relocated files to make sure everything is |
---|
1720 | * still sane. |
---|
1721 | * |
---|
1722 | * Defragmentation success depends on some coordination with tfsadd()... |
---|
1723 | * Whenever a file is added to TFS, tfsadd() must verify that the space |
---|
1724 | * needed for defrag overhead (defrag state & header tables) will be |
---|
1725 | * available. Also, tfsadd() must make sure that the defrag overhead will |
---|
1726 | * always fit into one sector (the sector just prior to the spare). |
---|
1727 | */ |
---|
1728 | |
---|
1729 | int |
---|
1730 | _tfsclean(TDEV *tdp, int restart, int verbose) |
---|
1731 | { |
---|
1732 | int dhstsize; /* Size of state table overhead */ |
---|
1733 | int firstsnum; /* Number of first sector in TFS device. */ |
---|
1734 | int lastsnum; /* Number of last sector in TFS device. */ |
---|
1735 | int lastssize; /* Size of last sector in TFS device. */ |
---|
1736 | uchar *lastsbase; /* Base address of last sector in TFS device. */ |
---|
1737 | int sectorcheck; /* Used to verify proper TFS configuration. */ |
---|
1738 | struct defraghdr *dht; /* Pointer to defrag header table. */ |
---|
1739 | int chkstat; /* Result of tfscheck() after defrag is done. */ |
---|
1740 | int ftot; /* Total number of active files in TFS. */ |
---|
1741 | int dtot; /* Total number of deleted files in TFS. */ |
---|
1742 | int fcnt; /* Running file total, used in hdrtbl build. */ |
---|
1743 | TFILE *tfp; /* Misc file pointer */ |
---|
1744 | char *newaddress; /* Used to calculate "new" location of file. */ |
---|
1745 | struct defraghdr dfhdr; /* Used to build defrag header table. */ |
---|
1746 | int activesnum; /* Sector being worked on restarted defrag. */ |
---|
1747 | struct sectorcrc *crctbl; /* Pointer to table of per-sector crcs. */ |
---|
1748 | int defrag_state; |
---|
1749 | int sidx, snum; |
---|
1750 | char *end; |
---|
1751 | |
---|
1752 | if (TfsCleanEnable < 0) |
---|
1753 | return(TFSERR_CLEANOFF); |
---|
1754 | |
---|
1755 | /* If incoming TFS device pointer is NULL, return error |
---|
1756 | */ |
---|
1757 | if (!tdp) |
---|
1758 | return(TFSERR_BADARG); |
---|
1759 | |
---|
1760 | activesnum = 0; |
---|
1761 | |
---|
1762 | /* If the 'restart' flag is set, then we only want to do a defrag if |
---|
1763 | * we determine that one is already in progress; so we have to look at |
---|
1764 | * the current state of the defrag state table to figure out if a defrag |
---|
1765 | * was active. If not, just return. |
---|
1766 | */ |
---|
1767 | if (restart) { |
---|
1768 | defrag_state = defragGetState(tdp,&activesnum); |
---|
1769 | switch(defrag_state) { |
---|
1770 | case SECTOR_DEFRAG_INACTIVE: |
---|
1771 | case SECTOR_DEFRAG_ABORT_RESTART: |
---|
1772 | return(TFS_OKAY); |
---|
1773 | case SCANNING_ACTIVE_SECTOR_1: |
---|
1774 | case SCANNING_ACTIVE_SECTOR_2: |
---|
1775 | case SCANNING_ACTIVE_SECTOR_3: |
---|
1776 | case SCANNING_ACTIVE_SECTOR_4: |
---|
1777 | case SCANNING_ACTIVE_SECTOR_5: |
---|
1778 | defrag_state = SCANNING_ACTIVE_SECTOR; |
---|
1779 | break; |
---|
1780 | } |
---|
1781 | } |
---|
1782 | else { |
---|
1783 | defrag_state = SECTOR_DEFRAG_INACTIVE; |
---|
1784 | } |
---|
1785 | |
---|
1786 | if (verbose || restart || (!MFLAGS_NODEFRAGPRN())) { |
---|
1787 | printf("TFS device '%s' powersafe defragmentation\n",tdp->prefix); |
---|
1788 | if ((restart) && pollConsole("ok?")) { |
---|
1789 | printf("aborted\n"); |
---|
1790 | return(TFS_OKAY); |
---|
1791 | } |
---|
1792 | } |
---|
1793 | |
---|
1794 | if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) |
---|
1795 | return(TFSERR_MEMFAIL); |
---|
1796 | lastsnum = firstsnum + tdp->sectorcount - 1; |
---|
1797 | if (addrtosector((uchar *)tdp->end,§orcheck,0,0) < 0) |
---|
1798 | return(TFSERR_MEMFAIL); |
---|
1799 | if (lastsnum != sectorcheck) { |
---|
1800 | /* If this error occurs, it is an indication that TFS was not |
---|
1801 | * properly configured in config.h, this error should not occur |
---|
1802 | * if TFS is properly configured. |
---|
1803 | */ |
---|
1804 | printf("%s: SECTORCOUNT != TFSSTART <-> TFSEND\n", tdp->prefix); |
---|
1805 | printf("First TFS sector = %d, last = %d\n",firstsnum,sectorcheck); |
---|
1806 | return(TFSERR_MEMFAIL); |
---|
1807 | } |
---|
1808 | |
---|
1809 | if (defrag_state == SECTOR_DEFRAG_INACTIVE) { |
---|
1810 | activesnum = firstsnum; |
---|
1811 | } |
---|
1812 | |
---|
1813 | /* Retrieve information about last sector: |
---|
1814 | */ |
---|
1815 | if (sectortoaddr(lastsnum,&lastssize,&lastsbase) == -1) |
---|
1816 | return(TFSERR_MEMFAIL); |
---|
1817 | |
---|
1818 | /* Establish a pointer to a table of CRCs that will contain |
---|
1819 | * one 32-bit CRC for each sector (prior to starting the defrag). |
---|
1820 | */ |
---|
1821 | crctbl = defragCrcTable(tdp); |
---|
1822 | |
---|
1823 | /* Retrieve the number of "dead" and "living" files: |
---|
1824 | * If there are no dead files, then there is no need to defrag. |
---|
1825 | * If there are no "living" files, then we can just init the flash. |
---|
1826 | */ |
---|
1827 | ftot = dtot = 0; |
---|
1828 | if (restart && defragValidDSI(tdp,0)) { |
---|
1829 | dht = (struct defraghdr *)crctbl - 1; |
---|
1830 | ftot = dht->idx + 1; |
---|
1831 | } |
---|
1832 | else { |
---|
1833 | tfp = (TFILE *)tdp->start; |
---|
1834 | while(validtfshdr(tfp)) { |
---|
1835 | if (TFS_FILEEXISTS(tfp)) |
---|
1836 | ftot++; |
---|
1837 | else |
---|
1838 | dtot++; |
---|
1839 | tfp = nextfp(tfp,tdp); |
---|
1840 | } |
---|
1841 | if (dtot == 0) { |
---|
1842 | if (verbose) |
---|
1843 | printf("No dead files in %s.\n",tdp->prefix); |
---|
1844 | if (tfsflasherased(tdp,verbose)) |
---|
1845 | return(0); |
---|
1846 | if (verbose) |
---|
1847 | printf("Cleaning up end of flash...\n"); |
---|
1848 | } |
---|
1849 | } |
---|
1850 | if (ftot == 0) { |
---|
1851 | if (verbose) |
---|
1852 | printf("No active files detected, erasing all %s flash...\n", |
---|
1853 | tdp->prefix); |
---|
1854 | _tfsinit(tdp); |
---|
1855 | return(0); |
---|
1856 | } |
---|
1857 | |
---|
1858 | /* Now that we know how many files are in TFS, we can establish |
---|
1859 | * a pointer to the defrag header table, and the size of the table... |
---|
1860 | */ |
---|
1861 | dht = (struct defraghdr *)crctbl - ftot; |
---|
1862 | dhstsize = (ulong)(tdp->end+1) - (ulong)dht; |
---|
1863 | dhstsize += 4; /* Account for the CRC of the state tables. */ |
---|
1864 | |
---|
1865 | if (defrag_state == SECTOR_DEFRAG_INACTIVE) { |
---|
1866 | ulong crc; |
---|
1867 | |
---|
1868 | if (verbose) { |
---|
1869 | printf("TFS defrag: building DSI space...\n"); |
---|
1870 | } |
---|
1871 | |
---|
1872 | /* We start by making sure that the space needed by the |
---|
1873 | * defrag header and state table at the end of the last |
---|
1874 | * sector is clear... |
---|
1875 | */ |
---|
1876 | if (!flasherased((uchar *)dht, (uchar *)(tdp->end))) { |
---|
1877 | if (defragEraseSpare(tdp) < 0) |
---|
1878 | return(TFSERR_FLASHFAILURE); |
---|
1879 | |
---|
1880 | if (defragFwrite(9,(uchar *)(tdp->spare),lastsbase, |
---|
1881 | lastssize-dhstsize) == -1) { |
---|
1882 | return(TFSERR_FLASHFAILURE); |
---|
1883 | } |
---|
1884 | if (defragSerase(5,lastsnum) < 0) { |
---|
1885 | return(TFSERR_FLASHFAILURE); |
---|
1886 | } |
---|
1887 | if (defragFwrite(10,lastsbase,(uchar *)(tdp->spare), |
---|
1888 | lastssize) == -1) { |
---|
1889 | return(TFSERR_FLASHFAILURE); |
---|
1890 | } |
---|
1891 | } |
---|
1892 | |
---|
1893 | /* Erase the spare then copy the portion of the last TFS |
---|
1894 | * sector that does not overlap with the defrag header and |
---|
1895 | * state table area to the spare. We do this so that the spare |
---|
1896 | * sector contains a defrag header and state table area that |
---|
1897 | * is erased. |
---|
1898 | */ |
---|
1899 | if (defragEraseSpare(tdp) < 0) |
---|
1900 | return(TFSERR_FLASHFAILURE); |
---|
1901 | |
---|
1902 | if (defragFwrite(11,(uchar *)tdp->spare, |
---|
1903 | lastsbase,lastssize-dhstsize) == -1) { |
---|
1904 | return(TFSERR_FLASHFAILURE); |
---|
1905 | } |
---|
1906 | |
---|
1907 | /* At this point we have a valid copy of the last sector in |
---|
1908 | * the spare. If any portion of the last sector is not identical |
---|
1909 | * to what is in the spare, then we need to erase the last sector |
---|
1910 | * and re-copy what is in the spare to the last sector. This is |
---|
1911 | * necessary because an interrupt may have occurred while writing |
---|
1912 | * to the last sector, and it may have corrupted something. |
---|
1913 | */ |
---|
1914 | |
---|
1915 | if ((memcmp((char *)lastsbase,(char *)(tdp->spare),lastssize-dhstsize)) || |
---|
1916 | (!flasherased((uchar *)dht,(uchar *)tdp->end))) { |
---|
1917 | if (defragSerase(6,lastsnum) < 0) { |
---|
1918 | return(TFSERR_FLASHFAILURE); |
---|
1919 | } |
---|
1920 | if (defragFwrite(12,lastsbase,(uchar *)(tdp->spare), |
---|
1921 | lastssize) == -1) { |
---|
1922 | return(TFSERR_FLASHFAILURE); |
---|
1923 | } |
---|
1924 | } |
---|
1925 | /* Build the header table: |
---|
1926 | */ |
---|
1927 | fcnt = 0; |
---|
1928 | tfp = (TFILE *)tdp->start; |
---|
1929 | newaddress = (char *)tdp->start; |
---|
1930 | |
---|
1931 | if (verbose > 2) { |
---|
1932 | printf("\nDEFRAG HEADER DATA (dht=0x%lx, ftot=%d):\n", |
---|
1933 | (ulong)dht,ftot); |
---|
1934 | } |
---|
1935 | |
---|
1936 | while(validtfshdr(tfp)) { |
---|
1937 | if (TFS_FILEEXISTS(tfp)) { |
---|
1938 | uchar *base, *eof, *neof, *nbase; |
---|
1939 | int size, slot; |
---|
1940 | struct tfsdat *slotptr; |
---|
1941 | |
---|
1942 | strcpy(dfhdr.fname,TFS_NAME(tfp)); |
---|
1943 | dfhdr.ohdr = tfp; |
---|
1944 | dfhdr.ohdrcrc = tfp->hdrcrc; |
---|
1945 | dfhdr.filsize = TFS_SIZE(tfp); |
---|
1946 | if (addrtosector((uchar *)tfp,0,0,&base) < 0) |
---|
1947 | return(TFSERR_MEMFAIL); |
---|
1948 | |
---|
1949 | eof = (uchar *)(tfp+1)+TFS_SIZE(tfp)-1; |
---|
1950 | if (addrtosector((uchar *)eof,0,0,&base) < 0) |
---|
1951 | return(TFSERR_MEMFAIL); |
---|
1952 | dfhdr.oeso = eof - base + 1; |
---|
1953 | |
---|
1954 | neof = (uchar *)newaddress+TFSHDRSIZ+TFS_SIZE(tfp)-1; |
---|
1955 | if (addrtosector((uchar *)neof,&dfhdr.nesn,0,&nbase) < 0) |
---|
1956 | return(TFSERR_MEMFAIL); |
---|
1957 | dfhdr.neso = neof - nbase + 1; |
---|
1958 | |
---|
1959 | dfhdr.crc = 0; |
---|
1960 | dfhdr.idx = fcnt; |
---|
1961 | dfhdr.nda = newaddress; |
---|
1962 | |
---|
1963 | /* If the file is currently opened, adjust the base address. */ |
---|
1964 | slotptr = tfsSlots; |
---|
1965 | for (slot=0;slot<TFS_MAXOPEN;slot++,slotptr++) { |
---|
1966 | if (slotptr->offset != -1) { |
---|
1967 | if (slotptr->base == (uchar *)(TFS_BASE(tfp))) { |
---|
1968 | slotptr->base = (uchar *)(newaddress+TFSHDRSIZ); |
---|
1969 | } |
---|
1970 | } |
---|
1971 | } |
---|
1972 | size = TFS_SIZE(tfp) + TFSHDRSIZ; |
---|
1973 | if (size & 0xf) { |
---|
1974 | size += TFS_FSIZEMOD; |
---|
1975 | size &= ~(TFS_FSIZEMOD-1); |
---|
1976 | } |
---|
1977 | newaddress += size; |
---|
1978 | dfhdr.nextfile = (TFILE *)newaddress; |
---|
1979 | dfhdr.crc = crc32((uchar *)&dfhdr,DEFRAGHDRSIZ); |
---|
1980 | if (verbose > 2) { |
---|
1981 | printf(" File %s (sz=%d):\n",TFS_NAME(tfp),TFS_SIZE(tfp)); |
---|
1982 | printf(" nda= 0x%08lx, ohdr= 0x%08lx, nxt= 0x%08lx\n", |
---|
1983 | (ulong)(dfhdr.nda),(ulong)(dfhdr.ohdr), |
---|
1984 | (ulong)(dfhdr.nextfile)); |
---|
1985 | printf(" oeso= 0x%08lx, nesn= 0x%08lx, neso= 0x%08lx\n", |
---|
1986 | (ulong)(dfhdr.oeso),(ulong)(dfhdr.nesn), |
---|
1987 | (ulong)(dfhdr.neso)); |
---|
1988 | } |
---|
1989 | if (defragFwrite(13,(uchar *)(&dht[fcnt]), |
---|
1990 | (uchar *)(&dfhdr),DEFRAGHDRSIZ) == -1) { |
---|
1991 | return(TFSERR_FLASHFAILURE); |
---|
1992 | } |
---|
1993 | fcnt++; |
---|
1994 | defragTick(0); |
---|
1995 | } |
---|
1996 | tfp = nextfp(tfp,tdp); |
---|
1997 | } |
---|
1998 | |
---|
1999 | if (defragBuildCrcTable(tdp,dht,verbose) < 0) |
---|
2000 | return(TFSERR_FLASHFAILURE); |
---|
2001 | |
---|
2002 | /* Now, the last part of the state table build is to store a |
---|
2003 | * 32-bit crc of the data we just wrote... |
---|
2004 | */ |
---|
2005 | crc = crc32((uchar *)dht,(uchar *)tdp->end - (uchar *)dht); |
---|
2006 | if (defragFwrite(14,(uchar *)((ulong *)dht-1),(uchar *)&crc,4) == -1) { |
---|
2007 | return(TFSERR_FLASHFAILURE); |
---|
2008 | } |
---|
2009 | |
---|
2010 | defrag_state = SCANNING_ACTIVE_SECTOR; |
---|
2011 | } |
---|
2012 | |
---|
2013 | /* Exit here to have a complete defrag header installed. */ |
---|
2014 | defragExitTestPoint(1000); |
---|
2015 | |
---|
2016 | if (defrag_state == SCANNING_ACTIVE_SECTOR) { |
---|
2017 | |
---|
2018 | if (verbose) { |
---|
2019 | printf("TFS: updating sectors %d-%d...\n", |
---|
2020 | activesnum,lastsnum); |
---|
2021 | } |
---|
2022 | |
---|
2023 | /* Now we begin the actual defragmentation. We have built enough |
---|
2024 | * state information (defrag header and state table) into the last |
---|
2025 | * TFS sector, so now we can start the cleanup. |
---|
2026 | */ |
---|
2027 | for(sidx = activesnum - firstsnum; sidx < tdp->sectorcount; sidx++) { |
---|
2028 | if (defragFillActiveSector(tdp,ftot,sidx,verbose) < 0) |
---|
2029 | return(TFSERR_FLASHFAILURE); |
---|
2030 | } |
---|
2031 | |
---|
2032 | defrag_state = SECTOR_DEFRAG_ALMOST_DONE; |
---|
2033 | } |
---|
2034 | |
---|
2035 | /* Exit here to test "almost-done" state detection. */ |
---|
2036 | defragExitTestPoint(1001); |
---|
2037 | |
---|
2038 | if (defrag_state == SECTOR_DEFRAG_ALMOST_DONE) { |
---|
2039 | |
---|
2040 | /* We've completed the relocation of all files into a defragmented |
---|
2041 | * area of TFS flash space. Now we have to erase all sectors after |
---|
2042 | * the sector used by the last file in TFS (including the spare)... |
---|
2043 | * If the last file in TFS uses the last sector, then the defrag |
---|
2044 | * header table will be erased and there is nothing left to do |
---|
2045 | * except erase the spare. |
---|
2046 | */ |
---|
2047 | if (verbose) { |
---|
2048 | printf("TFS: clearing available space...\n"); |
---|
2049 | } |
---|
2050 | if (dht[ftot-1].crc != ERASED32) { |
---|
2051 | end = (dht[ftot-1].nda + dht[ftot-1].filsize + TFSHDRSIZ) - 1; |
---|
2052 | if (addrtosector((uchar *)end,&snum,0,0) < 0) |
---|
2053 | return(TFSERR_FLASHFAILURE); |
---|
2054 | snum++; |
---|
2055 | while(snum <= lastsnum) { |
---|
2056 | if (defragSerase(7,snum) < 0) |
---|
2057 | return(TFSERR_FLASHFAILURE); |
---|
2058 | snum++; |
---|
2059 | defragTick(0); |
---|
2060 | } |
---|
2061 | } |
---|
2062 | if (defragEraseSpare(tdp) < 0) |
---|
2063 | return(TFSERR_FLASHFAILURE); |
---|
2064 | |
---|
2065 | /* All defragmentation is done, so verify sanity of files... */ |
---|
2066 | chkstat = tfscheck(tdp,verbose); |
---|
2067 | } |
---|
2068 | else { |
---|
2069 | chkstat = TFS_OKAY; |
---|
2070 | } |
---|
2071 | |
---|
2072 | if ((verbose) || (!MFLAGS_NODEFRAGPRN())) |
---|
2073 | printf("Defragmentation complete\n"); |
---|
2074 | |
---|
2075 | return(chkstat); |
---|
2076 | } |
---|
2077 | |
---|
2078 | /* tfsfixup(): |
---|
2079 | * Called at system startup to finish up a TFS defragmentation if one |
---|
2080 | * was in progress. |
---|
2081 | */ |
---|
2082 | int |
---|
2083 | tfsfixup(int verbose, int dontquery) |
---|
2084 | { |
---|
2085 | TDEV *tdp; |
---|
2086 | |
---|
2087 | /* Clear test data... */ |
---|
2088 | DefragTestType = 0; |
---|
2089 | DefragTestPoint = 0; |
---|
2090 | DefragTestSector = 0; |
---|
2091 | |
---|
2092 | #if !DEFRAG_TEST_ENABLED |
---|
2093 | tfsTrace = 99; |
---|
2094 | #endif |
---|
2095 | |
---|
2096 | /* For each TFS device, run defrag with "fixup" flag set to let |
---|
2097 | * the defragger know that it should only defrag if a defrag was |
---|
2098 | * in progress. |
---|
2099 | */ |
---|
2100 | for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { |
---|
2101 | /* Call tfsclean() with fixup flag set... */ |
---|
2102 | #if TFS_VERBOSE_STARTUP |
---|
2103 | if (StateOfMonitor == INITIALIZE) |
---|
2104 | printf("TFS Scanning %s...\n",tdp->prefix); |
---|
2105 | #endif |
---|
2106 | _tfsclean(tdp,1,99); |
---|
2107 | } |
---|
2108 | |
---|
2109 | #if !DEFRAG_TEST_ENABLED |
---|
2110 | tfsTrace = 0; |
---|
2111 | #endif |
---|
2112 | return(0); |
---|
2113 | } |
---|
2114 | |
---|
2115 | #if DEFRAG_TEST_ENABLED |
---|
2116 | int |
---|
2117 | dumpDhdr(DEFRAGHDR *dhp) |
---|
2118 | { |
---|
2119 | printf("ohdr: 0x%08lx\n",(ulong)dhp->ohdr); |
---|
2120 | printf("nextfile: 0x%08lx\n",(ulong)dhp->nextfile); |
---|
2121 | printf("filsize: 0x%08lx\n",(ulong)dhp->filsize); |
---|
2122 | printf("crc: 0x%08lx\n",(ulong)dhp->crc); |
---|
2123 | printf("idx: 0x%08lx\n",(ulong)dhp->idx); |
---|
2124 | printf("nesn: 0x%08lx\n",(ulong)dhp->nesn); |
---|
2125 | printf("neso: 0x%08lx\n",(ulong)dhp->neso); |
---|
2126 | printf("nda: 0x%08lx\n",(ulong)dhp->nda); |
---|
2127 | printf("fname: %s\n",dhp->fname); |
---|
2128 | return(TFS_OKAY); |
---|
2129 | } |
---|
2130 | |
---|
2131 | int |
---|
2132 | dumpDhdrTbl(DEFRAGHDR *dhp, int ftot) |
---|
2133 | { |
---|
2134 | TDEV *tdp; |
---|
2135 | uchar *sbase; |
---|
2136 | ulong *crc, calccrc; |
---|
2137 | int i, ssize, snum; |
---|
2138 | struct sectorcrc *crctbl; |
---|
2139 | |
---|
2140 | for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { |
---|
2141 | |
---|
2142 | if (!dhp) { |
---|
2143 | crctbl = defragCrcTable(tdp); |
---|
2144 | printf("Device %s...\n",tdp->prefix); |
---|
2145 | dhp = (struct defraghdr *)crctbl - 1; |
---|
2146 | ftot = dhp->idx + 1; |
---|
2147 | printf("(%d files):\n",ftot); |
---|
2148 | dhp = (struct defraghdr *)crctbl - ftot; |
---|
2149 | crc = (ulong *)dhp-1; |
---|
2150 | if (*crc != crc32((uchar *)dhp,(uchar *)tdp->end - (uchar *)dhp)) { |
---|
2151 | printf("Table CRC failure\n"); |
---|
2152 | return(TFS_OKAY); |
---|
2153 | } |
---|
2154 | } |
---|
2155 | else |
---|
2156 | crctbl = (struct sectorcrc *)(dhp + ftot); |
---|
2157 | |
---|
2158 | printf("dhp=0x%lx, ftot=%d\n",(ulong)dhp,ftot); |
---|
2159 | |
---|
2160 | while(dhp < (struct defraghdr *)crctbl) { |
---|
2161 | printf(" %s (dhp=0x%lx, idx=%ld):\n", |
---|
2162 | dhp->fname,(ulong)dhp,dhp->idx); |
---|
2163 | printf(" nda: 0x%08lx, ohdr: 0x%08lx\n", |
---|
2164 | (ulong)dhp->nda,(ulong)dhp->ohdr); |
---|
2165 | dhp++; |
---|
2166 | } |
---|
2167 | |
---|
2168 | sbase = (uchar *)tdp->start; |
---|
2169 | printf("crctbl at 0x%lx\n",(ulong)crctbl); |
---|
2170 | for(i=0;i<tdp->sectorcount;i++) { |
---|
2171 | if (addrtosector(sbase,&snum,&ssize,0) < 0) |
---|
2172 | return(0); |
---|
2173 | if (i == tdp->sectorcount-1) { |
---|
2174 | ssize -= /* CRC table */ |
---|
2175 | (tdp->sectorcount * sizeof(struct sectorcrc)); |
---|
2176 | ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ |
---|
2177 | ssize -= 4; /* Crc of the tables */ |
---|
2178 | } |
---|
2179 | calccrc = crc32(sbase,ssize); |
---|
2180 | if (calccrc == crctbl[i].precrc) |
---|
2181 | printf("crctbl[%d] (snum=%d) pre-pass\n",i,snum); |
---|
2182 | else if (calccrc == crctbl[i].postcrc) |
---|
2183 | printf("crctbl[%d] (snum=%d) post-pass\n",i,snum); |
---|
2184 | else { |
---|
2185 | printf("crctbl[%d] (snum=%d) test failed\n",i,snum); |
---|
2186 | printf("pre: 0x%lx, post: 0x%lx,calc: 0x%lx\n", |
---|
2187 | crctbl[i].precrc,crctbl[i].postcrc,calccrc); |
---|
2188 | } |
---|
2189 | sbase += ssize; |
---|
2190 | } |
---|
2191 | } |
---|
2192 | return(TFS_OKAY); |
---|
2193 | } |
---|
2194 | #endif /* DEFRAG_TEST_ENABLED */ |
---|
2195 | #endif /* INCLUDE_TFS */ |
---|