天天看點

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; 

    unsigned *map_table;       

    unsigned nBlock;           

};

修改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;

}

}