1 /*
2 * NFTL mount code with extensive checks
3 *
4 * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
5 * Copyright (C) 2000 Netgem S.A.
6 *
7 * $Id: nftlmount.c,v 1.11 2000/11/17 12:24:09 ollie Exp $
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <asm/errno.h>
26 #include <asm/io.h>
27 #include <asm/uaccess.h>
28 #include <linux/miscdevice.h>
29 #include <linux/pci.h>
30 #include <linux/delay.h>
31 #include <linux/malloc.h>
32 #include <linux/sched.h>
33 #include <linux/init.h>
34 #include <linux/mtd/mtd.h>
35 #include <linux/mtd/nftl.h>
36 #include <linux/mtd/compatmac.h>
37
38 #define SECTORSIZE 512
39
40 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
41 * various device information of the NFTL partition and Bad Unit Table. Update
42 * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
43 * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
44 */
45 static int find_boot_record(struct NFTLrecord *nftl)
46 {
47 struct nftl_uci1 h1;
48 struct nftl_oob oob;
49 unsigned int block, boot_record_count;
50 int retlen;
51 u8 buf[SECTORSIZE];
52 struct NFTLMediaHeader *mh = &nftl->MediaHdr;
53
54 nftl->MediaUnit = BLOCK_NIL;
55 nftl->SpareMediaUnit = BLOCK_NIL;
56 boot_record_count = 0;
57
58 /* search for a valid boot record */
59 for (block = 0; block < nftl->nb_blocks; block++) {
60 unsigned int erase_mark;
61
62 /* read ANAND header. To be safer with BIOS, also use erase mark as discriminant */
63 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
64 8, &retlen, (char *)&h1) < 0)
65 continue;
66
67 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
68 if (erase_mark != ERASE_MARK)
69 continue;
70
71 if (MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
72 &retlen, buf, (char *)&oob) < 0)
73 continue;
74
75 memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
76 if (memcmp(mh->DataOrgID, "ANAND", 6) == 0) {
77 /* first boot record */
78 if (boot_record_count == 0) {
79 unsigned int i;
80 /* header found : read the bad block table data */
81 if (mh->UnitSizeFactor != 0xff) {
82 printk("Sorry, we don't support UnitSizeFactor "
83 "of != 1 yet\n");
84 goto ReplUnitTable;
85 }
86
87 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
88 if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks)
89 goto ReplUnitTable; /* small consistency check */
90
91 nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
92 if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2))
93 goto ReplUnitTable; /* small consistency check */
94
95 /* FixMe: with bad blocks, the total size available is not FormattedSize any
96 more !!! */
97 nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
98 nftl->MediaUnit = block;
99
100 /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
101 for (i = 0; i < nftl->nb_blocks; i++) {
102 if ((i & (SECTORSIZE - 1)) == 0) {
103 /* read one sector for every SECTORSIZE of blocks */
104 if (MTD_READECC(nftl->mtd, block * nftl->EraseSize +
105 i + SECTORSIZE, SECTORSIZE,
106 &retlen, buf, (char *)&oob) < 0)
107 goto ReplUnitTable;
108 }
109 /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
110 if (buf[i & (SECTORSIZE - 1)] != 0xff)
111 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
112 }
113
114 boot_record_count++;
115 } else if (boot_record_count == 1) {
116 nftl->SpareMediaUnit = block;
117 boot_record_count++;
118 break;
119 }
120 }
121 ReplUnitTable:
122 }
123
124 if (boot_record_count == 0) {
125 /* no boot record found */
126 return -1;
127 } else {
128 return 0;
129 }
130 }
131
132 static int memcmpb(void *a, int c, int n)
133 {
134 int i;
135 for (i = 0; i < n; i++) {
136 if (c != ((unsigned char *)a)[i])
137 return 1;
138 }
139 return 0;
140 }
141
142 /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
143 static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
144 int check_oob)
145 {
146 int i, retlen;
147 u8 buf[SECTORSIZE];
148
149 for (i = 0; i < len; i += SECTORSIZE) {
150 /* we want to read the sector without ECC check here since a free
151 sector does not have ECC syndrome on it yet */
152 if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)
153 return -1;
154 if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
155 return -1;
156
157 if (check_oob) {
158 if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,
159 &retlen, buf) < 0)
160 return -1;
161 if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)
162 return -1;
163 }
164 address += SECTORSIZE;
165 }
166
167 return 0;
168 }
169
170 /* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and
171 * Update NFTL metadata. Each erase operation is checked with check_free_sectors
172 *
173 * Return: 0 when succeed, -1 on error.
174 *
175 * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
176 * 2. UnitSizeFactor != 0xFF
177 */
178 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
179 {
180 int retlen;
181 unsigned int nb_erases, erase_mark;
182 struct nftl_uci1 uci;
183 struct erase_info *instr = &nftl->instr;
184
185 /* Read the Unit Control Information #1 for Wear-Leveling */
186 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
187 8, &retlen, (char *)&uci) < 0)
188 goto default_uci1;
189
190 erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
191 if (erase_mark != ERASE_MARK) {
192 default_uci1:
193 uci.EraseMark = cpu_to_le16(ERASE_MARK);
194 uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
195 uci.WearInfo = cpu_to_le32(0);
196 }
197
198 memset(instr, 0, sizeof(struct erase_info));
199
200 /* XXX: use async erase interface, XXX: test return code */
201 instr->addr = block * nftl->EraseSize;
202 instr->len = nftl->EraseSize;
203 MTD_ERASE(nftl->mtd, instr);
204
205 if (instr->state == MTD_ERASE_FAILED) {
206 /* could not format, FixMe: We should update the BadUnitTable
207 both in memory and on disk */
208 printk("Error while formatting block %d\n", block);
209 return -1;
210 } else {
211 /* increase and write Wear-Leveling info */
212 nb_erases = le32_to_cpu(uci.WearInfo);
213 nb_erases++;
214
215 /* wrap (almost impossible with current flashs) or free block */
216 if (nb_erases == 0)
217 nb_erases = 1;
218
219 /* check the "freeness" of Erase Unit before updating metadata
220 * FixMe: is this check really necessary ? since we have check the
221 * return code after the erase operation. */
222 if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
223 return -1;
224
225 uci.WearInfo = le32_to_cpu(nb_erases);
226 if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
227 &retlen, (char *)&uci) < 0)
228 return -1;
229 return 0;
230 }
231 }
232
233 /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
234 * Mark as 'IGNORE' each incorrect sector. This check is only done if the chain
235 * was being folded when NFTL was interrupted.
236 *
237 * The check_free_sectors in this function is neceressary. There is a possible
238 * situation that after writing the Data area, the Block Control Information is
239 * not updated according (due to power failure or something) which leaves the block
240 * in an umconsistent state. So we have to check if a block is really FREE in this
241 * case. */
242 static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
243 {
244 unsigned int block, i, status;
245 struct nftl_bci bci;
246 int sectors_per_block, retlen;
247
248 sectors_per_block = nftl->EraseSize / SECTORSIZE;
249 block = first_block;
250 for (;;) {
251 for (i = 0; i < sectors_per_block; i++) {
252 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,
253 8, &retlen, (char *)&bci) < 0)
254 status = SECTOR_IGNORE;
255 else
256 status = bci.Status | bci.Status1;
257
258 switch(status) {
259 case SECTOR_FREE:
260 /* verify that the sector is really free. If not, mark
261 as ignore */
262 if (memcmpb(&bci, 0xff, 8) != 0 ||
263 check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
264 SECTORSIZE, 0) != 0) {
265 printk("Incorrect free sector %d in block %d: "
266 "marking it as ignored\n",
267 i, block);
268
269 /* sector not free actually : mark it as SECTOR_IGNORE */
270 bci.Status = SECTOR_IGNORE;
271 bci.Status1 = SECTOR_IGNORE;
272 MTD_WRITEOOB(nftl->mtd,
273 block * nftl->EraseSize + i * SECTORSIZE,
274 8, &retlen, (char *)&bci);
275 }
276 break;
277 default:
278 break;
279 }
280 }
281
282 /* proceed to next Erase Unit on the chain */
283 block = nftl->ReplUnitTable[block];
284 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
285 printk("incorrect ReplUnitTable[] : %d\n", block);
286 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
287 break;
288 }
289 }
290
291 /* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */
292 static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
293 {
294 unsigned int length = 0, block = first_block;
295
296 for (;;) {
297 length++;
298 /* avoid infinite loops, although this is guaranted not to
299 happen because of the previous checks */
300 if (length >= nftl->nb_blocks) {
301 printk("nftl: length too long %d !\n", length);
302 break;
303 }
304
305 block = nftl->ReplUnitTable[block];
306 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
307 printk("incorrect ReplUnitTable[] : %d\n", block);
308 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
309 break;
310 }
311 return length;
312 }
313
314 /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a
315 * Virtual Unit Chain, i.e. all the units are disconnected.
316 *
317 * It is not stricly correct to begin from the first block of the chain because
318 * if we stop the code, we may see again a valid chain if there was a first_block
319 * flag in a block inside it. But is it really a problem ?
320 *
321 * FixMe: Figure out what the last statesment means. What if power failure when we are
322 * in the for (;;) loop formatting blocks ??
323 */
324 static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
325 {
326 unsigned int block = first_block, block1;
327
328 printk("Formatting chain at block %d\n", first_block);
329
330 for (;;) {
331 block1 = nftl->ReplUnitTable[block];
332
333 printk("Formatting block %d\n", block);
334 if (NFTL_formatblock(nftl, block) < 0) {
335 /* cannot format !!!! Mark it as Bad Unit,
336 FixMe: update the BadUnitTable on disk */
337 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
338 } else {
339 nftl->ReplUnitTable[block] = BLOCK_FREE;
340 }
341
342 /* goto next block on the chain */
343 block = block1;
344
345 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
346 printk("incorrect ReplUnitTable[] : %d\n", block);
347 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
348 break;
349 }
350 }
351
352 /* check_and_mark_free_block: Verify that a block is free in the NFTL sense (valid erase mark) or
353 * totally free (only 0xff).
354 *
355 * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the
356 * following critia:
357 * 1. */
358 static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
359 {
360 struct nftl_uci1 h1;
361 unsigned int erase_mark;
362 int i, retlen;
363 unsigned char buf[SECTORSIZE];
364
365 /* check erase mark. */
366 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
367 &retlen, (char *)&h1) < 0)
368 return -1;
369
370 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
371 if (erase_mark != ERASE_MARK) {
372 /* if no erase mark, the block must be totally free. This is
373 possible in two cases : empty filsystem or interrupted erase (very unlikely) */
374 if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
375 return -1;
376
377 /* free block : write erase mark */
378 h1.EraseMark = cpu_to_le16(ERASE_MARK);
379 h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
380 h1.WearInfo = cpu_to_le32(0);
381 if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
382 &retlen, (char *)&h1) < 0)
383 return -1;
384 } else {
385 #if 0
386 /* if erase mark present, need to skip it when doing check */
387 for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
388 /* check free sector */
389 if (check_free_sectors (nftl, block * nftl->EraseSize + i,
390 SECTORSIZE, 0) != 0)
391 return -1;
392
393 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i,
394 16, &retlen, buf) < 0)
395 return -1;
396 if (i == SECTORSIZE) {
397 /* skip erase mark */
398 if (memcmpb(buf, 0xff, 8))
399 return -1;
400 } else {
401 if (memcmpb(buf, 0xff, 16))
402 return -1;
403 }
404 }
405 #endif
406 }
407
408 return 0;
409 }
410
411 /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS
412 * to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2
413 * is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted
414 * for some reason. A clean up/check of the VUC is neceressary in this case.
415 *
416 * WARNING: return 0 if read error
417 */
418 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
419 {
420 struct nftl_uci2 uci;
421 int retlen;
422
423 if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
424 8, &retlen, (char *)&uci) < 0)
425 return 0;
426
427 return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
428 }
429
430 int NFTL_mount(struct NFTLrecord *s)
431 {
432 int i;
433 unsigned int first_logical_block, logical_block, rep_block, nb_erases, erase_mark;
434 unsigned int block, first_block, is_first_block;
435 int chain_length, do_format_chain;
436 struct nftl_uci0 h0;
437 struct nftl_uci1 h1;
438 int retlen;
439
440 /* XXX: will be suppressed */
441 s->lastEUN = s->nb_blocks - 1;
442
443 /* memory alloc */
444 s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
445 s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
446 if (!s->EUNtable || !s->ReplUnitTable) {
447 fail:
448 if (s->EUNtable)
449 kfree(s->EUNtable);
450 if (s->ReplUnitTable)
451 kfree(s->ReplUnitTable);
452 return -1;
453 }
454
455 /* mark all blocks as potentially containing data */
456 for (i = 0; i < s->nb_blocks; i++) {
457 s->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
458 }
459
460 /* search for NFTL MediaHeader and Spare NFTL Media Header */
461 if (find_boot_record(s) < 0) {
462 printk("Could not find valid boot record\n");
463 goto fail;
464 }
465
466 /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
467 for (i = 0; i < s->nb_boot_blocks; i++)
468 s->ReplUnitTable[i] = BLOCK_RESERVED;
469
470 /* also mark the boot records (NFTL MediaHeader) blocks as reserved */
471 if (s->MediaUnit != BLOCK_NIL)
472 s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED;
473 if (s->SpareMediaUnit != BLOCK_NIL)
474 s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED;
475
476 /* init the logical to physical table */
477 for (i = 0; i < s->nb_blocks; i++) {
478 s->EUNtable[i] = BLOCK_NIL;
479 }
480
481 /* first pass : explore each block chain */
482 first_logical_block = 0;
483 for (first_block = 0; first_block < s->nb_blocks; first_block++) {
484 /* if the block was not already explored, we can look at it */
485 if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
486 block = first_block;
487 chain_length = 0;
488 do_format_chain = 0;
489
490 for (;;) {
491 /* read the block header. If error, we format the chain */
492 if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8,
493 &retlen, (char *)&h0) < 0 ||
494 MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
495 &retlen, (char *)&h1) < 0) {
496 s->ReplUnitTable[block] = BLOCK_NIL;
497 do_format_chain = 1;
498 break;
499 }
500
501 logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
502 rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
503 nb_erases = le32_to_cpu (h1.WearInfo);
504 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
505
506 is_first_block = !(logical_block >> 15);
507 logical_block = logical_block & 0x7fff;
508
509 /* invalid/free block test */
510 if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
511 if (chain_length == 0) {
512 /* if not currently in a chain, we can handle it safely */
513 if (check_and_mark_free_block(s, block) < 0) {
514 /* not really free: format it */
515 printk("Formatting block %d\n", block);
516 if (NFTL_formatblock(s, block) < 0) {
517 /* could not format: reserve the block */
518 s->ReplUnitTable[block] = BLOCK_RESERVED;
519 } else {
520 s->ReplUnitTable[block] = BLOCK_FREE;
521 }
522 } else {
523 /* free block: mark it */
524 s->ReplUnitTable[block] = BLOCK_FREE;
525 }
526 /* directly examine the next block. */
527 goto examine_ReplUnitTable;
528 } else {
529 /* the block was in a chain : this is bad. We
530 must format all the chain */
531 printk("Block %d: free but referenced in chain %d\n",
532 block, first_block);
533 s->ReplUnitTable[block] = BLOCK_NIL;
534 do_format_chain = 1;
535 break;
536 }
537 }
538
539 /* we accept only first blocks here */
540 if (chain_length == 0) {
541 /* this block is not the first block in chain :
542 ignore it, it will be included in a chain
543 later, or marked as not explored */
544 if (!is_first_block)
545 goto examine_ReplUnitTable;
546 first_logical_block = logical_block;
547 } else {
548 if (logical_block != first_logical_block) {
549 printk("Block %d: incorrect logical block: %d expected: %d\n",
550 block, logical_block, first_logical_block);
551 /* the chain is incorrect : we must format it,
552 but we need to read it completly */
553 do_format_chain = 1;
554 }
555 if (is_first_block) {
556 /* we accept that a block is marked as first
557 block while being last block in a chain
558 only if the chain is being folded */
559 if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
560 rep_block != 0xffff) {
561 printk("Block %d: incorrectly marked as first block in chain\n",
562 block);
563 /* the chain is incorrect : we must format it,
564 but we need to read it completly */
565 do_format_chain = 1;
566 } else {
567 printk("Block %d: folding in progress - ignoring first block flag\n",
568 block);
569 }
570 }
571 }
572 chain_length++;
573 if (rep_block == 0xffff) {
574 /* no more blocks after */
575 s->ReplUnitTable[block] = BLOCK_NIL;
576 break;
577 } else if (rep_block >= s->nb_blocks) {
578 printk("Block %d: referencing invalid block %d\n",
579 block, rep_block);
580 do_format_chain = 1;
581 s->ReplUnitTable[block] = BLOCK_NIL;
582 break;
583 } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
584 /* same problem as previous 'is_first_block' test:
585 we accept that the last block of a chain has
586 the first_block flag set if folding is in
587 progress. We handle here the case where the
588 last block appeared first */
589 if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
590 s->EUNtable[first_logical_block] == rep_block &&
591 get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
592 /* EUNtable[] will be set after */
593 printk("Block %d: folding in progress - ignoring first block flag\n",
594 rep_block);
595 s->ReplUnitTable[block] = rep_block;
596 s->EUNtable[first_logical_block] = BLOCK_NIL;
597 } else {
598 printk("Block %d: referencing block %d already in another chain\n",
599 block, rep_block);
600 /* XXX: should handle correctly fold in progress chains */
601 do_format_chain = 1;
602 s->ReplUnitTable[block] = BLOCK_NIL;
603 }
604 break;
605 } else {
606 /* this is OK */
607 s->ReplUnitTable[block] = rep_block;
608 block = rep_block;
609 }
610 }
611
612 /* the chain was completely explored. Now we can decide
613 what to do with it */
614 if (do_format_chain) {
615 /* invalid chain : format it */
616 format_chain(s, first_block);
617 } else {
618 unsigned int first_block1, chain_to_format, chain_length1;
619 int fold_mark;
620
621 /* valid chain : get foldmark */
622 fold_mark = get_fold_mark(s, first_block);
623 if (fold_mark == 0) {
624 /* cannot get foldmark : format the chain */
625 printk("Could read foldmark at block %d\n", first_block);
626 format_chain(s, first_block);
627 } else {
628 if (fold_mark == FOLD_MARK_IN_PROGRESS)
629 check_sectors_in_chain(s, first_block);
630
631 /* now handle the case where we find two chains at the
632 same virtual address : we select the longer one,
633 because the shorter one is the one which was being
634 folded if the folding was not done in place */
635 first_block1 = s->EUNtable[first_logical_block];
636 if (first_block1 != BLOCK_NIL) {
637 /* XXX: what to do if same length ? */
638 chain_length1 = calc_chain_length(s, first_block1);
639 printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
640 first_block1, chain_length1, first_block, chain_length);
641
642 if (chain_length >= chain_length1) {
643 chain_to_format = first_block1;
644 s->EUNtable[first_logical_block] = first_block;
645 } else {
646 chain_to_format = first_block;
647 }
648 format_chain(s, chain_to_format);
649 } else {
650 s->EUNtable[first_logical_block] = first_block;
651 }
652 }
653 }
654 }
655 examine_ReplUnitTable:
656 }
657
658 /* second pass to format unreferenced blocks and init free block count */
659 s->numfreeEUNs = 0;
660 s->LastFreeEUN = BLOCK_NIL;
661
662 for (block = 0; block < s->nb_blocks; block++) {
663 if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
664 printk("Unreferenced block %d, formatting it\n", block);
665 if (NFTL_formatblock(s, block) < 0)
666 s->ReplUnitTable[block] = BLOCK_RESERVED;
667 else
668 s->ReplUnitTable[block] = BLOCK_FREE;
669 }
670 if (s->ReplUnitTable[block] == BLOCK_FREE) {
671 s->numfreeEUNs++;
672 s->LastFreeEUN = block;
673 }
674 }
675
676 return 0;
677 }
678
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.