最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

[patch 3] jffs2 for ecc nor

工作和技术 crifan 1839浏览 0评论

[patch 3] jffs2 for ecc nor



Two things are needed:
- erase marker has to be n times 8 byte, which makes it 16.
- wbuf.c has to be used, with a tiny buffer of 8 byte.

The former is done in an ugly way. David already prepared the
infrastructure for a nicer one, but that is untested.

The latter pulls all necessary functionality from wbuf.c into
nor_wbuf.c and touches a couple of other spots. This is currently a
config option, but it would make some sense to make this generic, as
already two types of flashes use it.

Joern

diff -Naur jffs2/fs/jffs2/Makefile jffs2.new/fs/jffs2/Makefile
--- jffs2/fs/jffs2/Makefile Wed Jun 19 18:56:23 2002
+++ jffs2.new/fs/jffs2/Makefile Thu Jul 11 16:06:24 2002
@@ -19,6 +19,7 @@
 LINUX_OBJS-25 := super.o
 
 NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o
+NAND_OBJS-$(CONFIG_JFFS2_FS_ECC_NOR) := nor_wbuf.o
 
 O_TARGET := jffs2.o
 
diff -Naur jffs2/fs/jffs2/erase.c jffs2.new/fs/jffs2/erase.c
--- jffs2/fs/jffs2/erase.c Thu Jul 11 16:16:15 2002
+++ jffs2.new/fs/jffs2/erase.c Thu Jul 11 16:11:08 2002
@@ -262,12 +262,21 @@
 
 void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
 {
+ static struct jffs2_cleanmarker marker = {
+  magic:  JFFS2_MAGIC_BITMASK,
+  nodetype: JFFS2_NODETYPE_CLEANMARKER,
+  padding: 0x0add0add,
+  totlen:  sizeof(struct jffs2_cleanmarker)
+ };
  struct jffs2_eraseblock *jeb;
  struct jffs2_raw_node_ref *marker_ref = NULL;
  unsigned char *ebuf;
  size_t retlen;
  int ret;
 
+ if (unlikely(!marker.hdr_crc))
+  marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4);
+
  spin_lock_bh(&c->erase_completion_lock);
  while (!list_empty(&c->erase_complete_list)) {
   jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
@@ -345,14 +354,6 @@
    jeb->used_size = 0;
    jeb->dirty_size = 0;
   } else {
-   struct jffs2_unknown_node marker = {
-    magic:  JFFS2_MAGIC_BITMASK,
-    nodetype: JFFS2_NODETYPE_CLEANMARKER,
-    totlen:  c->cleanmarker_size
-   };
-
-   marker.hdr_crc = crc32(0, &marker, sizeof(marker) - 4);
-
    ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
    if (ret) {
     printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %dn",
@@ -368,7 +369,7 @@
    marker_ref->next_in_ino = NULL;
    marker_ref->next_phys = NULL;
    marker_ref->flash_offset = jeb->offset;
-   marker_ref->totlen = PAD(marker.totlen);
+   marker_ref->totlen = PAD(sizeof(marker));
    
    jeb->first_node = jeb->last_node = marker_ref;
    
diff -Naur jffs2/fs/jffs2/fs.c jffs2.new/fs/jffs2/fs.c
--- jffs2/fs/jffs2/fs.c Wed Jul  3 15:23:51 2002
+++ jffs2.new/fs/jffs2/fs.c Thu Jul 11 16:11:30 2002
@@ -266,7 +266,6 @@
 {
  struct jffs2_sb_info *c;
  struct inode *root_i;
- int ret;
 
  c = JFFS2_SB_INFO(sb);
 
@@ -285,26 +284,18 @@
          c->flash_size / c->sector_size);
   return -EINVAL;
  }
-
- c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-
- if (c->mtd->eccsize) {
-  c->cleanmarker_size = (c->cleanmarker_size-1) / c->mtd->eccsize
-   * c->mtd->eccsize + c->mtd->eccsize;
- }
-
- if (jffs2_cleanmarker_oob(c)) {
-  /* Cleanmarker is out-of-band, so inline size zero */
-  c->cleanmarker_size = 0;
- }
-
+ 
+ /*
+  * TODO: Move the following code into a function, as it is
+  * duplicated almost verbatim 
+  */
  if (c->mtd->type == MTD_NANDFLASH) {
   /* Initialise write buffer */
   c->wbuf_pagesize = c->mtd->oobblock;
   c->wbuf_ofs = 0xFFFFFFFF;
   c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
   if (!c->wbuf)
-   return -ENOMEM;
+   goto out_mtd;
 
   /* Initialize process for timed wbuf flush */
   INIT_TQUEUE(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c);
@@ -312,19 +303,24 @@
   init_timer(&c->wbuf_timer);
   c->wbuf_timer.function = jffs2_wbuf_timeout;
   c->wbuf_timer.data = (unsigned long) c;
- }
+ } else if ((c->mtd->type == MTD_NORFLASH) && (c->mtd->flags & MTD_ECC)) {
+  /* Initialise write buffer */
+  c->wbuf_pagesize = c->mtd->eccsize; /* FIXME: is this the correct field? */
+  c->wbuf_ofs = 0xFFFFFFFF;
+  c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+  if (!c->wbuf)
+   goto out_mtd;
 
- c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
- if (!c->inocache_list) {
-  ret = -ENOMEM;
-  goto out_wbuf;
+  /* Initialize process for timed wbuf flush */
+  INIT_TQUEUE(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c);
+  /* Initialize timer for timed wbuf flush */
+  init_timer(&c->wbuf_timer);
+  c->wbuf_timer.function = jffs2_wbuf_timeout;
+  c->wbuf_timer.data = (unsigned long) c;
  }
- memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
-
- if ((ret = jffs2_do_mount_fs(c)))
-  goto out_inohash;
 
- ret = -EINVAL;
+ if (jffs2_do_mount_fs(c))
+  goto out_mtd;
 
  D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inoden"));
  root_i = iget(sb, 1);
@@ -354,10 +350,6 @@
  jffs2_free_ino_caches(c);
  jffs2_free_raw_node_refs(c);
  kfree(c->blocks);
- out_inohash:
- kfree(c->inocache_list);
- out_wbuf:
- if (c->wbuf)
-  kfree(c->wbuf);
- return ret;
+ out_mtd:
+ return -EINVAL;
 }
