Any RO filesystem on NAND
PATCH 1/1 Any RO filesystem on NAND
Hello.
The following patch implements any RO filesystem on MTD devices like NANDs with bad blocks.
It is a modification for the mtd-block device when the partition/device is read only.
Regards
Pantelis
drivers/mtd/mtdblock.c +81 -5
@@ -26,6 +26,11 @@unsigned long cache_offset;unsigned int cache_size;enum {STATE_EMPTY ,STATE_CLEAN ,STATE_DIRTY } cache_state; + +/* block map for RO */ +int *block_map; +int block_top; +int block_scantop; } *mtdblks[MAX_MTD_DEVICES ];/*
@@ -190,6 +195,71 @@return 0 ; } +static unsigned long map_block (struct mtdblk_dev *mtdblk,unsigned long pos) +{ +struct mtd_info *mtd = mtdblk->mtd; +int i, block; + +/* only for read-only devices with OOB info and bad block checking */ +if ((mtd->flags &MTD_WRITEABLE ) ==MTD_WRITEABLE || + (mtd->flags &MTD_OOB ) ==0 || mtd->block_isbad ==NULL || + mtd->erasesize ==0 ) +return pos; + +/* first time in */ +if (mtdblk->block_map ==NULL ) { + mtdblk->block_top = mtd->size / mtd->erasesize; + mtdblk->block_map =kmalloc (sizeof (*mtdblk->block_map) * mtdblk->block_top,GFP_KERNEL ); +if (mtdblk->block_map ==NULL ) { +printk (KERN_WARNING "mtd: block_map(): unable to allocate block map\n" ); +return (unsigned long )-1 ; + } +for (i =0 ; i < mtdblk->block_top; i++) + mtdblk->block_map[i] =-1 ; + +for (i =0 ; i < mtdblk->block_top; i++) +if ((*mtd->block_isbad)(mtd, i * mtd->erasesize) ==0 ) +break ; + +if (i >= mtdblk->block_top) { +printk (KERN_WARNING "mtd: block_map(): all blocks bad?!\n" ); +return (unsigned long )-1 ; + } + mtdblk->block_scantop =0 ; + mtdblk->block_map[0 ] = i; + +DEBUG (0 ,"mtdblk: map %d -> %d\n" , mtdblk->block_scantop, mtdblk->block_map[mtdblk->block_scantop]); + } + + block = (int )(pos / mtd->erasesize); +if ((unsigned int )block >= (unsigned int )mtdblk->block_top) { +printk (KERN_WARNING "mtd: block_map(): requested block too large!\n" ); +return (unsigned long )-1 ; + } + +/* scan for bad block up to where we want */ +while (block >= mtdblk->block_scantop) { +/* find a non bad block */ +for (i = mtdblk->block_map[mtdblk->block_scantop] +1 ; i < mtdblk->block_top; i++) +if ((*mtd->block_isbad)(mtd, i * mtd->erasesize) ==0 ) +break ; + +/* exchausted ? */ +if (i >= mtdblk->block_top) { +printk (KERN_WARNING "mtd: block_map(): no more good blocks\n" ); +return (unsigned long )-1 ; + } + + mtdblk->block_map[++mtdblk->block_scantop] = i; +DEBUG (0 ,"mtdblk: map %d -> %d\n" , mtdblk->block_scantop, mtdblk->block_map[mtdblk->block_scantop]); + } + +/* get the mapped block */ + block = mtdblk->block_map[block]; + +/* form actual position */ +return ((unsigned long )block * mtd->erasesize) | (pos & (mtd->erasesize -1 )); +}static int do_cached_read (struct mtdblk_dev *mtdblk,unsigned long pos,int len,char *buf)
@@ -222,11 +292,17 @@ mtdblk->cache_offset == sect_start) { memcpy (buf, mtdblk->cache_data + offset, size); } else { - ret =MTD_READ (mtd, pos, size, &retlen, buf); -if (ret) -return ret; -if (retlen != size) -return -EIO ; + pos =map_block (mtdblk, pos); +if (pos == (unsigned long )-1 ) { +memset (buf,0xff , size); + retlen = size; + }else { + ret =MTD_READ (mtd, pos, size, &retlen, buf); +if (ret) +return ret; +if (retlen != size) +return -EIO ; + } } buf += size;
mtdblock.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 81 insertions(+), 5 deletions(-)