Re: data loss on jffs2 filesystem on dataflash

Peter Menzebach
2005-09-22T12:30:30Z

Peter Menzebach wrote:
> Hi,
> I loose files, which I write on a jffs2 filesystem.
>
> I start with a freshly erased mtd partition. Then I start the following
> sequence:
>
> mount /conf
> echo aaa > /conf/aaa
> echo aaa > /conf/aaa
> umount /conf
> mount /conf
>
> After remounting, the file gets lost (I think because the GC removes the
> inode). I use kernel 2.6.13 with mtd out of cvs of today.
> The machine is a AT91RM9200 with a serial dataflash. I used already
> jffs2 (most time readonly) as rootfs here for months without problems.
> The only specialty is, that the dataflash has a unfamiliar erase size of
> 8448 bytes.
>
OK guys,
here we are with a patch for it. I made several tests now with
wbuf->pagesize of 1056 and 8*1056 and erase size of 8*1056 and it looks
good so far.

Open is now the question, if we should implement a possibility to adjust
the wbuf_pagesize independently from the jffs2 sectorsize. For my
purposes I can live with a wbuf_size = jffs2 sector_size = 8*1056, but
if we find a nice solution, I would implement it...

IMHO the cleanest solution would be, that the dataflash/mtd layer
reports it's true erase_size = smallest write size = 528/1056 bytes, and
should not make a further guess about later use.

JFFS2 now recognizes, that it can't work with this parameters, and
should adjust it to multiples of the size internally.

Please comment to patch and how to proceed...

Best regards
Peter

P.S. Sry I can't manage to send the patch as attachment. (it get's
rejected by the mailing list)

diff -urN mtda/fs/jffs2/nodelist.c mtdb/fs/jffs2/nodelist.c
--- mtda/fs/jffs2/nodelist.c 2005-09-22 13:47:32.000000000 +0200
+++ mtdb/fs/jffs2/nodelist.c 2005-09-22 13:44:50.000000000 +0200
@@ -412,7 +412,7 @@

/* Calculate how many bytes were already checked */
ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
- len = ofs & (c->wbuf_pagesize - 1);
+ len = ofs % c->wbuf_pagesize;
if (likely(len))
len = c->wbuf_pagesize - len;

diff -urN mtda/fs/jffs2/os-linux.h mtdb/fs/jffs2/os-linux.h
--- mtda/fs/jffs2/os-linux.h 2005-09-22 13:47:36.000000000 +0200
+++ mtdb/fs/jffs2/os-linux.h 2005-09-22 13:44:53.000000000 +0200
@@ -65,8 +65,12 @@

#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)

-#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+/*
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+*/
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+#define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) *
c->sector_size) )
+

#ifdef CONFIG_JFFS2_SUMMARY
#define jffs2_can_mark_obsolete(c) (0)
diff -urN mtda/fs/jffs2/scan.c mtdb/fs/jffs2/scan.c
--- mtda/fs/jffs2/scan.c 2005-09-22 13:47:32.000000000 +0200
+++ mtdb/fs/jffs2/scan.c 2005-09-22 13:44:50.000000000 +0200
@@ -233,12 +233,12 @@
c->nextblock->dirty_size = 0;
}
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- if (!jffs2_can_mark_obsolete(c) && c->nextblock &&
(c->nextblock->free_size & (c->wbuf_pagesize-1))) {
+ if (!jffs2_can_mark_obsolete(c) && c->nextblock &&
(c->nextblock->free_size % c->wbuf_pagesize)) {
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
skip a little and align it. */

- uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1);
+ uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize;

D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in
nextblock to ensure page alignment\n",
skip));
diff -urN mtda/fs/jffs2/wbuf.c mtdb/fs/jffs2/wbuf.c
--- mtda/fs/jffs2/wbuf.c 2005-09-22 13:47:32.000000000 +0200
+++ mtdb/fs/jffs2/wbuf.c 2005-09-22 13:44:50.000000000 +0200
@@ -28,12 +28,12 @@
static unsigned char *brokenbuf;
#endif

+#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) )
+
/* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 2

-/* two seconds timeout for timed wbuf-flushing */
-#define WBUF_FLUSH_TIMEOUT 2 * HZ
-
struct jffs2_inodirty {
uint32_t ino;
struct jffs2_inodirty *next;
@@ -434,7 +434,7 @@
if we have a switch to next page, we will not have
enough remaining space for this.
*/
- if (pad && !jffs2_dataflash(c)) {
+ if (pad ) {
c->wbuf_len = PAD(c->wbuf_len);

/* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
@@ -483,9 +483,9 @@
}

spin_lock(&c->erase_completion_lock);
-
+
/* Adjust free size of the block if we padded. */
- if (pad && !jffs2_dataflash(c)) {
+ if (pad) {
struct jffs2_eraseblock *jeb;

jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -602,15 +602,6 @@

return ret;
}
-
-#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-#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];
@@ -654,7 +645,7 @@
erase block. Anything else, and you die.
New block starts at xxx000c (0-b = block header)
*/
- if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
+ if (PAGE_DIV(to) != PAGE_DIV(c->wbuf_ofs)) {
/* It's a write to a new block */
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));
@@ -905,7 +896,7 @@
goto exit;

/* if we read in a different block, return */
- if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
+ if (PAGE_DIV(ofs) != PAGE_DIV(c->wbuf_ofs))
goto exit;

if (ofs >= c->wbuf_ofs) {
@@ -1104,7 +1095,7 @@
return 0;

if (!c->mtd->block_markbad)
- return 1; // What else can we do?
+ return 1;

D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad
block at %08x\n", bad_offset));
ret = c->mtd->block_markbad(c->mtd, bad_offset);
diff -urN mtda/drivers/mtd/mtdpart.c mtdb/drivers/mtd/mtdpart.c
--- mtda/drivers/mtd/mtdpart.c 2005-02-08 18:11:13.000000000 +0100
+++ mtdb/drivers/mtd/mtdpart.c 2005-09-14 13:20:18.000000000 +0200
@@ -465,8 +465,9 @@
if (slave->offset == MTDPART_OFS_APPEND)
slave->offset = cur_offset;
if (slave->offset == MTDPART_OFS_NXTBLK) {
- u_int32_t emask = master->erasesize-1;
- slave->offset = (cur_offset + emask) & ~emask;
+ slave->offset = cur_offset;
+ if ((cur_offset % master->erasesize) != 0)
+ slave->offset = ((cur_offset / master->erasesize) + 1) *
master->erasesize;
if (slave->offset != cur_offset) {
printk(KERN_NOTICE "Moving partition %d: "
"0x%08x -> 0x%08x\n", i,