diff options
author | Andrew Victor <andrew@sanpeople.com> | 2005-02-09 04:09:05 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:27:09 -0400 |
commit | 3be36675d41a30ed3b192f92684f1417aa0f8bfe (patch) | |
tree | da8395bb14ffef19e551c509c47d16b52fb536d9 | |
parent | 045e9a5d51ced27bfcbdb78071534ce6fd36b33d (diff) |
[JFFS2] Core changes required to support JFFS2-on-Dataflash devices.
DataFlash page-sizes are not a power of two (they're multiples of 528
bytes). There are a few places in JFFS2 code where sector_size is used
as a bitmask. A new macro (SECTOR_ADDR) was defined to calculate these
sector addresses. For non-DataFlash devices, the original (faster)
bitmask operation is still used.
In scan.c, the EMPTY_SCAN_SIZE was a constant of 1024.
Since this could be larger than the sector size of the DataFlash, this
is now basically set to MIN(sector_size, 1024).
Addition of a jffs2_is_writebuffered() macro.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | fs/jffs2/erase.c | 4 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 5 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 5 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 20 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 63 |
5 files changed, 53 insertions, 44 deletions
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 41451e8bf361..ae858f878875 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -233,7 +233,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
233 | continue; | 233 | continue; |
234 | } | 234 | } |
235 | 235 | ||
236 | if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) { | 236 | if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { |
237 | /* It's in the block we're erasing */ | 237 | /* It's in the block we're erasing */ |
238 | struct jffs2_raw_node_ref *this; | 238 | struct jffs2_raw_node_ref *this; |
239 | 239 | ||
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 87ec74ff5930..61ae001eced5 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $ | 10 | * $Id: gc.c,v 1.145 2005/02/09 09:09:01 pavlov Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -816,8 +816,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
816 | 816 | ||
817 | /* Doesn't matter if there's one in the same erase block. We're going to | 817 | /* Doesn't matter if there's one in the same erase block. We're going to |
818 | delete it too at the same time. */ | 818 | delete it too at the same time. */ |
819 | if ((raw->flash_offset & ~(c->sector_size-1)) == | 819 | if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) |
820 | (fd->raw->flash_offset & ~(c->sector_size-1))) | ||
821 | continue; | 820 | continue; |
822 | 821 | ||
823 | D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); | 822 | D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 03b0acc37b73..0412416d1f2d 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -97,7 +97,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
97 | #endif | 97 | #endif |
98 | } | 98 | } |
99 | 99 | ||
100 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) | ||
101 | |||
100 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) | 102 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) |
103 | #define jffs2_is_writebuffered(c) (c->wbuf != NULL) | ||
101 | 104 | ||
102 | #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) | 105 | #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) |
103 | #define jffs2_can_mark_obsolete(c) (1) | 106 | #define jffs2_can_mark_obsolete(c) (1) |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index ded53584a897..76859ff53437 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $ | 10 | * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | #include "nodelist.h" | 20 | #include "nodelist.h" |
21 | 21 | ||
22 | #define EMPTY_SCAN_SIZE 1024 | 22 | #define DEFAULT_EMPTY_SCAN_SIZE 1024 |
23 | 23 | ||
24 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ | 24 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ |
25 | c->free_size -= _x; c->dirty_size += _x; \ | 25 | c->free_size -= _x; c->dirty_size += _x; \ |
@@ -75,6 +75,14 @@ static inline int min_free(struct jffs2_sb_info *c) | |||
75 | return min; | 75 | return min; |
76 | 76 | ||
77 | } | 77 | } |
78 | |||
79 | static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { | ||
80 | if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) | ||
81 | return sector_size; | ||
82 | else | ||
83 | return DEFAULT_EMPTY_SCAN_SIZE; | ||
84 | } | ||
85 | |||
78 | int jffs2_scan_medium(struct jffs2_sb_info *c) | 86 | int jffs2_scan_medium(struct jffs2_sb_info *c) |
79 | { | 87 | { |
80 | int i, ret; | 88 | int i, ret; |
@@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
316 | if (!buf_size) { | 324 | if (!buf_size) { |
317 | buf_len = c->sector_size; | 325 | buf_len = c->sector_size; |
318 | } else { | 326 | } else { |
319 | buf_len = EMPTY_SCAN_SIZE; | 327 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); |
320 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); | 328 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); |
321 | if (err) | 329 | if (err) |
322 | return err; | 330 | return err; |
@@ -326,10 +334,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
326 | ofs = 0; | 334 | ofs = 0; |
327 | 335 | ||
328 | /* Scan only 4KiB of 0xFF before declaring it's empty */ | 336 | /* Scan only 4KiB of 0xFF before declaring it's empty */ |
329 | while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) | 337 | while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) |
330 | ofs += 4; | 338 | ofs += 4; |
331 | 339 | ||
332 | if (ofs == EMPTY_SCAN_SIZE) { | 340 | if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { |
333 | #ifdef CONFIG_JFFS2_FS_NAND | 341 | #ifdef CONFIG_JFFS2_FS_NAND |
334 | if (jffs2_cleanmarker_oob(c)) { | 342 | if (jffs2_cleanmarker_oob(c)) { |
335 | /* scan oob, take care of cleanmarker */ | 343 | /* scan oob, take care of cleanmarker */ |
@@ -423,7 +431,7 @@ scan_more: | |||
423 | bail now */ | 431 | bail now */ |
424 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && | 432 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && |
425 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { | 433 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { |
426 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE)); | 434 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); |
427 | return BLK_STATE_CLEANMARKER; | 435 | return BLK_STATE_CLEANMARKER; |
428 | } | 436 | } |
429 | 437 | ||
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 79414abadd5e..894dea88678d 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * | 9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * | 11 | * |
12 | * $Id: wbuf.c,v 1.86 2005/02/05 18:23:37 hammache Exp $ | 12 | * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
@@ -415,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
415 | int ret; | 415 | int ret; |
416 | size_t retlen; | 416 | size_t retlen; |
417 | 417 | ||
418 | /* Nothing to do if not NAND flash. In particular, we shouldn't | 418 | /* Nothing to do if not write-buffering the flash. In particular, we shouldn't |
419 | del_timer() the timer we never initialised. */ | 419 | del_timer() the timer we never initialised. */ |
420 | if (jffs2_can_mark_obsolete(c)) | 420 | if (!jffs2_is_writebuffered(c)) |
421 | return 0; | 421 | return 0; |
422 | 422 | ||
423 | if (!down_trylock(&c->alloc_sem)) { | 423 | if (!down_trylock(&c->alloc_sem)) { |
@@ -426,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
426 | BUG(); | 426 | BUG(); |
427 | } | 427 | } |
428 | 428 | ||
429 | if(!c->wbuf || !c->wbuf_len) | 429 | if (!c->wbuf_len) /* already checked c->wbuf above */ |
430 | return 0; | 430 | return 0; |
431 | 431 | ||
432 | /* claim remaining space on the page | 432 | /* claim remaining space on the page |
@@ -620,7 +620,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
620 | uint32_t outvec_to = to; | 620 | uint32_t outvec_to = to; |
621 | 621 | ||
622 | /* If not NAND flash, don't bother */ | 622 | /* If not NAND flash, don't bother */ |
623 | if (!c->wbuf) | 623 | if (!jffs2_is_writebuffered(c)) |
624 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); | 624 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); |
625 | 625 | ||
626 | down_write(&c->wbuf_sem); | 626 | down_write(&c->wbuf_sem); |
@@ -649,7 +649,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
649 | erase block. Anything else, and you die. | 649 | erase block. Anything else, and you die. |
650 | New block starts at xxx000c (0-b = block header) | 650 | New block starts at xxx000c (0-b = block header) |
651 | */ | 651 | */ |
652 | if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { | 652 | if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { |
653 | /* It's a write to a new block */ | 653 | /* It's a write to a new block */ |
654 | if (c->wbuf_len) { | 654 | if (c->wbuf_len) { |
655 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); | 655 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); |
@@ -847,7 +847,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r | |||
847 | { | 847 | { |
848 | struct kvec vecs[1]; | 848 | struct kvec vecs[1]; |
849 | 849 | ||
850 | if (jffs2_can_mark_obsolete(c)) | 850 | if (!jffs2_is_writebuffered(c)) |
851 | return c->mtd->write(c->mtd, ofs, len, retlen, buf); | 851 | return c->mtd->write(c->mtd, ofs, len, retlen, buf); |
852 | 852 | ||
853 | vecs[0].iov_base = (unsigned char *) buf; | 853 | vecs[0].iov_base = (unsigned char *) buf; |
@@ -863,38 +863,37 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
863 | loff_t orbf = 0, owbf = 0, lwbf = 0; | 863 | loff_t orbf = 0, owbf = 0, lwbf = 0; |
864 | int ret; | 864 | int ret; |
865 | 865 | ||
866 | /* Read flash */ | 866 | if (!jffs2_is_writebuffered(c)) |
867 | if (!jffs2_can_mark_obsolete(c)) { | ||
868 | |||
869 | if (jffs2_cleanmarker_oob(c)) | ||
870 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | ||
871 | else | ||
872 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | ||
873 | |||
874 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | ||
875 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | ||
876 | len, ofs); | ||
877 | /* | ||
878 | * We have the raw data without ECC correction in the buffer, maybe | ||
879 | * we are lucky and all data or parts are correct. We check the node. | ||
880 | * If data are corrupted node check will sort it out. | ||
881 | * We keep this block, it will fail on write or erase and the we | ||
882 | * mark it bad. Or should we do that now? But we should give him a chance. | ||
883 | * Maybe we had a system crash or power loss before the ecc write or | ||
884 | * a erase was completed. | ||
885 | * So we return success. :) | ||
886 | */ | ||
887 | ret = 0; | ||
888 | } | ||
889 | } else | ||
890 | return c->mtd->read(c->mtd, ofs, len, retlen, buf); | 867 | return c->mtd->read(c->mtd, ofs, len, retlen, buf); |
891 | 868 | ||
869 | /* Read flash */ | ||
870 | if (jffs2_cleanmarker_oob(c)) | ||
871 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | ||
872 | else | ||
873 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | ||
874 | |||
875 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | ||
876 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | ||
877 | len, ofs); | ||
878 | /* | ||
879 | * We have the raw data without ECC correction in the buffer, maybe | ||
880 | * we are lucky and all data or parts are correct. We check the node. | ||
881 | * If data are corrupted node check will sort it out. | ||
882 | * We keep this block, it will fail on write or erase and the we | ||
883 | * mark it bad. Or should we do that now? But we should give him a chance. | ||
884 | * Maybe we had a system crash or power loss before the ecc write or | ||
885 | * a erase was completed. | ||
886 | * So we return success. :) | ||
887 | */ | ||
888 | ret = 0; | ||
889 | } | ||
890 | |||
892 | /* if no writebuffer available or write buffer empty, return */ | 891 | /* if no writebuffer available or write buffer empty, return */ |
893 | if (!c->wbuf_pagesize || !c->wbuf_len) | 892 | if (!c->wbuf_pagesize || !c->wbuf_len) |
894 | return ret;; | 893 | return ret;; |
895 | 894 | ||
896 | /* if we read in a different block, return */ | 895 | /* if we read in a different block, return */ |
897 | if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) | 896 | if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) |
898 | return ret; | 897 | return ret; |
899 | 898 | ||
900 | /* Lock only if we have reason to believe wbuf contains relevant data, | 899 | /* Lock only if we have reason to believe wbuf contains relevant data, |