Allow any filesystem on MTD Nand when Read Only
Subsystems (2)
PATCH 1/1 Allow any filesystem on MTD Nand when Read Only
Hello there.
The following patch allows you to have any filesystem over NAND when mounted read only.
The main drive for this was that I wanted to use CRAMFS over NAND flash since it has a much higher compression ratio than JFFS2.
How it works is pretty simple.
It's pretty reasonable assumption that bad blocks are created only when writting to NAND. So in the read-only case it is possible to skip over the bad blocks and offer a bad-block free block device to the upper layers. This allows us to utilize any filesystem when read-only.
In order to speed the mount operation the bad block detection is performed lazilly.
Using the patch I was able to mount as read-only CRAMFS/JFFS2 partitions which contained simulated bad-blocks.
Awaiting your comments...
Regards
Pantelis
drivers/mtd/chips/amd_flash.c +3 -0
@@ -760,6 +760,9 @@ mtd->lock = amd_flash_lock; mtd->unlock = amd_flash_unlock; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + private =kmalloc (sizeof (*private) + (sizeof (struct flchip ) * temp.numchips),GFP_KERNEL );if (!private) {
drivers/mtd/chips/cfi_cmdset_0001.c +4 -0
@@ -307,6 +307,10 @@ mtd->unlock = cfi_intelext_unlock; mtd->suspend = cfi_intelext_suspend; mtd->resume = cfi_intelext_resume; + + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + mtd->flags =MTD_CAP_NORFLASH ; map->fldrv = &cfi_intelext_chipdrv; mtd->name = map->name;
drivers/mtd/chips/cfi_cmdset_0002.c +4 -0
@@ -367,6 +367,10 @@ mtd->sync = cfi_amdstd_sync; mtd->suspend = cfi_amdstd_suspend; mtd->resume = cfi_amdstd_resume; + + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + mtd->flags =MTD_CAP_NORFLASH ; map->fldrv = &cfi_amdstd_chipdrv; mtd->name = map->name;
drivers/mtd/chips/cfi_cmdset_0020.c +4 -0
@@ -226,6 +226,10 @@ mtd->unlock = cfi_staa_unlock; mtd->suspend = cfi_staa_suspend; mtd->resume = cfi_staa_resume; + + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + mtd->flags =MTD_CAP_NORFLASH ; mtd->flags |=MTD_ECC ;/* FIXME: Not all STMicro flashes have this */ mtd->eccsize =8 ;/* FIXME: Should be 0 for STMicro flashes w/out ECC */
drivers/mtd/chips/map_ram.c +3 -0
@@ -76,6 +76,9 @@while (mtd->size & (mtd->erasesize -1 )) mtd->erasesize >>=1 ; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; +__module_get (THIS_MODULE );return mtd; }
drivers/mtd/chips/map_rom.c +4 -0
@@ -46,6 +46,10 @@ mtd->read = maprom_read; mtd->write = maprom_write; mtd->sync = maprom_nop; + + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + mtd->flags =MTD_CAP_ROM ; mtd->erasesize =131072 ;while (mtd->size & (mtd->erasesize -1 ))
drivers/mtd/chips/sharp.c +4 -0
@@ -139,6 +139,10 @@ mtd->sync = sharp_sync; mtd->suspend = sharp_suspend; mtd->resume = sharp_resume; + + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + mtd->flags =MTD_CAP_NORFLASH ; mtd->name = map->name;
drivers/mtd/devices/doc2000.c +3 -0
@@ -605,6 +605,9 @@ mtd->write_oob = doc_write_oob; mtd->sync =NULL ; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + this->totlen =0 ; this->numchips =0 ;
drivers/mtd/devices/doc2001.c +3 -0
@@ -380,6 +380,9 @@ mtd->write_oob = doc_write_oob; mtd->sync =NULL ; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + this->totlen =0 ; this->numchips =0 ; this->curfloor =-1 ;
drivers/mtd/devices/doc2001plus.c +3 -0
@@ -504,6 +504,9 @@ mtd->write_oob = doc_write_oob; mtd->sync =NULL ; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + this->totlen =0 ; this->numchips =0 ; this->curfloor =-1 ;
drivers/mtd/devices/ms02-nv.c +3 -0
@@ -226,6 +226,9 @@ mtd->read = ms02nv_read; mtd->write = ms02nv_write; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; + ret = -EIO ;if (add_mtd_device (mtd)) { printk(KERN_ERR
drivers/mtd/devices/mtdram.c +3 -0
@@ -145,6 +145,9 @@ mtd->read = ram_read; mtd->write = ram_write; + mtd->block_read = mtd->read; + mtd->block_write = mtd->write; +if (add_mtd_device (mtd)) {return -EIO ; }
drivers/mtd/mtdblock.c +5 -5
@@ -84,7 +84,7 @@* Next, writhe data to flash. */ - ret =MTD_WRITE (mtd, pos, len, &retlen, buf); + ret =MTD_BLOCK_WRITE (mtd, pos, len, &retlen, buf);if (ret)return ret;if (retlen != len)
@@ -134,7 +134,7 @@ mtd->name, pos, len);if (!sect_size) -return MTD_WRITE (mtd, pos, len, &retlen, buf); +return MTD_BLOCK_WRITE (mtd, pos, len, &retlen, buf);while (len >0 ) {unsigned long sect_start = (pos/sect_size)*sect_size;
@@ -166,7 +166,7 @@ mtdblk->cache_offset != sect_start) {/* fill the cache with the current sector */ mtdblk->cache_state =STATE_EMPTY ; - ret =MTD_READ (mtd, sect_start, sect_size, &retlen, mtdblk->cache_data); + ret =MTD_BLOCK_READ (mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);if (ret)return ret;if (retlen != sect_size)
@@ -203,7 +203,7 @@ mtd->name, pos, len);if (!sect_size) -return MTD_READ (mtd, pos, len, &retlen, buf); +return MTD_BLOCK_READ (mtd, pos, len, &retlen, buf);while (len >0 ) {unsigned long sect_start = (pos/sect_size)*sect_size;
@@ -222,7 +222,7 @@ mtdblk->cache_offset == sect_start) { memcpy (buf, mtdblk->cache_data + offset, size); } else { - ret =MTD_READ (mtd, pos, size, &retlen, buf); + ret =MTD_BLOCK_READ (mtd, pos, size, &retlen, buf);if (ret)return ret;if (retlen != size)
drivers/mtd/mtdcore.c +60 -0
72 lines not on this page · raw message
drivers/mtd/mtdpart.c +56 -0
68 lines not on this page · raw message
drivers/mtd/nand/nand.c +62 -5
121 lines not on this page · raw message
include/linux/mtd/mtd.h +13 -0
@@ -166,6 +166,10 @@u_int32_t ecctype;u_int32_t eccsize; +/* block map for RO */ +int *block_map; +int block_top; +int block_scantop;// Kernel-only stuff starts here. char *name;
@@ -240,6 +244,10 @@int (*block_isbad) (struct mtd_info *mtd,loff_t ofs);int (*block_markbad) (struct mtd_info *mtd,loff_t ofs); +/* block read */ +int (*block_read) (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf); +int (*block_write) (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf); +void *priv;struct module *owner;
@@ -273,6 +281,8 @@int default_mtd_readv (struct mtd_info *mtd,struct iovec *vecs,unsigned long count,loff_t from,size_t *retlen); +loff_t map_over_bad_blocks (struct mtd_info *mtd,loff_t from); + #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)#define MTD_POINT (mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d))#define MTD_UNPOINT (mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
@@ -286,6 +296,9 @@ #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)#define MTD_SYNC (mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) +#define MTD_BLOCK_READ(mtd, args...) (*(mtd->block_read))(mtd, args) +#define MTD_BLOCK_WRITE(mtd, args...) (*(mtd->block_write))(mtd, args) +/* * Debugging macro and defines */
include/linux/mtd/nand.h +1 -0
@@ -235,6 +235,7 @@wait_queue_head_t wq;nand_state_t state;int page_shift; +int erase_shift;u_char *data_buf;u_char *oob_buf;int oobdirty;
drivers/mtd/chips/amd_flash.c | 3 + drivers/mtd/chips/cfi_cmdset_0001.c | 4 ++ drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++ drivers/mtd/chips/cfi_cmdset_0020.c | 4 ++ drivers/mtd/chips/map_ram.c | 3 + drivers/mtd/chips/map_rom.c | 4 ++ drivers/mtd/chips/sharp.c | 4 ++ drivers/mtd/devices/doc2000.c | 3 + drivers/mtd/devices/doc2001.c | 3 + drivers/mtd/devices/doc2001plus.c | 3 + drivers/mtd/devices/ms02-nv.c | 3 + drivers/mtd/devices/mtdram.c | 3 + drivers/mtd/mtdblock.c | 10 ++--- drivers/mtd/mtdcore.c | 60 ++++++++++++++++++++++++++++++++ drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++ drivers/mtd/nand/nand.c | 67 +++++++++++++++++++++++++++++++++--- include/linux/mtd/mtd.h | 13 ++++++ include/linux/mtd/nand.h | 1 18 files changed, 238 insertions(+), 10 deletions(-)
Quoted 4 lines · Pantelis Antoniou
Hello there.
The following patch allows you to have any filesystem over NAND when mounted read only.
Please don't do it like this. Do it as a block device 'translation layer' instead. See nftl/ftl/mtdblock for examples.
Can you join irc.freenode.net #mtd ?
Signature · 1 line
dwmw2
Quoted 4 lines · David Woodhouse
Quoted 2 lines · Pantelis Antoniou
Hello there.
Quoted 10 lines
Quoted 3 lines
The following patch allows you to have any filesystem over NAND when mounted read only.
Please don't do it like this. Do it as a block device 'translation layer' instead. See nftl/ftl/mtdblock for examples.
Can you join irc.freenode.net #mtd ?
Sorry I'm at work now and IRC is blocked.
I'll try to get into it when I get home in about 2 hours.
I'll take a look at nftl/ftl/mtdblock.
The patch is very small and it works perfectly however. What are your main objections?
Regards
Pantelis
Quoted 17 lines · Pantelis Antoniou
Hello there.
The following patch allows you to have any filesystem over NAND when mounted read only.
The main drive for this was that I wanted to use CRAMFS over NAND flash since it has a much higher compression ratio than JFFS2.
How it works is pretty simple.
It's pretty reasonable assumption that bad blocks are created only when writting to NAND. So in the read-only case it is possible to skip over the bad blocks and offer a bad-block free block device to the upper layers. This allows us to utilize any filesystem when read-only.
In order to speed the mount operation the bad block detection is performed lazilly.
Quoted 9 lines
Using the patch I was able to mount as read-only CRAMFS/JFFS2 partitions which contained simulated bad-blocks.
Awaiting your comments...
Regards
Pantelis
After more thought, I am in the process of doing something similar.
However my changes are not quite done yet. Roughly it goes like this:
Write a new read-only block driver that skips bad blocks and uses ECC reads. This allows any read only file system to use it (ie cramfs). The bad block map is kept in the first non-bad page in the partition, when the driver is installed it reads the bad block map.
To write the data into the mtd, you have a special version of nandwrite that checks for bad blocks while writing the image and finally writes the bad block map.
One difference between my approach and yours is that no existing mtd driver code is touched, it is simply another mtd block driver.
David Daney.
Quoted 6 lines · David Daney
Quoted 3 lines · Pantelis Antoniou
The following patch allows you to have any filesystem over NAND when mounted read only.
After more thought, I am in the process of doing something similar.
I have also been doing something similar to this - though I put the bad block handling into Squashfs (another RO compressed filesystem). It therefore seems as if all the possible approaches have been tried: putting the bad block code in the NAND layer; implementing a new RO block-driver; and putting the bad block code in the RO filesystem! It definately seems as if there is a requirement for this in the main source.
Pantelis have you looked at Squashfs? This filesystem gives much better compression than CRAMFS.
Phillip
Quoted 8 lines · Phillip Lougher
Quoted 6 lines · David Daney
Quoted 3 lines · Pantelis Antoniou
The following patch allows you to have any filesystem over NAND when mounted read only.
Quoted 6 lines
Quoted 2 lines
After more thought, I am in the process of doing something similar.
I have also been doing something similar to this - though I put the bad block handling into Squashfs (another RO compressed filesystem). It therefore seems as if all the possible approaches have been tried: putting the bad block code in the NAND layer; implementing a new RO block-driver; and putting the bad block code in the RO filesystem! It definately seems as if there is a requirement for this in the main source.
Pantelis have you looked at Squashfs? This filesystem gives much better compression than CRAMFS.
It seems that if people want to use more than one type of RO filesystem, that putting the badblock handling in the block driver instead of every filesystem makes more sense.
David Daney.
Quoted 8 lines · Phillip Lougher
Quoted 6 lines · David Daney
Quoted 3 lines · Pantelis Antoniou
The following patch allows you to have any filesystem over NAND when mounted read only.
Quoted 7 lines
Quoted 2 lines
After more thought, I am in the process of doing something similar.
I have also been doing something similar to this - though I put the bad block handling into Squashfs (another RO compressed filesystem). It therefore seems as if all the possible approaches have been tried: putting the bad block code in the NAND layer; implementing a new RO block-driver; and putting the bad block code in the RO filesystem! It definately seems as if there is a requirement for this in the main source.
Pantelis have you looked at Squashfs? This filesystem gives much better compression than CRAMFS.
I've taken a look at squashfs. It does seems nicer than CRAMFS.
My main problem is not that it's not in the kernel proper, but it's not in by bootloader too. If you took a look at u-boot and implemented squashfs support I would probably switch.
Quoted 5 lines
Phillip
Regards
Pantelis