NAND for SQUASHFS design

概述

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 mappingpart_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; } }

 

你可能感兴趣的:(list,function,struct,Flash,table,Allocation)