[PATCH 1/2] [MTD] [JFFS2] MLC NAND support

Jason Liu liu.h.jason at gmail.com
Fri Sep 19 10:50:58 EDT 2008


Could you send out the panic log? How do you perform the robustness test.
Currently, I found the jffs2 filesystem can't support MLC well. Not
long time ago,
I use the patch JFFS2 doesn't use OOB at MLC NAND/OneNAND from
Kyungmin Park <kyungmin.park at samsung.com> on Sumsung MLC nand flash
K9LAG08U0M, but sometimes i will meet BUG() on the jffs2 file system. I suspect
that that patch does not completely handle MLC nand flash well. How
about this patch?

2008/9/19 AYYANARPONNUSAMY GANGHEYAMOORTHY <moorthy.apg at samsung.com>:
> Currently JFFS2 writes twice to the first page of the block,
> cleanmarker in OOB area and data in main area, which prevents
> JFFS2 from being used on MLC devices which have NOP count 1.
> This patch reserves the first page only for the cleanmarker.
>
> Note : With robustness testing, one test board out six has
> given a BUG. We are looking into it.
>
> Signed-off-by: Rajshekar H Payagond <rajshekar.hp at samsung.com>
> ---
> --- a/fs/jffs2/build.c  2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/build.c  2008-09-01 13:39:56.000000000 +0530
> @@ -330,7 +330,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
>        int i;
>        int size;
>
> -       c->free_size = c->flash_size;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
> +               c->free_size = 0;
> +       else
> +               c->free_size = c->flash_size;
> +
>        c->nr_blocks = c->flash_size / c->sector_size;
>        size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
>  #ifndef __ECOS
> @@ -346,7 +350,14 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
>        for (i=0; i<c->nr_blocks; i++) {
>                INIT_LIST_HEAD(&c->blocks[i].list);
>                c->blocks[i].offset = i * c->sector_size;
> -               c->blocks[i].free_size = c->sector_size;
> +               if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +                       c->blocks[i].free_size =
> +                                       c->sector_size - c->wbuf_pagesize;
> +                       c->blocks[i].used_size = c->wbuf_pagesize;
> +                       c->free_size +=  c->blocks[i].free_size;
> +                       c->used_size += c->blocks[i].used_size;
> +               } else
> +                       c->blocks[i].free_size = c->sector_size;
>        }
>
>        INIT_LIST_HEAD(&c->clean_list);
> --- a/fs/jffs2/debug.c  2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/debug.c  2008-09-01 13:39:56.000000000 +0530
> @@ -307,6 +307,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(s
>        uint32_t my_dirty_size = 0;
>        struct jffs2_raw_node_ref *ref2 = jeb->first_node;
>
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
> +               my_used_size = c->wbuf_pagesize;
> +
>        while (ref2) {
>                uint32_t totlen = ref_totlen(c, jeb, ref2);
>
> --- a/fs/jffs2/erase.c  2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/erase.c  2008-09-01 13:39:56.000000000 +0530
> @@ -454,13 +454,21 @@ static void jffs2_mark_erased_block(stru
>                }
>        }
>        /* Everything else got zeroed before the erase */
> -       jeb->free_size = c->sector_size;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +               jeb->free_size = c->sector_size - c->wbuf_pagesize;
> +               jeb->used_size = c->wbuf_pagesize;
> +       } else
> +               jeb->free_size = c->sector_size;
>
>        mutex_lock(&c->erase_free_sem);
>        spin_lock(&c->erase_completion_lock);
>
>        c->erasing_size -= c->sector_size;
> -       c->free_size += c->sector_size;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +               c->free_size += c->sector_size - c->wbuf_pagesize;
> +               c->used_size += c->wbuf_pagesize;
> +       } else
> +               c->free_size += c->sector_size;
>
>        /* Account for cleanmarker now, if it's in-band */
>        if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c))
> --- a/fs/jffs2/gc.c     2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/gc.c     2008-09-01 13:39:56.000000000 +0530
> @@ -237,9 +237,19 @@ int jffs2_garbage_collect_pass(struct jf
>        D1(if (c->nextblock)
>           printk(KERN_DEBUG "Nextblock at  %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
>
> -       if (!jeb->used_size) {
> -               mutex_unlock(&c->alloc_sem);
> -               goto eraseit;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +               if (jeb->used_size <= c->wbuf_pagesize) {
> +                       mutex_unlock(&c->alloc_sem);
> +                       goto eraseit;
> +               }
> +
> +       }
> +
> +       else{
> +               if (!jeb->used_size) {
> +                       mutex_unlock(&c->alloc_sem);
> +                       goto eraseit;
> +               }
>        }
>
>        raw = jeb->gc_node;
> @@ -429,13 +439,32 @@ int jffs2_garbage_collect_pass(struct jf
>        spin_lock(&c->erase_completion_lock);
>
>  eraseit:
> -       if (c->gcblock && !c->gcblock->used_size) {
> -               D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
> -               /* We're GC'ing an empty block? */
> -               list_add_tail(&c->gcblock->list, &c->erase_pending_list);
> -               c->gcblock = NULL;
> -               c->nr_erasing_blocks++;
> -               jffs2_erase_pending_trigger(c);
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +               if (c->gcblock && (c->gcblock->used_size <= c->wbuf_pagesize)) {
> +                       D1(printk(KERN_DEBUG "Block at 0x%08x completely"
> +                               " obsoleted by GC. Moving to erase_pending_list\n"
> +                               , c->gcblock->offset));
> +                       /* We're GC'ing an empty block? */
> +                       list_add_tail(&c->gcblock->list,
> +                                       &c->erase_pending_list);
> +                       c->gcblock = NULL;
> +                       c->nr_erasing_blocks++;
> +                       jffs2_erase_pending_trigger(c);
> +               }
> +       }
> +
> +       else{
> +               if (c->gcblock && !c->gcblock->used_size) {
> +                       D1(printk(KERN_DEBUG "Block at 0x%08x completely"
> +                               " obsoleted by GC. Moving to erase_pending_list\n"
> +                               , c->gcblock->offset));
> +                       /* We're GC'ing an empty block? */
> +                       list_add_tail(&c->gcblock->list,
> +                                       &c->erase_pending_list);
> +                       c->gcblock = NULL;
> +                       c->nr_erasing_blocks++;
> +                       jffs2_erase_pending_trigger(c);
> +               }
>        }
>        spin_unlock(&c->erase_completion_lock);
>
> --- a/fs/jffs2/nodelist.c       2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/nodelist.c       2008-09-01 13:39:56.000000000 +0530
> @@ -634,7 +634,11 @@ struct jffs2_raw_node_ref *jffs2_link_no
>
>        if (!jeb->first_node) {
>                jeb->first_node = ref;
> -               BUG_ON(ref_offset(ref) != jeb->offset);
> +               if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
> +                       BUG_ON(ref_offset(ref) !=
> +                                               jeb->offset + c->wbuf_pagesize);
> +               else
> +                       BUG_ON(ref_offset(ref) != jeb->offset);
>        } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) {
>                uint32_t last_len = ref_totlen(c, jeb, jeb->last_node);
>
> --- a/fs/jffs2/nodemgmt.c       2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/nodemgmt.c       2008-09-01 16:15:47.000000000 +0530
> @@ -362,16 +362,25 @@ static int jffs2_do_reserve_space(struct
>        }
>
>        if (!jeb) {
> -
>                ret = jffs2_find_nextblock(c);
>                if (ret)
>                        return ret;
>
>                jeb = c->nextblock;
> +               if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +                       if (jeb->free_size != c->sector_size -
> +                               c->cleanmarker_size - c->wbuf_pagesize) {
> +                               printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
> +                               goto restart;
> +                       }
> +               }
>
> -               if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
> -                       printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
> -                       goto restart;
> +               else{
> +                       if (jeb->free_size != c->sector_size -
> +                                       c->cleanmarker_size) {
> +                               printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
> +                               goto restart;
> +                       }
>                }
>        }
>        /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
> --- a/fs/jffs2/scan.c   2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/scan.c   2008-09-01 13:39:56.000000000 +0530
> @@ -534,7 +534,10 @@ static int jffs2_scan_eraseblock (struct
>                }
>        }
>
> -       buf_ofs = jeb->offset;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
> +               buf_ofs = jeb->offset + c->wbuf_pagesize;
> +       else
> +               buf_ofs = jeb->offset;
>
>        if (!buf_size) {
>                /* This is the XIP case -- we're reading _directly_ from the flash chip */
> @@ -582,7 +585,10 @@ static int jffs2_scan_eraseblock (struct
>        }
>
>        /* Now ofs is a complete physical flash offset as it always was... */
> -       ofs += jeb->offset;
> +       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH)
> +               ofs += jeb->offset + c->wbuf_pagesize;
> +       else
> +               ofs += jeb->offset;
>
>        noise = 10;
>
> --- a/fs/jffs2/wbuf.c   2008-08-24 04:48:32.000000000 +0530
> +++ b/fs/jffs2/wbuf.c   2008-09-01 13:39:56.000000000 +0530
> @@ -873,6 +873,13 @@ int jffs2_flash_writev(struct jffs2_sb_i
>                        vlen -= wbuf_retlen;
>                        outvec_to += wbuf_retlen;
>                        c->wbuf_ofs = outvec_to;
> +                       if (c->mtd->flags == MTD_CAP_MLCNANDFLASH) {
> +                               /* adjust write buffer offset,
> +                                * else we get a non contiguous write bug
> +                                */
> +                               if (!(c->wbuf_ofs % c->sector_size))
> +                                       c->wbuf_ofs = 0xffffffff;
> +                       }
>                        donelen += wbuf_retlen;
>                        v += wbuf_retlen;
>                }
> --- a/include/mtd/mtd-abi.h     2008-09-02 13:51:09.000000000 +0530
> +++ b/include/mtd/mtd-abi.h     2008-09-02 13:51:42.000000000 +0530
> @@ -28,12 +28,14 @@ struct mtd_oob_buf {
>  #define MTD_BIT_WRITEABLE      0x800   /* Single bits can be flipped */
>  #define MTD_NO_ERASE           0x1000  /* No erase necessary */
>  #define MTD_POWERUP_LOCK       0x2000  /* Always locked after reset */
> +#define MTD_WRITABLE_ONCE      0x4000
>
>  // Some common devices / combinations of capabilities
>  #define MTD_CAP_ROM            0
>  #define MTD_CAP_RAM            (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
>  #define MTD_CAP_NORFLASH       (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
>  #define MTD_CAP_NANDFLASH      (MTD_WRITEABLE)
> +#define MTD_CAP_MLCNANDFLASH   (MTD_WRITEABLE | MTD_WRITABLE_ONCE)
>
>  /* ECC byte placement */
>  #define MTD_NANDECC_OFF                0       // Switch off ECC (Not recommended)
>
>
>
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>



More information about the linux-mtd mailing list