- To: [email protected]
- Subject: [patch 3] jffs2 for ecc nor
- From: Jörn Engel <[email protected]>
- Date: Thu, 11 Jul 2002 17:48:28 +0200
- Cc: [email protected]
- Sender: [email protected]
- User-agent: Mutt/1.3.28i
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