[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>
This commit is contained in:
committed by
Thomas Gleixner
parent
045e9a5d51
commit
3be36675d4
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* For licensing information, see the file 'LICENCE' in this directory.
|
||||||
*
|
*
|
||||||
* $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
|
* $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
|
if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
|
||||||
/* It's in the block we're erasing */
|
/* It's in the block we're erasing */
|
||||||
struct jffs2_raw_node_ref *this;
|
struct jffs2_raw_node_ref *this;
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* For licensing information, see the file 'LICENCE' in this directory.
|
||||||
*
|
*
|
||||||
* $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
|
* $Id: gc.c,v 1.145 2005/02/09 09:09:01 pavlov Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -816,8 +816,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
|
|||||||
|
|
||||||
/* Doesn't matter if there's one in the same erase block. We're going to
|
/* Doesn't matter if there's one in the same erase block. We're going to
|
||||||
delete it too at the same time. */
|
delete it too at the same time. */
|
||||||
if ((raw->flash_offset & ~(c->sector_size-1)) ==
|
if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
|
||||||
(fd->raw->flash_offset & ~(c->sector_size-1)))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
|
D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* For licensing information, see the file 'LICENCE' in this directory.
|
||||||
*
|
*
|
||||||
* $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
|
* $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -97,7 +97,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
|
||||||
|
|
||||||
#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
|
#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)
|
||||||
#define jffs2_can_mark_obsolete(c) (1)
|
#define jffs2_can_mark_obsolete(c) (1)
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* For licensing information, see the file 'LICENCE' in this directory.
|
||||||
*
|
*
|
||||||
* $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
|
* $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include "nodelist.h"
|
#include "nodelist.h"
|
||||||
|
|
||||||
#define EMPTY_SCAN_SIZE 1024
|
#define DEFAULT_EMPTY_SCAN_SIZE 1024
|
||||||
|
|
||||||
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
|
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
|
||||||
c->free_size -= _x; c->dirty_size += _x; \
|
c->free_size -= _x; c->dirty_size += _x; \
|
||||||
@@ -75,6 +75,14 @@ static inline int min_free(struct jffs2_sb_info *c)
|
|||||||
return min;
|
return min;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
|
||||||
|
if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
|
||||||
|
return sector_size;
|
||||||
|
else
|
||||||
|
return DEFAULT_EMPTY_SCAN_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
int jffs2_scan_medium(struct jffs2_sb_info *c)
|
int jffs2_scan_medium(struct jffs2_sb_info *c)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
@@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||||||
if (!buf_size) {
|
if (!buf_size) {
|
||||||
buf_len = c->sector_size;
|
buf_len = c->sector_size;
|
||||||
} else {
|
} else {
|
||||||
buf_len = EMPTY_SCAN_SIZE;
|
buf_len = EMPTY_SCAN_SIZE(c->sector_size);
|
||||||
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
|
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@@ -326,10 +334,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||||||
ofs = 0;
|
ofs = 0;
|
||||||
|
|
||||||
/* Scan only 4KiB of 0xFF before declaring it's empty */
|
/* Scan only 4KiB of 0xFF before declaring it's empty */
|
||||||
while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
|
while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
|
||||||
ofs += 4;
|
ofs += 4;
|
||||||
|
|
||||||
if (ofs == EMPTY_SCAN_SIZE) {
|
if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
|
||||||
#ifdef CONFIG_JFFS2_FS_NAND
|
#ifdef CONFIG_JFFS2_FS_NAND
|
||||||
if (jffs2_cleanmarker_oob(c)) {
|
if (jffs2_cleanmarker_oob(c)) {
|
||||||
/* scan oob, take care of cleanmarker */
|
/* scan oob, take care of cleanmarker */
|
||||||
@@ -423,7 +431,7 @@ scan_more:
|
|||||||
bail now */
|
bail now */
|
||||||
if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
|
if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
|
||||||
c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
|
c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
|
||||||
D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
|
D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
|
||||||
return BLK_STATE_CLEANMARKER;
|
return BLK_STATE_CLEANMARKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* For licensing information, see the file 'LICENCE' in this directory.
|
||||||
*
|
*
|
||||||
* $Id: wbuf.c,v 1.86 2005/02/05 18:23:37 hammache Exp $
|
* $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -415,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||||||
int ret;
|
int ret;
|
||||||
size_t retlen;
|
size_t retlen;
|
||||||
|
|
||||||
/* Nothing to do if not NAND flash. In particular, we shouldn't
|
/* Nothing to do if not write-buffering the flash. In particular, we shouldn't
|
||||||
del_timer() the timer we never initialised. */
|
del_timer() the timer we never initialised. */
|
||||||
if (jffs2_can_mark_obsolete(c))
|
if (!jffs2_is_writebuffered(c))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!down_trylock(&c->alloc_sem)) {
|
if (!down_trylock(&c->alloc_sem)) {
|
||||||
@@ -426,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!c->wbuf || !c->wbuf_len)
|
if (!c->wbuf_len) /* already checked c->wbuf above */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* claim remaining space on the page
|
/* claim remaining space on the page
|
||||||
@@ -620,7 +620,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
|
|||||||
uint32_t outvec_to = to;
|
uint32_t outvec_to = to;
|
||||||
|
|
||||||
/* If not NAND flash, don't bother */
|
/* If not NAND flash, don't bother */
|
||||||
if (!c->wbuf)
|
if (!jffs2_is_writebuffered(c))
|
||||||
return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
|
return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
|
||||||
|
|
||||||
down_write(&c->wbuf_sem);
|
down_write(&c->wbuf_sem);
|
||||||
@@ -649,7 +649,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
|
|||||||
erase block. Anything else, and you die.
|
erase block. Anything else, and you die.
|
||||||
New block starts at xxx000c (0-b = block header)
|
New block starts at xxx000c (0-b = block header)
|
||||||
*/
|
*/
|
||||||
if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
|
if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
|
||||||
/* It's a write to a new block */
|
/* It's a write to a new block */
|
||||||
if (c->wbuf_len) {
|
if (c->wbuf_len) {
|
||||||
D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
|
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
|
|||||||
{
|
{
|
||||||
struct kvec vecs[1];
|
struct kvec vecs[1];
|
||||||
|
|
||||||
if (jffs2_can_mark_obsolete(c))
|
if (!jffs2_is_writebuffered(c))
|
||||||
return c->mtd->write(c->mtd, ofs, len, retlen, buf);
|
return c->mtd->write(c->mtd, ofs, len, retlen, buf);
|
||||||
|
|
||||||
vecs[0].iov_base = (unsigned char *) buf;
|
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
|
|||||||
loff_t orbf = 0, owbf = 0, lwbf = 0;
|
loff_t orbf = 0, owbf = 0, lwbf = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Read flash */
|
if (!jffs2_is_writebuffered(c))
|
||||||
if (!jffs2_can_mark_obsolete(c)) {
|
|
||||||
|
|
||||||
if (jffs2_cleanmarker_oob(c))
|
|
||||||
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
|
|
||||||
else
|
|
||||||
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
|
||||||
|
|
||||||
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
|
||||||
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
|
||||||
len, ofs);
|
|
||||||
/*
|
|
||||||
* We have the raw data without ECC correction in the buffer, maybe
|
|
||||||
* we are lucky and all data or parts are correct. We check the node.
|
|
||||||
* If data are corrupted node check will sort it out.
|
|
||||||
* We keep this block, it will fail on write or erase and the we
|
|
||||||
* mark it bad. Or should we do that now? But we should give him a chance.
|
|
||||||
* Maybe we had a system crash or power loss before the ecc write or
|
|
||||||
* a erase was completed.
|
|
||||||
* So we return success. :)
|
|
||||||
*/
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
return c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
return c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||||
|
|
||||||
|
/* Read flash */
|
||||||
|
if (jffs2_cleanmarker_oob(c))
|
||||||
|
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
|
||||||
|
else
|
||||||
|
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
|
||||||
|
|
||||||
|
if ( (ret == -EBADMSG) && (*retlen == len) ) {
|
||||||
|
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
|
||||||
|
len, ofs);
|
||||||
|
/*
|
||||||
|
* We have the raw data without ECC correction in the buffer, maybe
|
||||||
|
* we are lucky and all data or parts are correct. We check the node.
|
||||||
|
* If data are corrupted node check will sort it out.
|
||||||
|
* We keep this block, it will fail on write or erase and the we
|
||||||
|
* mark it bad. Or should we do that now? But we should give him a chance.
|
||||||
|
* Maybe we had a system crash or power loss before the ecc write or
|
||||||
|
* a erase was completed.
|
||||||
|
* So we return success. :)
|
||||||
|
*/
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* if no writebuffer available or write buffer empty, return */
|
/* if no writebuffer available or write buffer empty, return */
|
||||||
if (!c->wbuf_pagesize || !c->wbuf_len)
|
if (!c->wbuf_pagesize || !c->wbuf_len)
|
||||||
return ret;;
|
return ret;;
|
||||||
|
|
||||||
/* if we read in a different block, return */
|
/* if we read in a different block, return */
|
||||||
if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
|
if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Lock only if we have reason to believe wbuf contains relevant data,
|
/* Lock only if we have reason to believe wbuf contains relevant data,
|
||||||
|
Reference in New Issue
Block a user