diff -Naur jffs2/fs/jffs2/nor_wbuf.c jffs2.new/fs/jffs2/nor_wbuf.c
--- jffs2/fs/jffs2/nor_wbuf.c Thu Jan  1 01:00:00 1970
+++ jffs2.new/fs/jffs2/nor_wbuf.c Thu Jul 11 16:15:10 2002
@@ -0,0 +1,477 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <[email protected]>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include "crc32.h"
+#include <linux/mtd/nand.h>
+#include "nodelist.h"
+
+#if 0 /* toggle this for debugging */
+#define CHECKPOINT(n) printk(__FUNCTION__ ": %dn", n)
+#else
+#define CHECKPOINT(n)
+#endif
+
+/* max. erase failures before we mark a block bad */
+#define MAX_ERASE_FAILURES  5
+
+/* two seconds timeout for timed wbuf-flushing */
+#define WBUF_FLUSH_TIMEOUT HZ / 4
+
+static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
+{
+ struct list_head *this, *next;
+ static int n;
+
+ CHECKPOINT(0);
+ if (list_empty(&c->erasable_pending_wbuf_list))
+  return;
+
+ list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
+  struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+  D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...n", jeb->offset));
+  list_del(this);
+  if ((jiffies + (n++)) & 127) {
+   /* Most of the time, we just erase it immediately. Otherwise we
+      spend ages scanning it on mount, etc. */
+   D1(printk(KERN_DEBUG "...and adding to erase_pending_listn"));
+   list_add_tail(&jeb->list, &c->erase_pending_list);
+   c->nr_erasing_blocks++;
+   jffs2_erase_pending_trigger(c);
+  } else {
+   /* Sometimes, however, we leave it elsewhere so it doesn't get
+      immediately reused, and we spread the load a bit. */
+   D1(printk(KERN_DEBUG "...and adding to erasable_listn"));
+   list_add_tail(&jeb->list, &c->erasable_list);
+  }
+ }
+}
+
+/* 
+* Timed flushing of wbuf. If we have no consecutive write to wbuf, within 
+* the specified time, we flush the contents with padding !
+*/
+void jffs2_wbuf_timeout (unsigned long data)
+{
+ struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;
+ CHECKPOINT(0);
+ /* 
+ * Wake up the flush process, we need process context to have the right 
+ * to sleep on flash write
+ */
+ D1(printk(KERN_DEBUG "jffs2_wbuf_timeout(): timer expiredn"));
+ schedule_task(&c->wbuf_task);
+}
+
+/*
+* Process for timed wbuf flush
+*
+* FIXME What happens, if we have a write failure there ????
+*/
+void jffs2_wbuf_process (void *data)
+{
+ struct jffs2_sb_info *c = (struct jffs2_sb_info *) data; 
+ 
+ CHECKPOINT(0);
+ D1(printk(KERN_DEBUG "jffs2_wbuf_process() enteredn"));
+
+ if (!down_trylock(&c->alloc_sem)) {
+  D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem gotn"));
+ 
+  if(!c->nextblock || (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)))
+   jffs2_flush_wbuf(c, 1); /* pad only */
+  else   
+   jffs2_flush_wbuf(c, 2); /* pad and adjust nextblock */
+  up(&c->alloc_sem);
+ } else {
+  D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupiedn"));
+ } 
+}
+
+
+/* Meaning of pad argument:
+   0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
+   1: Pad, do not adjust nextblock free_size
+   2: Pad, adjust nextblock free_size
+*/
+int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
+{
+ int ret;
+ size_t retlen;
+ 
+ CHECKPOINT(0);
+ if (!down_trylock(&c->alloc_sem)) {
+  up(&c->alloc_sem);
+  printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!n");
+  BUG();
+ }
+
+ /* delete a eventually started timed wbuf flush */
+ del_timer_sync(&c->wbuf_timer);
+
+ if(!c->wbuf || !c->wbuf_len)
+  return 0;
+
+ /* claim remaining space on the page
+    this happens, if we have a change to a new block,
+    or if fsync forces us to flush the writebuffer.
+    if we have a switch to next page, we will not have
+    enough remaining space for this. 
+ */
+ if (pad) {
+  c->wbuf_len = PAD(c->wbuf_len);
+  
+  if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
+   struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
+   padnode->magic = JFFS2_MAGIC_BITMASK;
+   padnode->nodetype = JFFS2_NODETYPE_PADDING;
+   padnode->totlen = c->wbuf_pagesize - c->wbuf_len;
+   padnode->hdr_crc = crc32(0, padnode, sizeof(*padnode)-4);
+  }
+ }
+ /* else jffs2_flash_writev has actually filled in the rest of the
+    buffer for us, and will deal with the node refs etc. later. */
+ 
+ ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
+ 
+ if (ret || retlen != c->wbuf_pagesize) {
+  if (ret)
+   printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %dn",ret);
+  else
+   printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short %d instead of %dn",retlen,c->wbuf_pagesize);
+   
+  ret = -EIO;  
+  /* CHECKME NAND 
+     So that the caller knows what happened. If
+     we were called from jffs2_flash_writev(), it'll
+     know to return failure and _its_ caller will
+     try again. writev gives back to jffs2_write_xxx 
+     in write.c. There are the real fixme's
+   */
+
+  /*  FIXME NAND
+     If we were called from GC or fsync, there's no repair kit yet
+  */
+      
+  return ret; 
+ }
+
+ /* Adjusting free size of next block only, if it's called from fsync ! */
+ if (pad == 2) {
+  D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblockn"));
+  spin_lock_bh(&c->erase_completion_lock);
+  if (!c->nextblock)
+   BUG();
+  if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len))
+   BUG();
+  c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len);
+  c->nextblock->dirty_size += (c->wbuf_pagesize - c->wbuf_len);
+  spin_unlock_bh(&c->erase_completion_lock);
+ }
+
+ /* Stick any now-obsoleted blocks on the erase_pending_list */
+ spin_lock_bh(&c->erase_completion_lock);
+ jffs2_refile_wbuf_blocks(c);
+ spin_unlock_bh(&c->erase_completion_lock);
+
+ memset(c->wbuf,0xff,c->wbuf_pagesize);
+ /* adjust write buffer offset, else we get a non contigous write bug */
+ c->wbuf_ofs+= c->wbuf_pagesize;
+ c->wbuf_len = 0;
+ return 0;
+}
+
+#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
+#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen)
+{
+ struct iovec outvecs[3];
+ uint32_t totlen = 0;
+ uint32_t split_ofs = 0;
+ uint32_t old_totlen;
+ int ret, splitvec = -1;
+ int invec, outvec;
+ size_t wbuf_retlen;
+ unsigned char *wbuf_ptr;
+ size_t donelen = 0;
+ uint32_t outvec_to = to;
+
+ CHECKPOINT(0);
+ /* If not NAND flash, don't bother */
+ if (!c->wbuf)
+  return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
+ 
+ CHECKPOINT(1);
+ /* If wbuf_ofs is not initialized, set it to target adress */
+ if (c->wbuf_ofs == 0xFFFFFFFF) {
+  c->wbuf_ofs = PAGE_DIV(to);
+  c->wbuf_len = PAGE_MOD(to);   
+  memset(c->wbuf,0xff,c->wbuf_pagesize);
+ }
+
+ CHECKPOINT(2);
+ /* Sanity checks on target address. 
+    It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 
+    and it's permitted to write at the beginning of a new 
+    erase block. Anything else, and you die.
+    New block starts at xxx000c (0-b = block header)
+ */
+ if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
+  /* 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%08xn", (unsigned long)to, c->wbuf_ofs));
+   ret = jffs2_flush_wbuf(c, 1);
+   if (ret) {
+    /* the underlying layer has to check wbuf_len to do the cleanup */
+    D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %dn", ret));
+    *retlen = 0;
+    return ret;
+   }
+  }
+  /* set pointer to new block */
+  c->wbuf_ofs = PAGE_DIV(to);
+  c->wbuf_len = PAGE_MOD(to);   
+ } 
+
+ CHECKPOINT(3);
+ if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
+  /* We're not writing immediately after the writebuffer. Bad. */
+  printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lxn", (unsigned long)to);
+  if (c->wbuf_len)
+   printk(KERN_CRIT "wbuf was previously %08x-%08xn",
+       c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
+  printk(KERN_CRIT "wbuf size is 0x%08xn", c->wbuf_pagesize);
+  BUG();
+ }
+
+ CHECKPOINT(4);
+ /* Note outvecs[3] above. We know count is never greater than 2 */
+ if (count > 2) {
+  printk(KERN_CRIT "jffs2_flash_writev(): count is %ldn", count);
+  BUG();
+ }
+
+ invec = 0;
+ outvec = 0;
+
+
+ CHECKPOINT(5);
+ /* Fill writebuffer first, if already in use */ 
+ if (c->wbuf_len) {
+  uint32_t invec_ofs = 0;
+
+  /* adjust alignment offset */ 
+  if (c->wbuf_len != PAGE_MOD(to)) {
+   c->wbuf_len = PAGE_MOD(to);
+   /* take care of alignment to next page */
+   if (!c->wbuf_len)
+    c->wbuf_len = c->wbuf_pagesize;
+  }
+  
+  while(c->wbuf_len < c->wbuf_pagesize) {
+   uint32_t thislen;
+   
+   if (invec == count)
+    goto alldone;
+
+   thislen = c->wbuf_pagesize - c->wbuf_len;
+
+   if (thislen >= invecs[invec].iov_len)
+    thislen = invecs[invec].iov_len;
+ 
+   invec_ofs = thislen;
+
+   memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
+   c->wbuf_len += thislen;
+   donelen += thislen;
+   /* Get next invec, if actual did not fill the buffer */
+   if (c->wbuf_len < c->wbuf_pagesize) 
+    invec++;
+  }   
+  
+  /* write buffer is full, flush buffer */
+  ret = jffs2_flush_wbuf(c, 0);
+  if (ret) {
+   /* the underlying layer has to check wbuf_len to do the cleanup */
+   D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %dn", ret));
+   *retlen = 0;
+   return ret;
+  }
+  outvec_to += donelen;
+  c->wbuf_ofs = outvec_to;
+  
+  /* All invecs done ? */
+  if (invec == count)
+   goto alldone;
+
+  /* Set up the first outvec, containing the remainder of the
+     invec we partially used */
+  if (invecs[invec].iov_len > invec_ofs) {
+   outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;
+   totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;
+   if (totlen > c->wbuf_pagesize) {
+    splitvec = outvec;
+    split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);
+   }
+   outvec++;
+  }
+  invec++;
+ }
+
+ /* OK, now we've flushed the wbuf and the start of the bits
+    we have been asked to write, now to write the rest.... */
+
+ CHECKPOINT(6);
+ /* totlen holds the amount of data still to be written */
+ old_totlen = totlen;
+ for ( ; invec < count; invec++,outvec++ ) {
+  outvecs[outvec].iov_base = invecs[invec].iov_base;
+  totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;
+  if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {
+   splitvec = outvec;
+   split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);
+   old_totlen = totlen;
+  }
+ }
+
+ /* Now the outvecs array holds all the remaining data to write */
+ /* Up to splitvec,split_ofs is to be written immediately. The rest
+    goes into the (now-empty) wbuf */
+
+ CHECKPOINT(7);
+ if (splitvec != -1) {
+  uint32_t remainder;
+  int ret;
+
+  remainder = outvecs[splitvec].iov_len - split_ofs;
+  outvecs[splitvec].iov_len = split_ofs;
+
+  /* We did cross a page boundary, so we write some now */
+  ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); 
+  if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
+   /* At this point we have no problem,
+      c->wbuf is empty. 
+   */
+   *retlen = donelen;
+   return ret;
+  }
+  
+  donelen += wbuf_retlen;
+  c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
+
+  if (remainder) {
+   outvecs[splitvec].iov_base += split_ofs;
+   outvecs[splitvec].iov_len = remainder;
+  } else {
+   splitvec++;
+  }
+
+ } else {
+  splitvec = 0;
+ }
+
+ /* Now splitvec points to the start of the bits we have to copy
+    into the wbuf */
+ wbuf_ptr = c->wbuf;
+
+ CHECKPOINT(8);
+ for ( ; splitvec < outvec; splitvec++) {
+  /* Don't copy the wbuf into itself */
+  if (outvecs[splitvec].iov_base == c->wbuf)
+   continue;
+  memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len);
+  wbuf_ptr += outvecs[splitvec].iov_len;
+  donelen += outvecs[splitvec].iov_len;
+ }
+ c->wbuf_len = wbuf_ptr - c->wbuf;
+
+alldone: 
+ CHECKPOINT(9);
+ *retlen = donelen;
+ /* Setup timed wbuf flush, if buffer len != 0 */
+ if (c->wbuf_len) {
+  D1(printk (KERN_DEBUG "jffs2_flash_writev: mod wbuf_timern")); 
+  mod_timer(&c->wbuf_timer, jiffies + WBUF_FLUSH_TIMEOUT);
+ }
+ return 0;
+}
+
+/*
+ This is the entry for NOR-Flash. We use it also for NAND to flush wbuf
+*/
+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
+{
+ CHECKPOINT(0);
+ return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+}
+
+/*
+ Handle readback from writebuffer and ECC failure return
+*/
+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
+{
+ loff_t orbf = 0, owbf = 0, lwbf = 0;
+ int ret;
+
+ /* Read flash */
+ ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
+
+ if (!jffs2_can_mark_obsolete(c) && (ret == -EIO) && (*retlen == len) ) {
+  printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC errorn", 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 (!c->wbuf_pagesize || !c->wbuf_len)
+  return ret;
+
+
+ /* if we read in a different block, return */
+ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) 
+  return ret; 
+
+ if (ofs >= c->wbuf_ofs) {
+  owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
+  if (owbf > c->wbuf_len)  /* is read beyond write buffer ? */
+   return ret;
+  lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
+  if (lwbf > len) 
+   lwbf = len;
+ } else { 
+  orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
+  if (orbf > len)   /* is write beyond write buffer ? */
+   return ret;
+  lwbf = len - orbf;   /* number of bytes to copy */
+  if (lwbf > c->wbuf_len) 
+   lwbf = c->wbuf_len;
+ } 
+ if (lwbf > 0)
+  memcpy(buf+orbf,c->wbuf+owbf,lwbf);
+
+ return ret;
+}
+
diff -Naur jffs2/fs/jffs2/os-linux.h jffs2.new/fs/jffs2/os-linux.h
--- jffs2/fs/jffs2/os-linux.h Wed Jun 19 18:56:25 2002
+++ jffs2.new/fs/jffs2/os-linux.h Thu Jul 11 16:13:32 2002
@@ -67,6 +67,24 @@
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
 #ifndef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_ECC_NOR /* ECC'd NOR flash */
