⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nftlmount.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * NFTL mount code with extensive checks * * Author: Fabrice Bellard (fabrice.bellard@netgem.com)  * Copyright (C) 2000 Netgem S.A. * * $Id: nftlmount.c,v 1.11 2000/11/17 12:24:09 ollie Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/kernel.h>#include <linux/module.h>#include <asm/errno.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/miscdevice.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/malloc.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nftl.h>#include <linux/mtd/compatmac.h>#define SECTORSIZE 512/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the *	various device information of the NFTL partition and Bad Unit Table. Update *	the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] *	is used for management of Erase Unit in other routines in nftl.c and nftlmount.c */static int find_boot_record(struct NFTLrecord *nftl){	struct nftl_uci1 h1;	struct nftl_oob oob;	unsigned int block, boot_record_count;	int retlen;	u8 buf[SECTORSIZE];	struct NFTLMediaHeader *mh = &nftl->MediaHdr;	nftl->MediaUnit = BLOCK_NIL;	nftl->SpareMediaUnit = BLOCK_NIL;	boot_record_count = 0;	/* search for a valid boot record */	for (block = 0; block < nftl->nb_blocks; block++) {		unsigned int erase_mark;		/* read ANAND header. To be safer with BIOS, also use erase mark as discriminant */		if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,				8, &retlen, (char *)&h1) < 0)			continue;		erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));		if (erase_mark != ERASE_MARK) 			continue;		if (MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,				&retlen, buf, (char *)&oob) < 0)			continue;		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));		if (memcmp(mh->DataOrgID, "ANAND", 6) == 0) {			/* first boot record */			if (boot_record_count == 0) {				unsigned int i;				/* header found : read the bad block table data */				if (mh->UnitSizeFactor != 0xff) {					printk("Sorry, we don't support UnitSizeFactor "					       "of != 1 yet\n");					goto ReplUnitTable;				}				nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);				if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks)					goto ReplUnitTable; /* small consistency check */				nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;				if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2))					goto ReplUnitTable; /* small consistency check */				/* FixMe: with bad blocks, the total size available is not FormattedSize any				   more !!! */				nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);				nftl->MediaUnit = block;				/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */				for (i = 0; i < nftl->nb_blocks; i++) {					if ((i & (SECTORSIZE - 1)) == 0) {						/* read one sector for every SECTORSIZE of blocks */						if (MTD_READECC(nftl->mtd, block * nftl->EraseSize +								i + SECTORSIZE, SECTORSIZE,								&retlen, buf, (char *)&oob) < 0)							goto ReplUnitTable;					}					/* mark the Bad Erase Unit as RESERVED in ReplUnitTable */					if (buf[i & (SECTORSIZE - 1)] != 0xff)						nftl->ReplUnitTable[i] = BLOCK_RESERVED;				}				boot_record_count++;			} else if (boot_record_count == 1) {				nftl->SpareMediaUnit = block;				boot_record_count++;				break;			}		}	ReplUnitTable:	}	if (boot_record_count == 0) {		/* no boot record found */		return -1;	} else {		return 0;	}}static int memcmpb(void *a, int c, int n){	int i;	for (i = 0; i < n; i++) {		if (c != ((unsigned char *)a)[i])			return 1;	}	return 0;}/* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, 			      int check_oob){	int i, retlen;	u8 buf[SECTORSIZE];	for (i = 0; i < len; i += SECTORSIZE) {		/* we want to read the sector without ECC check here since a free		   sector does not have ECC syndrome on it yet */		if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)			return -1;		if (memcmpb(buf, 0xff, SECTORSIZE) != 0)			return -1;		if (check_oob) {			if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,					&retlen, buf) < 0)				return -1;			if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)				return -1;		}		address += SECTORSIZE;	}	return 0;}/* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and *              Update NFTL metadata. Each erase operation is checked with check_free_sectors * * Return: 0 when succeed, -1 on error. * *  ToDo: 1. Is it neceressary to check_free_sector after erasing ??  *        2. UnitSizeFactor != 0xFF */int NFTL_formatblock(struct NFTLrecord *nftl, int block){	int retlen;	unsigned int nb_erases, erase_mark;	struct nftl_uci1 uci;	struct erase_info *instr = &nftl->instr;	/* Read the Unit Control Information #1 for Wear-Leveling */	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,			8, &retlen, (char *)&uci) < 0)		goto default_uci1;	erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));	if (erase_mark != ERASE_MARK) {	default_uci1:		uci.EraseMark = cpu_to_le16(ERASE_MARK);		uci.EraseMark1 = cpu_to_le16(ERASE_MARK);		uci.WearInfo = cpu_to_le32(0);	}	memset(instr, 0, sizeof(struct erase_info));	/* XXX: use async erase interface, XXX: test return code */	instr->addr = block * nftl->EraseSize;	instr->len = nftl->EraseSize;	MTD_ERASE(nftl->mtd, instr);	if (instr->state == MTD_ERASE_FAILED) {		/* could not format, FixMe: We should update the BadUnitTable 		   both in memory and on disk */		printk("Error while formatting block %d\n", block);		return -1;	} else {		/* increase and write Wear-Leveling info */		nb_erases = le32_to_cpu(uci.WearInfo);		nb_erases++;		/* wrap (almost impossible with current flashs) or free block */		if (nb_erases == 0)			nb_erases = 1;		/* check the "freeness" of Erase Unit before updating metadata		 * FixMe:  is this check really necessary ? since we have check the		 *         return code after the erase operation. */		if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)			return -1;		uci.WearInfo = le32_to_cpu(nb_erases);		if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,				 &retlen, (char *)&uci) < 0)			return -1;		return 0;	}}/* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct. *	Mark as 'IGNORE' each incorrect sector. This check is only done if the chain *	was being folded when NFTL was interrupted. * *	The check_free_sectors in this function is neceressary. There is a possible *	situation that after writing the Data area, the Block Control Information is *	not updated according (due to power failure or something) which leaves the block *	in an umconsistent state. So we have to check if a block is really FREE in this *	case. */static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block){	unsigned int block, i, status;	struct nftl_bci bci;	int sectors_per_block, retlen;	sectors_per_block = nftl->EraseSize / SECTORSIZE;	block = first_block;	for (;;) {		for (i = 0; i < sectors_per_block; i++) {			if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,					8, &retlen, (char *)&bci) < 0)				status = SECTOR_IGNORE;			else				status = bci.Status | bci.Status1;			switch(status) {			case SECTOR_FREE:				/* verify that the sector is really free. If not, mark				   as ignore */				if (memcmpb(&bci, 0xff, 8) != 0 ||				    check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, 						       SECTORSIZE, 0) != 0) {					printk("Incorrect free sector %d in block %d: "					       "marking it as ignored\n",					       i, block);					/* sector not free actually : mark it as SECTOR_IGNORE  */					bci.Status = SECTOR_IGNORE;					bci.Status1 = SECTOR_IGNORE;					MTD_WRITEOOB(nftl->mtd,						     block * nftl->EraseSize + i * SECTORSIZE,						     8, &retlen, (char *)&bci);				}				break;			default:				break;			}		}		/* proceed to next Erase Unit on the chain */		block = nftl->ReplUnitTable[block];		if (!(block == BLOCK_NIL || block < nftl->nb_blocks))			printk("incorrect ReplUnitTable[] : %d\n", block);		if (block == BLOCK_NIL || block >= nftl->nb_blocks)			break;	}}/* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block){	unsigned int length = 0, block = first_block;	for (;;) {		length++;		/* avoid infinite loops, although this is guaranted not to		   happen because of the previous checks */		if (length >= nftl->nb_blocks) {			printk("nftl: length too long %d !\n", length);			break;		}		block = nftl->ReplUnitTable[block];		if (!(block == BLOCK_NIL || block < nftl->nb_blocks))			printk("incorrect ReplUnitTable[] : %d\n", block);		if (block == BLOCK_NIL || block >= nftl->nb_blocks)			break;	}	return length;}/* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a *	Virtual Unit Chain, i.e. all the units are disconnected. * *	It is not stricly correct to begin from the first block of the chain because *	if we stop the code, we may see again a valid chain if there was a first_block *	flag in a block inside it. But is it really a problem ? * * FixMe: Figure out what the last statesment means. What if power failure when we are *	in the for (;;) loop formatting blocks ?? */static void format_chain(struct NFTLrecord *nftl, unsigned int first_block){	unsigned int block = first_block, block1;	printk("Formatting chain at block %d\n", first_block);	for (;;) {		block1 = nftl->ReplUnitTable[block];		printk("Formatting block %d\n", block);		if (NFTL_formatblock(nftl, block) < 0) {			/* cannot format !!!! Mark it as Bad Unit,			   FixMe: update the BadUnitTable on disk */			nftl->ReplUnitTable[block] = BLOCK_RESERVED;		} else {			nftl->ReplUnitTable[block] = BLOCK_FREE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -