squashfs和cramfs作为根文件系统时让MTD支持跳过坏块
概述Squashfs一般存放于nor flash中,但是也可以使用Nand flash存储squashfs文件系统,但是需要绕过坏块。 算法描述在bootloader中烧写squashfs分区时,顺序的将squashfs烧到Nand flash中,如果碰上坏块,则顺序写入下一个好块。例如:#2是坏块,则数据写到#1, #3, #4,…上面。引导linux后,在mtd相应的s
概述
Squashfs一般存放于nor flash中,但是也可以使用Nand flash存储squashfs文件系统,但是需要绕过坏块。
算法描述
在bootloader中烧写squashfs分区时,顺序的将squashfs烧到Nand flash中,如果碰上坏块,则顺序写入下一个好块。例如:#2是坏块,则数据写到#1, #3, #4,…上面。
引导linux后,在mtd相应的squashfs分区上面建立一个逻辑块与物理块的映射表。逻辑块表示squashfs要访问的块地址,而物理块表示实际存储的物理块地址。
同上例,#2是坏块,则逻辑块与物理块的映射关系建立如下:
logic[0] = phys[0],
logic[1]=phys[1],
logic[2]=phys[3],
logic[3]=phys[4],
建立映射关系后,就知道squash访问的地址对应的物理地址了。
程序实现:
声明结构:
struct part_map{
struct mtd_info *part_mtd; /* Mapping partition mtd */
unsigned *map_table; /* Mapping from logic block to phys block */
unsigned nBlock; /* Logic block number */
};
修改nandpart.c即可实现。
1. 声明一个partition mapping表。
2. 在add_mtd_partitions()函数中,当mtd分驱创建成功后,创建partition mapping表。
3. 在part_read ()函数中时,如果匹配到partition mapping的part_mtd,则先通过map_table获取到物理地址后,再调用part->master->read_ecc读取nand flash中的数据。
4. 在del_mtd_partitions()函数中,匹配到partition mapping分区,则删除之.
原码补丁如下:
- --- linux-2.6.10/drivers/mtd/mtdpart.c 2005-01-13 05:59:48.000000000 +0800
- +++ linux-2.6.10-mips-dev/drivers/mtd/mtdpart.c 2009-03-12 18:50:44.000000000 +0800
- @@ -22,6 +22,22 @@
- #include <linux/mtd/partitions.h>
- #include <linux/mtd/compatmac.h>
- +/* Walson: definicate two mapping table for squashfs
- + * partition, because squashfs do not know bad block.
- + * So the we have do the valid mapping between logic block
- + * and phys block
- + */
- +#include <linux/mtd/nand.h>
- +#define MAX_PARTITION_MAPPING 2
- +struct part_map{
- + struct mtd_info *part_mtd; /* Mapping partition mtd */
- + unsigned *map_table; /* Mapping from logic block to phys block */
- + unsigned nBlock; /* Logic block number */
- +};
- +
- +static struct part_map *part_mapping[MAX_PARTITION_MAPPING];
- +static int part_mapping_count = -1;
- +
- /* Our partition linked list */
- static LIST_HEAD(mtd_partitions);
- @@ -51,6 +67,35 @@
- size_t *retlen, u_char *buf)
- {
- struct mtd_part *part = PART(mtd);
- +
- + /* Walson: calucate physical address */
- + struct nand_chip *this = part->master->priv;
- + unsigned logic_b, phys_b;
- + unsigned i;
- +
- + if ( part_mapping_count > 0 )
- + {
- + for ( i=0; i<MAX_PARTITION_MAPPING; i++ )
- + {
- + if ( part_mapping[i] && part_mapping[i]->part_mtd==mtd )
- + {
- + /* remap from logic block to physical block */
- + logic_b = from >> this->bbt_erase_shift;
- + if ( logic_b < part_mapping[i]->nBlock )
- + {
- + phys_b = part_mapping[i]->map_table[logic_b];
- + from = phys_b << this->bbt_erase_shift | (from&(mtd->erasesize-1));
- + }
- + else
- + {
- + /* the offset is bigger than good block range, don't read data */
- + *retlen = 0;
- + return -EINVAL;
- + }
- + }
- + }
- + }
- +
- if (from >= mtd->size)
- len = 0;
- else if (from + len > mtd->size)
- @@ -201,6 +246,35 @@
- unsigned long count, loff_t from, size_t *retlen)
- {
- struct mtd_part *part = PART(mtd);
- +
- + /* Walson: calucate physical address */
- + struct nand_chip *this = part->master->priv;
- + unsigned logic_b, phys_b;
- + unsigned i;
- +
- + if ( part_mapping_count > 0 )
- + {
- + for ( i=0; i<MAX_PARTITION_MAPPING; i++ )
- + {
- + if ( part_mapping[i] && part_mapping[i]->part_mtd==mtd )
- + {
- + /* remap from logic block to physical block */
- + logic_b = from >> this->bbt_erase_shift;
- + if ( logic_b < part_mapping[i]->nBlock )
- + {
- + phys_b = part_mapping[i]->map_table[logic_b];
- + from = phys_b << this->bbt_erase_shift | (from&(mtd->erasesize-1));
- + }
- + else
- + {
- + /* the offset is bigger than good block range, don't read data */
- + *retlen = 0;
- + return -EINVAL;
- + }
- + }
- + }
- + }
- +
- if (part->master->readv_ecc == NULL)
- return part->master->readv (part->master, vecs, count,
- from + part->offset, retlen);
- @@ -317,6 +391,107 @@
- return part->master->block_markbad(part->master, ofs);
- }
- +
- +/* Walson:
- + * This function create a partition mapping
- + */
- +static int part_create_partition_mapping ( struct mtd_info *part_mtd )
- +{
- + struct mtd_part *part = PART(part_mtd);
- + struct nand_chip *this = part->master->priv;
- + struct part_map *map_part;
- + int index;
- + unsigned offset;
- + int logical_b, phys_b;
- +
- + if ( !part_mtd || !this )
- + {
- + printk("null mtd or it is no nand chip!");
- + return -1;
- + }
- +
- + if ( part_mapping_count < 0 )
- + {
- + /* Init the part mapping table when this function called first time */
- + memset(part_mapping, 0, sizeof(struct part_map *)*MAX_PARTITION_MAPPING);
- + part_mapping_count = 0;
- + }
- +
- + for ( index=0; index<MAX_PARTITION_MAPPING; index++ )
- + {
- + if ( part_mapping[index] == NULL )
- + break;
- + }
- +
- + if ( index >= MAX_PARTITION_MAPPING )
- + {
- + printk("partition mapping is full!");
- + return -1;
- + }
- +
- + map_part = kmalloc(sizeof(struct part_map), GFP_KERNEL);
- + if ( !map_part )
- + {
- + printk ("memory allocation error while creating partitions mapping for %s/n",
- + part_mtd->name);
- + return -1;
- + }
- +
- + map_part->map_table = kmalloc(sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift),
- + GFP_KERNEL);
- + if ( !map_part->map_table )
- + {
- + printk ("memory allocation error while creating partitions mapping for %s/n",
- + part_mtd->name);
- + kfree(map_part);
- + return -1;
- + }
- + memset(map_part->map_table, 0xFF, sizeof(unsigned)*(part_mtd->size>>this->bbt_erase_shift));
- +
- + /* Create partition mapping table */
- + logical_b = 0;
- + for ( offset=0; offset<part_mtd->size; offset+=part_mtd->erasesize )
- + {
- + if ( part_mtd->block_isbad &&
- + part_mtd->block_isbad(part_mtd, offset) )
- + continue;
- +
- + phys_b = offset >> this->bbt_erase_shift;
- + map_part->map_table[logical_b] = phys_b;
- + printk("part[%s]: logic[%u]=phys[%u]/n",
- + part_mtd->name, logical_b, phys_b);
- + logical_b++;
- + }
- + map_part->nBlock = logical_b;
- + map_part->part_mtd = part_mtd;
- +
- + part_mapping[index] = map_part;
- + part_mapping_count++;
- + return 0;
- +}
- +
- +static void part_del_partition_mapping( struct mtd_info *part_mtd )
- +{
- + int index;
- + struct part_map *map_part;
- +
- + if ( part_mapping_count > 0 )
- + {
- + for ( index=0; index<MAX_PARTITION_MAPPING; index++ )
- + {
- + map_part = part_mapping[index];
- + if ( map_part && map_part->part_mtd==part_mtd )
- + {
- + kfree(map_part->map_table);
- + kfree(map_part);
- + part_mapping[index] = NULL;
- + part_mapping_count--;
- + }
- + }
- + }
- +}
- +
- +
- /*
- * This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
- @@ -333,6 +508,9 @@
- slave = list_entry(node, struct mtd_part, list);
- if (slave->master == master) {
- struct list_head *prev = node->prev;
- +
- + /* walson: Free partition mapping if created */
- + part_del_partition_mapping(&slave->mtd);
- __list_del(prev, node->next);
- if(slave->registered)
- del_mtd_device(&slave->mtd);
- @@ -513,6 +691,19 @@
- {
- /* register our partition */
- add_mtd_device(&slave->mtd);
- +
- + /* Walson: Build partition mapping for squashfs */
- + if ( slave->mtd.name && 0==strcmp(slave->mtd.name, "base") )
- + {
- + part_create_partition_mapping(&slave->mtd);
- + }
- + else if ( slave->mtd.name && 0==strcmp(slave->mtd.name, "prog") )
- + {
- + part_create_partition_mapping(&slave->mtd);
- + }
- + else
- + {
- + }
- slave->registered = 1;
- }
- }
更多推荐
所有评论(0)