+
+#define jffs2_can_mark_obsolete(c) (0)
+#define jffs2_cleanmarker_oob(c) (0)
+#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
+
+#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
+#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
+
+/* nor_wbuf.c */
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
+void jffs2_wbuf_timeout(unsigned long data);
+void jffs2_wbuf_process(void *data);
+
+#else /* normal NOR flash */
+
 #define jffs2_can_mark_obsolete(c) (1)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -80,6 +98,7 @@
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
 
+#endif
 #else /* NAND support present */
 
 #define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
diff -Naur jffs2/fs/jffs2/scan.c jffs2.new/fs/jffs2/scan.c
--- jffs2/fs/jffs2/scan.c Wed Jul  3 15:36:02 2002
+++ jffs2.new/fs/jffs2/scan.c Thu Jul 11 16:14:19 2002
@@ -342,14 +342,14 @@
    break;
 
   case JFFS2_NODETYPE_CLEANMARKER:
-   if (node.totlen != c->cleanmarker_size) {
+   if (node.totlen != sizeof(struct jffs2_cleanmarker)) {
     printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%xn", 
-           ofs, node.totlen, c->cleanmarker_size);
-    DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
+           ofs, node.totlen, sizeof(struct jffs2_cleanmarker));
+    DIRTY_SPACE(PAD(sizeof(struct jffs2_cleanmarker)));
    } else if (jeb->first_node) {
     printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)n", ofs, jeb->offset);
