diff options
author | Andrew Victor <andrew@sanpeople.com> | 2005-02-09 09:17:45 +0000 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 12:28:03 +0200 |
commit | 8f15fd55f9bf266139b10850947e19c4e3f4e9b7 (patch) | |
tree | 3df936efbffbbd6c20dd75f51780ac37458285ff /fs/jffs2 | |
parent | 3be36675d41a30ed3b192f92684f1417aa0f8bfe (diff) |
[JFFS2] Add support for JFFS2-on-Dataflash devices.
For Dataflash, can_mark_obsolete = false and the NAND write buffering
code (wbuf.c) is used.
Since the DataFlash chip will automatically erase pages when writing,
the cleanmarkers are not needed - so cleanmarker_oob = false and
cleanmarker_size = 0
DataFlash page-sizes are not a power of two (they're multiples of 528
bytes). The SECTOR_ADDR macro (added in the previous core patch) is
replaced with a (slower) div/mod version if CONFIG_JFFS2_FS_DATAFLASH is
selected.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/Makefile | 3 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 13 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 21 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 18 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 11 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 35 |
6 files changed, 87 insertions, 14 deletions
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index e3c38ccf9c7..6c2ebe176b4 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $ +# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -13,6 +13,7 @@ jffs2-y += super.o jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ae858f87887..a3c6cc15049 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $ + * $Id: erase.c,v 1.71 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -310,7 +310,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb int ret; uint32_t bad_offset; - if (!jffs2_cleanmarker_oob(c)) { + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) { marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); @@ -351,7 +351,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb bad_offset += i; printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); bad: - if (!jffs2_cleanmarker_oob(c)) + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) jffs2_free_raw_node_ref(marker_ref); kfree(ebuf); bad2: @@ -387,6 +387,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jeb->used_size = 0; jeb->dirty_size = 0; jeb->wasted_size = 0; + } else if (c->cleanmarker_size == 0) { + jeb->first_node = jeb->last_node = NULL; + + jeb->free_size = c->sector_size; + jeb->used_size = 0; + jeb->dirty_size = 0; + jeb->wasted_size = 0; } else { struct kvec vecs[1]; struct jffs2_unknown_node marker = { diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 30ab233fe42..5b7c960a047 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ + * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -456,6 +456,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) return -EINVAL; } #endif +#ifndef CONFIG_JFFS2_FS_DATAFLASH + if (c->mtd->type == MTD_DATAFLASH) { + printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); + return -EINVAL; + } +#endif c->flash_size = c->mtd->size; @@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { if (ret) return ret; } + + /* and Dataflash */ + if (jffs2_dataflash(c)) { + ret = jffs2_dataflash_setup(c); + if (ret) + return ret; + } + return ret; } @@ -674,4 +688,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { if (jffs2_nor_ecc(c)) { jffs2_nor_ecc_flash_cleanup(c); } + + /* and DataFlash */ + if (jffs2_dataflash(c)) { + jffs2_dataflash_cleanup(c); + } } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 0412416d1f2..af27b84007a 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ + * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -97,12 +97,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) +#else #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) +#endif #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) +#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -119,6 +123,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_wbuf_timeout NULL #define jffs2_wbuf_process NULL #define jffs2_nor_ecc(c) (0) +#define jffs2_dataflash(c) (0) #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) @@ -154,6 +159,15 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #endif /* NOR ECC */ +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) +int jffs2_dataflash_setup(struct jffs2_sb_info *c); +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); +#else +#define jffs2_dataflash(c) (0) +#define jffs2_dataflash_setup(c) (0) +#define jffs2_dataflash_cleanup(c) do {} while (0) +#endif /* DATAFLASH */ #endif /* NAND */ /* erase.c */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 76859ff5343..e8c43746c82 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $ + * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $ * */ #include <linux/kernel.h> @@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif @@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, @@ -351,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } #endif D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); - return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ + if (c->cleanmarker_size == 0) + return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */ + else + return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ } if (ofs) { D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 894dea88678..a35e007e5bf 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $ + * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -435,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if we have a switch to next page, we will not have enough remaining space for this. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR @@ -486,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { struct jffs2_eraseblock *jeb; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -604,8 +604,14 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) +#else #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) +#endif + int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { struct kvec outvecs[3]; @@ -1192,6 +1198,29 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) kfree(c->wbuf); } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +int jffs2_dataflash_setup(struct jffs2_sb_info *c) { + c->cleanmarker_size = 0; /* No cleanmarkers needed */ + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = c->sector_size; + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); + + return 0; +} + +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} +#endif + #ifdef CONFIG_JFFS2_FS_NOR_ECC int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ |