in inftlmount.c [526:776]
int INFTL_mount(struct INFTLrecord *s)
{
struct mtd_info *mtd = s->mbd.mtd;
unsigned int block, first_block, prev_block, last_block;
unsigned int first_logical_block, logical_block, erase_mark;
int chain_length, do_format_chain;
struct inftl_unithead1 h0;
struct inftl_unittail h1;
size_t retlen;
int i;
u8 *ANACtable, ANAC;
pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s);
/* Search for INFTL MediaHeader and Spare INFTL Media Header */
if (find_boot_record(s) < 0) {
printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
return -ENXIO;
}
/* Init the logical to physical table */
for (i = 0; i < s->nb_blocks; i++)
s->VUtable[i] = BLOCK_NIL;
logical_block = block = BLOCK_NIL;
/* Temporary buffer to store ANAC numbers. */
ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
if (!ANACtable)
return -ENOMEM;
/*
* First pass is to explore each physical unit, and construct the
* virtual chains that exist (newest physical unit goes into VUtable).
* Any block that is in any way invalid will be left in the
* NOTEXPLORED state. Then at the end we will try to format it and
* mark it as free.
*/
pr_debug("INFTL: pass 1, explore each unit\n");
for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {
if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)
continue;
do_format_chain = 0;
first_logical_block = BLOCK_NIL;
last_block = BLOCK_NIL;
block = first_block;
for (chain_length = 0; ; chain_length++) {
if ((chain_length == 0) &&
(s->PUtable[block] != BLOCK_NOTEXPLORED)) {
/* Nothing to do here, onto next block */
break;
}
if (inftl_read_oob(mtd, block * s->EraseSize + 8,
8, &retlen, (char *)&h0) < 0 ||
inftl_read_oob(mtd, block * s->EraseSize +
2 * SECTORSIZE + 8, 8, &retlen,
(char *)&h1) < 0) {
/* Should never happen? */
do_format_chain++;
break;
}
logical_block = le16_to_cpu(h0.virtualUnitNo);
prev_block = le16_to_cpu(h0.prevUnitNo);
erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));
ANACtable[block] = h0.ANAC;
/* Previous block is relative to start of Partition */
if (prev_block < s->nb_blocks)
prev_block += s->firstEUN;
/* Already explored partial chain? */
if (s->PUtable[block] != BLOCK_NOTEXPLORED) {
/* Check if chain for this logical */
if (logical_block == first_logical_block) {
if (last_block != BLOCK_NIL)
s->PUtable[last_block] = block;
}
break;
}
/* Check for invalid block */
if (erase_mark != ERASE_MARK) {
printk(KERN_WARNING "INFTL: corrupt block %d "
"in chain %d, chain length %d, erase "
"mark 0x%x?\n", block, first_block,
chain_length, erase_mark);
/*
* Assume end of chain, probably incomplete
* fold/erase...
*/
if (chain_length == 0)
do_format_chain++;
break;
}
/* Check for it being free already then... */
if ((logical_block == BLOCK_FREE) ||
(logical_block == BLOCK_NIL)) {
s->PUtable[block] = BLOCK_FREE;
break;
}
/* Sanity checks on block numbers */
if ((logical_block >= s->nb_blocks) ||
((prev_block >= s->nb_blocks) &&
(prev_block != BLOCK_NIL))) {
if (chain_length > 0) {
printk(KERN_WARNING "INFTL: corrupt "
"block %d in chain %d?\n",
block, first_block);
do_format_chain++;
}
break;
}
if (first_logical_block == BLOCK_NIL) {
first_logical_block = logical_block;
} else {
if (first_logical_block != logical_block) {
/* Normal for folded chain... */
break;
}
}
/*
* Current block is valid, so if we followed a virtual
* chain to get here then we can set the previous
* block pointer in our PUtable now. Then move onto
* the previous block in the chain.
*/
s->PUtable[block] = BLOCK_NIL;
if (last_block != BLOCK_NIL)
s->PUtable[last_block] = block;
last_block = block;
block = prev_block;
/* Check for end of chain */
if (block == BLOCK_NIL)
break;
/* Validate next block before following it... */
if (block > s->lastEUN) {
printk(KERN_WARNING "INFTL: invalid previous "
"block %d in chain %d?\n", block,
first_block);
do_format_chain++;
break;
}
}
if (do_format_chain) {
format_chain(s, first_block);
continue;
}
/*
* Looks like a valid chain then. It may not really be the
* newest block in the chain, but it is the newest we have
* found so far. We might update it in later iterations of
* this loop if we find something newer.
*/
s->VUtable[first_logical_block] = first_block;
logical_block = BLOCK_NIL;
}
INFTL_dumptables(s);
/*
* Second pass, check for infinite loops in chains. These are
* possible because we don't update the previous pointers when
* we fold chains. No big deal, just fix them up in PUtable.
*/
pr_debug("INFTL: pass 2, validate virtual chains\n");
for (logical_block = 0; logical_block < s->numvunits; logical_block++) {
block = s->VUtable[logical_block];
last_block = BLOCK_NIL;
/* Check for free/reserved/nil */
if (block >= BLOCK_RESERVED)
continue;
ANAC = ANACtable[block];
for (i = 0; i < s->numvunits; i++) {
if (s->PUtable[block] == BLOCK_NIL)
break;
if (s->PUtable[block] > s->lastEUN) {
printk(KERN_WARNING "INFTL: invalid prev %d, "
"in virtual chain %d\n",
s->PUtable[block], logical_block);
s->PUtable[block] = BLOCK_NIL;
}
if (ANACtable[block] != ANAC) {
/*
* Chain must point back to itself. This is ok,
* but we will need adjust the tables with this
* newest block and oldest block.
*/
s->VUtable[logical_block] = block;
s->PUtable[last_block] = BLOCK_NIL;
break;
}
ANAC--;
last_block = block;
block = s->PUtable[block];
}
if (i >= s->nb_blocks) {
/*
* Uhoo, infinite chain with valid ANACS!
* Format whole chain...
*/
format_chain(s, first_block);
}
}
INFTL_dumptables(s);
INFTL_dumpVUchains(s);
/*
* Third pass, format unreferenced blocks and init free block count.
*/
s->numfreeEUNs = 0;
s->LastFreeEUN = BLOCK_NIL;
pr_debug("INFTL: pass 3, format unused blocks\n");
for (block = s->firstEUN; block <= s->lastEUN; block++) {
if (s->PUtable[block] == BLOCK_NOTEXPLORED) {
printk("INFTL: unreferenced block %d, formatting it\n",
block);
if (INFTL_formatblock(s, block) < 0)
s->PUtable[block] = BLOCK_RESERVED;
else
s->PUtable[block] = BLOCK_FREE;
}
if (s->PUtable[block] == BLOCK_FREE) {
s->numfreeEUNs++;
if (s->LastFreeEUN == BLOCK_NIL)
s->LastFreeEUN = block;
}
}
kfree(ANACtable);
return 0;
}