-    DIRTY_SPACE(PAD(c->cleanmarker_size));
-    ofs += PAD(c->cleanmarker_size);
+    DIRTY_SPACE(PAD(sizeof(struct jffs2_cleanmarker)));
+    ofs += PAD(sizeof(struct jffs2_cleanmarker));
     continue;
    } else {
     struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
@@ -360,12 +360,12 @@
     marker_ref->next_in_ino = NULL;
     marker_ref->next_phys = NULL;
     marker_ref->flash_offset = ofs;
-    marker_ref->totlen = c->cleanmarker_size;
+    marker_ref->totlen = sizeof(struct jffs2_cleanmarker);
     jeb->first_node = jeb->last_node = marker_ref;
         
-    USED_SPACE(PAD(c->cleanmarker_size));
+    USED_SPACE(PAD(sizeof(struct jffs2_cleanmarker)));
    }
-   ofs += PAD(c->cleanmarker_size);
+   ofs += PAD(sizeof(struct jffs2_cleanmarker));
    break;
 
   case JFFS2_NODETYPE_PADDING:
@@ -407,7 +407,7 @@
  D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08xn", jeb->offset, 
     jeb->free_size, jeb->dirty_size, jeb->used_size));
 
- if (jeb->used_size == PAD(c->cleanmarker_size) && 
+ if (jeb->used_size == PAD(sizeof(struct jffs2_cleanmarker)) && 
      !jeb->first_node->next_in_ino && !jeb->dirty_size)
   return BLK_STATE_CLEANMARKER;
  else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode)))
