brintos

brintos / linux-shallow public Read only

0
0
Text · 21.5 KiB · 6276daa Raw
777 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * inftlmount.c -- INFTL mount code with extensive checks.4 *5 * Author: Greg Ungerer (gerg@snapgear.com)6 * Copyright © 2002-2003, Greg Ungerer (gerg@snapgear.com)7 *8 * Based heavily on the nftlmount.c code which is:9 * Author: Fabrice Bellard (fabrice.bellard@netgem.com)10 * Copyright © 2000 Netgem S.A.11 */12 13#include <linux/kernel.h>14#include <linux/module.h>15#include <asm/errno.h>16#include <asm/io.h>17#include <linux/uaccess.h>18#include <linux/delay.h>19#include <linux/slab.h>20#include <linux/mtd/mtd.h>21#include <linux/mtd/nftl.h>22#include <linux/mtd/inftl.h>23 24/*25 * find_boot_record: Find the INFTL Media Header and its Spare copy which26 *	contains the various device information of the INFTL partition and27 *	Bad Unit Table. Update the PUtable[] table according to the Bad28 *	Unit Table. PUtable[] is used for management of Erase Unit in29 *	other routines in inftlcore.c and inftlmount.c.30 */31static int find_boot_record(struct INFTLrecord *inftl)32{33	struct inftl_unittail h1;34	//struct inftl_oob oob;35	unsigned int i, block;36	u8 buf[SECTORSIZE];37	struct INFTLMediaHeader *mh = &inftl->MediaHdr;38	struct mtd_info *mtd = inftl->mbd.mtd;39	struct INFTLPartition *ip;40	size_t retlen;41 42	pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl);43 44        /*45	 * Assume logical EraseSize == physical erasesize for starting the46	 * scan. We'll sort it out later if we find a MediaHeader which says47	 * otherwise.48	 */49	inftl->EraseSize = inftl->mbd.mtd->erasesize;50        inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;51 52	inftl->MediaUnit = BLOCK_NIL;53 54	/* Search for a valid boot record */55	for (block = 0; block < inftl->nb_blocks; block++) {56		int ret;57 58		/*59		 * Check for BNAND header first. Then whinge if it's found60		 * but later checks fail.61		 */62		ret = mtd_read(mtd, block * inftl->EraseSize, SECTORSIZE,63			       &retlen, buf);64		/* We ignore ret in case the ECC of the MediaHeader is invalid65		   (which is apparently acceptable) */66		if (retlen != SECTORSIZE) {67			static int warncount = 5;68 69			if (warncount) {70				printk(KERN_WARNING "INFTL: block read at 0x%x "71					"of mtd%d failed: %d\n",72					block * inftl->EraseSize,73					inftl->mbd.mtd->index, ret);74				if (!--warncount)75					printk(KERN_WARNING "INFTL: further "76						"failures for this block will "77						"not be printed\n");78			}79			continue;80		}81 82		if (retlen < 6 || memcmp(buf, "BNAND", 6)) {83			/* BNAND\0 not found. Continue */84			continue;85		}86 87		/* To be safer with BIOS, also use erase mark as discriminant */88		ret = inftl_read_oob(mtd,89				     block * inftl->EraseSize + SECTORSIZE + 8,90				     8, &retlen,(char *)&h1);91		if (ret < 0) {92			printk(KERN_WARNING "INFTL: ANAND header found at "93				"0x%x in mtd%d, but OOB data read failed "94				"(err %d)\n", block * inftl->EraseSize,95				inftl->mbd.mtd->index, ret);96			continue;97		}98 99 100		/*101		 * This is the first we've seen.102		 * Copy the media header structure into place.103		 */104		memcpy(mh, buf, sizeof(struct INFTLMediaHeader));105 106		/* Read the spare media header at offset 4096 */107		mtd_read(mtd, block * inftl->EraseSize + 4096, SECTORSIZE,108			 &retlen, buf);109		if (retlen != SECTORSIZE) {110			printk(KERN_WARNING "INFTL: Unable to read spare "111			       "Media Header\n");112			return -1;113		}114		/* Check if this one is the same as the first one we found. */115		if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {116			printk(KERN_WARNING "INFTL: Primary and spare Media "117			       "Headers disagree.\n");118			return -1;119		}120 121		mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);122		mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);123		mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);124		mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);125		mh->FormatFlags = le32_to_cpu(mh->FormatFlags);126		mh->PercentUsed = le32_to_cpu(mh->PercentUsed);127 128		pr_debug("INFTL: Media Header ->\n"129			 "    bootRecordID          = %s\n"130			 "    NoOfBootImageBlocks   = %d\n"131			 "    NoOfBinaryPartitions  = %d\n"132			 "    NoOfBDTLPartitions    = %d\n"133			 "    BlockMultiplierBits   = %d\n"134			 "    FormatFlgs            = %d\n"135			 "    OsakVersion           = 0x%x\n"136			 "    PercentUsed           = %d\n",137			 mh->bootRecordID, mh->NoOfBootImageBlocks,138			 mh->NoOfBinaryPartitions,139			 mh->NoOfBDTLPartitions,140			 mh->BlockMultiplierBits, mh->FormatFlags,141			 mh->OsakVersion, mh->PercentUsed);142 143		if (mh->NoOfBDTLPartitions == 0) {144			printk(KERN_WARNING "INFTL: Media Header sanity check "145				"failed: NoOfBDTLPartitions (%d) == 0, "146				"must be at least 1\n", mh->NoOfBDTLPartitions);147			return -1;148		}149 150		if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {151			printk(KERN_WARNING "INFTL: Media Header sanity check "152				"failed: Total Partitions (%d) > 4, "153				"BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +154				mh->NoOfBinaryPartitions,155				mh->NoOfBDTLPartitions,156				mh->NoOfBinaryPartitions);157			return -1;158		}159 160		if (mh->BlockMultiplierBits > 1) {161			printk(KERN_WARNING "INFTL: sorry, we don't support "162				"UnitSizeFactor 0x%02x\n",163				mh->BlockMultiplierBits);164			return -1;165		} else if (mh->BlockMultiplierBits == 1) {166			printk(KERN_WARNING "INFTL: support for INFTL with "167				"UnitSizeFactor 0x%02x is experimental\n",168				mh->BlockMultiplierBits);169			inftl->EraseSize = inftl->mbd.mtd->erasesize <<170				mh->BlockMultiplierBits;171			inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;172			block >>= mh->BlockMultiplierBits;173		}174 175		/* Scan the partitions */176		for (i = 0; (i < 4); i++) {177			ip = &mh->Partitions[i];178			ip->virtualUnits = le32_to_cpu(ip->virtualUnits);179			ip->firstUnit = le32_to_cpu(ip->firstUnit);180			ip->lastUnit = le32_to_cpu(ip->lastUnit);181			ip->flags = le32_to_cpu(ip->flags);182			ip->spareUnits = le32_to_cpu(ip->spareUnits);183			ip->Reserved0 = le32_to_cpu(ip->Reserved0);184 185			pr_debug("    PARTITION[%d] ->\n"186				 "        virtualUnits    = %d\n"187				 "        firstUnit       = %d\n"188				 "        lastUnit        = %d\n"189				 "        flags           = 0x%x\n"190				 "        spareUnits      = %d\n",191				 i, ip->virtualUnits, ip->firstUnit,192				 ip->lastUnit, ip->flags,193				 ip->spareUnits);194 195			if (ip->Reserved0 != ip->firstUnit) {196				struct erase_info *instr = &inftl->instr;197 198				/*199				 * 	Most likely this is using the200				 * 	undocumented qiuck mount feature.201				 * 	We don't support that, we will need202				 * 	to erase the hidden block for full203				 * 	compatibility.204				 */205				instr->addr = ip->Reserved0 * inftl->EraseSize;206				instr->len = inftl->EraseSize;207				mtd_erase(mtd, instr);208			}209			if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {210				printk(KERN_WARNING "INFTL: Media Header "211					"Partition %d sanity check failed\n"212					"    firstUnit %d : lastUnit %d  >  "213					"virtualUnits %d\n", i, ip->lastUnit,214					ip->firstUnit, ip->Reserved0);215				return -1;216			}217			if (ip->Reserved1 != 0) {218				printk(KERN_WARNING "INFTL: Media Header "219					"Partition %d sanity check failed: "220					"Reserved1 %d != 0\n",221					i, ip->Reserved1);222				return -1;223			}224 225			if (ip->flags & INFTL_BDTL)226				break;227		}228 229		if (i >= 4) {230			printk(KERN_WARNING "INFTL: Media Header Partition "231				"sanity check failed:\n       No partition "232				"marked as Disk Partition\n");233			return -1;234		}235 236		inftl->nb_boot_blocks = ip->firstUnit;237		inftl->numvunits = ip->virtualUnits;238		if (inftl->numvunits > (inftl->nb_blocks -239		    inftl->nb_boot_blocks - 2)) {240			printk(KERN_WARNING "INFTL: Media Header sanity check "241				"failed:\n        numvunits (%d) > nb_blocks "242				"(%d) - nb_boot_blocks(%d) - 2\n",243				inftl->numvunits, inftl->nb_blocks,244				inftl->nb_boot_blocks);245			return -1;246		}247 248		inftl->mbd.size  = inftl->numvunits *249			(inftl->EraseSize / SECTORSIZE);250 251		/*252		 * Block count is set to last used EUN (we won't need to keep253		 * any meta-data past that point).254		 */255		inftl->firstEUN = ip->firstUnit;256		inftl->lastEUN = ip->lastUnit;257		inftl->nb_blocks = ip->lastUnit + 1;258 259		/* Memory alloc */260		inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),261					       GFP_KERNEL);262		if (!inftl->PUtable)263			return -ENOMEM;264 265		inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16),266					       GFP_KERNEL);267		if (!inftl->VUtable) {268			kfree(inftl->PUtable);269			return -ENOMEM;270		}271 272		/* Mark the blocks before INFTL MediaHeader as reserved */273		for (i = 0; i < inftl->nb_boot_blocks; i++)274			inftl->PUtable[i] = BLOCK_RESERVED;275		/* Mark all remaining blocks as potentially containing data */276		for (; i < inftl->nb_blocks; i++)277			inftl->PUtable[i] = BLOCK_NOTEXPLORED;278 279		/* Mark this boot record (NFTL MediaHeader) block as reserved */280		inftl->PUtable[block] = BLOCK_RESERVED;281 282		/* Read Bad Erase Unit Table and modify PUtable[] accordingly */283		for (i = 0; i < inftl->nb_blocks; i++) {284			int physblock;285			/* If any of the physical eraseblocks are bad, don't286			   use the unit. */287			for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {288				if (mtd_block_isbad(inftl->mbd.mtd,289						    i * inftl->EraseSize + physblock))290					inftl->PUtable[i] = BLOCK_RESERVED;291			}292		}293 294		inftl->MediaUnit = block;295		return 0;296	}297 298	/* Not found. */299	return -1;300}301 302static int memcmpb(void *a, int c, int n)303{304	int i;305	for (i = 0; i < n; i++) {306		if (c != ((unsigned char *)a)[i])307			return 1;308	}309	return 0;310}311 312/*313 * check_free_sector: check if a free sector is actually FREE,314 *	i.e. All 0xff in data and oob area.315 */316static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,317	int len, int check_oob)318{319	struct mtd_info *mtd = inftl->mbd.mtd;320	size_t retlen;321	int i, ret;322	u8 *buf;323 324	buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);325	if (!buf)326		return -ENOMEM;327 328	ret = -1;329	for (i = 0; i < len; i += SECTORSIZE) {330		if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))331			goto out;332		if (memcmpb(buf, 0xff, SECTORSIZE) != 0)333			goto out;334 335		if (check_oob) {336			if(inftl_read_oob(mtd, address, mtd->oobsize,337					  &retlen, &buf[SECTORSIZE]) < 0)338				goto out;339			if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)340				goto out;341		}342		address += SECTORSIZE;343	}344 345	ret = 0;346 347out:348	kfree(buf);349	return ret;350}351 352/*353 * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase354 *		 Unit and Update INFTL metadata. Each erase operation is355 *		 checked with check_free_sectors.356 *357 * Return: 0 when succeed, -1 on error.358 *359 * ToDo: 1. Is it necessary to check_free_sector after erasing ??360 */361int INFTL_formatblock(struct INFTLrecord *inftl, int block)362{363	size_t retlen;364	struct inftl_unittail uci;365	struct erase_info *instr = &inftl->instr;366	struct mtd_info *mtd = inftl->mbd.mtd;367	int physblock;368 369	pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block);370 371	memset(instr, 0, sizeof(struct erase_info));372 373	/* FIXME: Shouldn't we be setting the 'discarded' flag to zero374	   _first_? */375 376	/* Use async erase interface, test return code */377	instr->addr = block * inftl->EraseSize;378	instr->len = inftl->mbd.mtd->erasesize;379	/* Erase one physical eraseblock at a time, even though the NAND api380	   allows us to group them.  This way we if we have a failure, we can381	   mark only the failed block in the bbt. */382	for (physblock = 0; physblock < inftl->EraseSize;383	     physblock += instr->len, instr->addr += instr->len) {384		int ret;385 386		ret = mtd_erase(inftl->mbd.mtd, instr);387		if (ret) {388			printk(KERN_WARNING "INFTL: error while formatting block %d\n",389				block);390			goto fail;391		}392 393		/*394		 * Check the "freeness" of Erase Unit before updating metadata.395		 * FixMe: is this check really necessary? Since we have check396		 * the return code after the erase operation.397		 */398		if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)399			goto fail;400	}401 402	uci.EraseMark = cpu_to_le16(ERASE_MARK);403	uci.EraseMark1 = cpu_to_le16(ERASE_MARK);404	uci.Reserved[0] = 0;405	uci.Reserved[1] = 0;406	uci.Reserved[2] = 0;407	uci.Reserved[3] = 0;408	instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;409	if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0)410		goto fail;411	return 0;412fail:413	/* could not format, update the bad block table (caller is responsible414	   for setting the PUtable to BLOCK_RESERVED on failure) */415	mtd_block_markbad(inftl->mbd.mtd, instr->addr);416	return -1;417}418 419/*420 * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase421 *	Units in a Virtual Unit Chain, i.e. all the units are disconnected.422 *423 *	Since the chain is invalid then we will have to erase it from its424 *	head (normally for INFTL we go from the oldest). But if it has a425 *	loop then there is no oldest...426 */427static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)428{429	unsigned int block = first_block, block1;430 431	printk(KERN_WARNING "INFTL: formatting chain at block %d\n",432		first_block);433 434	for (;;) {435		block1 = inftl->PUtable[block];436 437		printk(KERN_WARNING "INFTL: formatting block %d\n", block);438		if (INFTL_formatblock(inftl, block) < 0) {439			/*440			 * Cannot format !!!! Mark it as Bad Unit,441			 */442			inftl->PUtable[block] = BLOCK_RESERVED;443		} else {444			inftl->PUtable[block] = BLOCK_FREE;445		}446 447		/* Goto next block on the chain */448		block = block1;449 450		if (block == BLOCK_NIL || block >= inftl->lastEUN)451			break;452	}453}454 455void INFTL_dumptables(struct INFTLrecord *s)456{457	int i;458 459	pr_debug("-------------------------------------------"460		"----------------------------------\n");461 462	pr_debug("VUtable[%d] ->", s->nb_blocks);463	for (i = 0; i < s->nb_blocks; i++) {464		if ((i % 8) == 0)465			pr_debug("\n%04x: ", i);466		pr_debug("%04x ", s->VUtable[i]);467	}468 469	pr_debug("\n-------------------------------------------"470		"----------------------------------\n");471 472	pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);473	for (i = 0; i <= s->lastEUN; i++) {474		if ((i % 8) == 0)475			pr_debug("\n%04x: ", i);476		pr_debug("%04x ", s->PUtable[i]);477	}478 479	pr_debug("\n-------------------------------------------"480		"----------------------------------\n");481 482	pr_debug("INFTL ->\n"483		"  EraseSize       = %d\n"484		"  h/s/c           = %d/%d/%d\n"485		"  numvunits       = %d\n"486		"  firstEUN        = %d\n"487		"  lastEUN         = %d\n"488		"  numfreeEUNs     = %d\n"489		"  LastFreeEUN     = %d\n"490		"  nb_blocks       = %d\n"491		"  nb_boot_blocks  = %d",492		s->EraseSize, s->heads, s->sectors, s->cylinders,493		s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,494		s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks);495 496	pr_debug("\n-------------------------------------------"497		"----------------------------------\n");498}499 500void INFTL_dumpVUchains(struct INFTLrecord *s)501{502	int logical, block, i;503 504	pr_debug("-------------------------------------------"505		"----------------------------------\n");506 507	pr_debug("INFTL Virtual Unit Chains:\n");508	for (logical = 0; logical < s->nb_blocks; logical++) {509		block = s->VUtable[logical];510		if (block >= s->nb_blocks)511			continue;512		pr_debug("  LOGICAL %d --> %d ", logical, block);513		for (i = 0; i < s->nb_blocks; i++) {514			if (s->PUtable[block] == BLOCK_NIL)515				break;516			block = s->PUtable[block];517			pr_debug("%d ", block);518		}519		pr_debug("\n");520	}521 522	pr_debug("-------------------------------------------"523		"----------------------------------\n");524}525 526int INFTL_mount(struct INFTLrecord *s)527{528	struct mtd_info *mtd = s->mbd.mtd;529	unsigned int block, first_block, prev_block, last_block;530	unsigned int first_logical_block, logical_block, erase_mark;531	int chain_length, do_format_chain;532	struct inftl_unithead1 h0;533	struct inftl_unittail h1;534	size_t retlen;535	int i;536	u8 *ANACtable, ANAC;537 538	pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s);539 540	/* Search for INFTL MediaHeader and Spare INFTL Media Header */541	if (find_boot_record(s) < 0) {542		printk(KERN_WARNING "INFTL: could not find valid boot record?\n");543		return -ENXIO;544	}545 546	/* Init the logical to physical table */547	for (i = 0; i < s->nb_blocks; i++)548		s->VUtable[i] = BLOCK_NIL;549 550	logical_block = block = BLOCK_NIL;551 552	/* Temporary buffer to store ANAC numbers. */553	ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);554	if (!ANACtable)555		return -ENOMEM;556 557	/*558	 * First pass is to explore each physical unit, and construct the559	 * virtual chains that exist (newest physical unit goes into VUtable).560	 * Any block that is in any way invalid will be left in the561	 * NOTEXPLORED state. Then at the end we will try to format it and562	 * mark it as free.563	 */564	pr_debug("INFTL: pass 1, explore each unit\n");565	for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {566		if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)567			continue;568 569		do_format_chain = 0;570		first_logical_block = BLOCK_NIL;571		last_block = BLOCK_NIL;572		block = first_block;573 574		for (chain_length = 0; ; chain_length++) {575 576			if ((chain_length == 0) &&577			    (s->PUtable[block] != BLOCK_NOTEXPLORED)) {578				/* Nothing to do here, onto next block */579				break;580			}581 582			if (inftl_read_oob(mtd, block * s->EraseSize + 8,583					   8, &retlen, (char *)&h0) < 0 ||584			    inftl_read_oob(mtd, block * s->EraseSize +585					   2 * SECTORSIZE + 8, 8, &retlen,586					   (char *)&h1) < 0) {587				/* Should never happen? */588				do_format_chain++;589				break;590			}591 592			logical_block = le16_to_cpu(h0.virtualUnitNo);593			prev_block = le16_to_cpu(h0.prevUnitNo);594			erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));595			ANACtable[block] = h0.ANAC;596 597			/* Previous block is relative to start of Partition */598			if (prev_block < s->nb_blocks)599				prev_block += s->firstEUN;600 601			/* Already explored partial chain? */602			if (s->PUtable[block] != BLOCK_NOTEXPLORED) {603				/* Check if chain for this logical */604				if (logical_block == first_logical_block) {605					if (last_block != BLOCK_NIL)606						s->PUtable[last_block] = block;607				}608				break;609			}610 611			/* Check for invalid block */612			if (erase_mark != ERASE_MARK) {613				printk(KERN_WARNING "INFTL: corrupt block %d "614					"in chain %d, chain length %d, erase "615					"mark 0x%x?\n", block, first_block,616					chain_length, erase_mark);617				/*618				 * Assume end of chain, probably incomplete619				 * fold/erase...620				 */621				if (chain_length == 0)622					do_format_chain++;623				break;624			}625 626			/* Check for it being free already then... */627			if ((logical_block == BLOCK_FREE) ||628			    (logical_block == BLOCK_NIL)) {629				s->PUtable[block] = BLOCK_FREE;630				break;631			}632 633			/* Sanity checks on block numbers */634			if ((logical_block >= s->nb_blocks) ||635			    ((prev_block >= s->nb_blocks) &&636			     (prev_block != BLOCK_NIL))) {637				if (chain_length > 0) {638					printk(KERN_WARNING "INFTL: corrupt "639						"block %d in chain %d?\n",640						block, first_block);641					do_format_chain++;642				}643				break;644			}645 646			if (first_logical_block == BLOCK_NIL) {647				first_logical_block = logical_block;648			} else {649				if (first_logical_block != logical_block) {650					/* Normal for folded chain... */651					break;652				}653			}654 655			/*656			 * Current block is valid, so if we followed a virtual657			 * chain to get here then we can set the previous658			 * block pointer in our PUtable now. Then move onto659			 * the previous block in the chain.660			 */661			s->PUtable[block] = BLOCK_NIL;662			if (last_block != BLOCK_NIL)663				s->PUtable[last_block] = block;664			last_block = block;665			block = prev_block;666 667			/* Check for end of chain */668			if (block == BLOCK_NIL)669				break;670 671			/* Validate next block before following it... */672			if (block > s->lastEUN) {673				printk(KERN_WARNING "INFTL: invalid previous "674					"block %d in chain %d?\n", block,675					first_block);676				do_format_chain++;677				break;678			}679		}680 681		if (do_format_chain) {682			format_chain(s, first_block);683			continue;684		}685 686		/*687		 * Looks like a valid chain then. It may not really be the688		 * newest block in the chain, but it is the newest we have689		 * found so far. We might update it in later iterations of690		 * this loop if we find something newer.691		 */692		s->VUtable[first_logical_block] = first_block;693		logical_block = BLOCK_NIL;694	}695 696	INFTL_dumptables(s);697 698	/*699	 * Second pass, check for infinite loops in chains. These are700	 * possible because we don't update the previous pointers when701	 * we fold chains. No big deal, just fix them up in PUtable.702	 */703	pr_debug("INFTL: pass 2, validate virtual chains\n");704	for (logical_block = 0; logical_block < s->numvunits; logical_block++) {705		block = s->VUtable[logical_block];706		last_block = BLOCK_NIL;707 708		/* Check for free/reserved/nil */709		if (block >= BLOCK_RESERVED)710			continue;711 712		ANAC = ANACtable[block];713		for (i = 0; i < s->numvunits; i++) {714			if (s->PUtable[block] == BLOCK_NIL)715				break;716			if (s->PUtable[block] > s->lastEUN) {717				printk(KERN_WARNING "INFTL: invalid prev %d, "718					"in virtual chain %d\n",719					s->PUtable[block], logical_block);720				s->PUtable[block] = BLOCK_NIL;721 722			}723			if (ANACtable[block] != ANAC) {724				/*725				 * Chain must point back to itself. This is ok,726				 * but we will need adjust the tables with this727				 * newest block and oldest block.728				 */729				s->VUtable[logical_block] = block;730				s->PUtable[last_block] = BLOCK_NIL;731				break;732			}733 734			ANAC--;735			last_block = block;736			block = s->PUtable[block];737		}738 739		if (i >= s->nb_blocks) {740			/*741			 * Uhoo, infinite chain with valid ANACS!742			 * Format whole chain...743			 */744			format_chain(s, first_block);745		}746	}747 748	INFTL_dumptables(s);749	INFTL_dumpVUchains(s);750 751	/*752	 * Third pass, format unreferenced blocks and init free block count.753	 */754	s->numfreeEUNs = 0;755	s->LastFreeEUN = BLOCK_NIL;756 757	pr_debug("INFTL: pass 3, format unused blocks\n");758	for (block = s->firstEUN; block <= s->lastEUN; block++) {759		if (s->PUtable[block] == BLOCK_NOTEXPLORED) {760			printk("INFTL: unreferenced block %d, formatting it\n",761				block);762			if (INFTL_formatblock(s, block) < 0)763				s->PUtable[block] = BLOCK_RESERVED;764			else765				s->PUtable[block] = BLOCK_FREE;766		}767		if (s->PUtable[block] == BLOCK_FREE) {768			s->numfreeEUNs++;769			if (s->LastFreeEUN == BLOCK_NIL)770				s->LastFreeEUN = block;771		}772	}773 774	kfree(ANACtable);775	return 0;776}777