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 */

};

 

修改mtdpart.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;
 		}
 	}

原文地址: http://blog.csdn.net/lwzlemon/article/details/4030463

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值