@@ -628,7 +628,7 @@
   if (!jeb->used_size) {
    D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08xn", 
       jeb->offset, raw->flash_offset & ~3));
-    ri.nodetype &= ~JFFS2_NODE_ACCURATE;
+   ri.nodetype &= ~JFFS2_NODE_ACCURATE;
    /* Perhaps we could also mark it as such on the medium. Maybe later */
   }
   break;
@@ -654,11 +654,7 @@
   tn->version = ri.version;
 
   USED_SPACE(PAD(ri.totlen));
-
-  /* No need to scan from the beginning of the list again. 
-     We can start from tn_list instead (Thanks Jocke) */
-  jffs2_add_tn_to_list(tn, tn_list);
-
+  jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes);
   /* Make sure the one we just added is the _last_ in the list
      with this version number, so the older ones get obsoleted */
   while (tn->next && tn->next->version == tn->version) {
diff -Naur jffs2/include/linux/jffs2.h jffs2.new/include/linux/jffs2.h
--- jffs2/include/linux/jffs2.h Wed Jun 19 18:56:27 2002
+++ jffs2.new/include/linux/jffs2.h Thu Jul 11 16:03:37 2002
@@ -77,6 +77,15 @@
  uint32_t hdr_crc;
 } __attribute__((packed));
 
+struct jffs2_cleanmarker
+{
+ uint16_t magic;
+ uint16_t nodetype;
+ uint32_t totlen;
+ uint32_t hdr_crc;
+ uint32_t padding; /* Necessary for some STMicro flashes */
+} __attribute__((packed));
+
 struct jffs2_raw_dirent
 {
  uint16_t magic;
@@ -130,6 +139,7 @@
 union jffs2_node_union {
  struct jffs2_raw_inode i;
  struct jffs2_raw_dirent d;
+ struct jffs2_cleanmarker c;
  struct jffs2_unknown_node u;
 };
 

To unsubscribe from this list: send the line "unsubscribe jffs-dev" in
the body of a message to [email protected]

转载请注明:在路上 » [patch 3] jffs2 for ecc nor

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
79 queries in 0.184 seconds, using 22.15MB memory