From linux-mtd at lists.infradead.org  Fri Jun  2 19:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Sat, 03 Jun 2006 00:59:02 +0100
Subject: [JFFS2] Remove stray __exit from jffs2_compressors_exit()
Message-ID: <E1FmJXh-0002Ua-UK@pentafluge.infradead.org>

Commit:     3bcc86f507f5a0b6f5bfa312f37ec33711558acb
Parent:     e9482b4374e2596e6f3f1ab30c4ea469f4ac6311
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sat Jun 3 00:25:50 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sat Jun 3 00:25:50 2006 +0100

    [JFFS2] Remove stray __exit from jffs2_compressors_exit()
    
    It's used from the initfunc in case of failure too. We could actually do
    with an '__initexit' for this kind of thing -- when built in to the
    kernel, it could do with being dropped with the init text. We _could_
    actually just use __init for it, but that would break if/when we start
    dropping init text from modules. So let's just leave it as it was for now,
    and mutter a little more about random 'janitorial' fixes from people who
    aren't paying attention to what they're doing.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>

 fs/jffs2/compr.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 5f45e01..7001ba2 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -440,7 +440,7 @@ #endif
         return 0;
 }
 
-int __exit jffs2_compressors_exit(void)
+int jffs2_compressors_exit(void)
 {
 /* Unregistering compressors */
 #ifdef CONFIG_JFFS2_RUBIN


From linux-mtd at lists.infradead.org  Fri Jun  9 10:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Fri, 09 Jun 2006 15:59:01 +0100
Subject: [JFFS2] Fix more breakage caused by janitorial meddling.
Message-ID: <E1FoiRx-00024t-F4@pentafluge.infradead.org>

Commit:     4ed0156f774cf50252e7f51032d1cc857fe86879
Parent:     3bcc86f507f5a0b6f5bfa312f37ec33711558acb
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Fri Jun 9 15:06:42 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Fri Jun 9 15:06:42 2006 +0100

    [JFFS2] Fix more breakage caused by janitorial meddling.
    
    jffs2_zlib_exit() and free_workspaces() shouldn't be marked __exit because
    they get called in the error case from the init functions.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>

 fs/jffs2/compr_zlib.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index d43cbac..5c63e0c 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -60,7 +60,7 @@ static int __init alloc_workspaces(void)
 	return 0;
 }
 
-static void __exit free_workspaces(void)
+static void free_workspaces(void)
 {
 	vfree(def_strm.workspace);
 	vfree(inf_strm.workspace);
@@ -216,7 +216,7 @@ int __init jffs2_zlib_init(void)
     return ret;
 }
 
-void __exit jffs2_zlib_exit(void)
+void jffs2_zlib_exit(void)
 {
     jffs2_unregister_compressor(&jffs2_zlib_comp);
     free_workspaces();


From linux-mtd at lists.infradead.org  Fri Jun  9 10:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Fri, 09 Jun 2006 15:59:02 +0100
Subject: [MTD] Prepare physmap for 64-bit-resources
Message-ID: <E1FoiRx-00025V-VU@pentafluge.infradead.org>

Commit:     f24ff6bf8c903bc0c645bf87fbe87f9a6d9f634f
Parent:     4ed0156f774cf50252e7f51032d1cc857fe86879
Author:     Andrew Morton <akpm at osdl.org>
AuthorDate: Fri Jun 9 15:12:34 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Fri Jun 9 15:12:34 2006 +0100

    [MTD] Prepare physmap for 64-bit-resources
    
    Fallout from the incoming 64-bit-resource stuff:
    
    drivers/mtd/maps/physmap.c: In function 'physmap_flash_probe':
    drivers/mtd/maps/physmap.c:94: warning: format '%.8lx' expects type 'long
    unsigned int', but argument 2 has type 'resource_size_t'
    drivers/mtd/maps/physmap.c:94: warning: format '%.8lx' expects type 'long
    unsigned int', but argument 3 has type 'resource_size_t'
    
    Cc: Vivek Goyal <vgoyal at in.ibm.com>
    Cc: Greg KH <greg at kroah.com>
    Signed-off-by: Andrew Morton <akpm at osdl.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>

 drivers/mtd/maps/physmap.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index bc82f70..433c3ca 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -89,9 +89,9 @@ static int physmap_flash_probe(struct pl
 	if (physmap_data == NULL)
 		return -ENODEV;
 
-       	printk(KERN_NOTICE "physmap platform flash device: %.8lx at %.8lx\n",
-		dev->resource->end - dev->resource->start + 1,
-		dev->resource->start);
+       	printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
+	    (unsigned long long)dev->resource->end - dev->resource->start + 1,
+	    (unsigned long long)dev->resource->start);
 
 	info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
 	if (info == NULL) {


From linux-mtd at lists.infradead.org  Fri Jun  9 19:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Sat, 10 Jun 2006 00:59:02 +0100
Subject: [MTD NAND] Fix s3c2410 NAND driver so it at least _looks_ like it
	compiles
Message-ID: <E1FoqsY-0008Ev-4u@pentafluge.infradead.org>

Commit:     f9068876f5ef583f8e9ebf4acd2ef5b35b113db9
Parent:     f24ff6bf8c903bc0c645bf87fbe87f9a6d9f634f
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sat Jun 10 00:53:16 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sat Jun 10 00:53:16 2006 +0100

    [MTD NAND] Fix s3c2410 NAND driver so it at least _looks_ like it compiles
    
    Fix the control bit handling so it even looks like it might work, too.
    Bad tglx. No biscuit.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>

 drivers/mtd/nand/s3c2410.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 8429793..d6365a6 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -256,7 +256,7 @@ static void s3c2410_nand_select_chip(str
 */
 
 static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigend int ctrl)
+				   unsigned int ctrl)
 {
 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 	struct nand_chip *chip = mtd->priv;
@@ -264,7 +264,7 @@ static void s3c2410_nand_hwcontrol(struc
 	if (cmd == NAND_CMD_NONE)
 		return;
 
-	if (cmd & NAND_CLE)
+	if (ctrl & NAND_CLE)
 		writeb(cmd, info->regs + S3C2410_NFCMD);
 	else
 		writeb(cmd, info->regs + S3C2410_NFADDR);
@@ -272,8 +272,8 @@ static void s3c2410_nand_hwcontrol(struc
 
 /* command and control functions */
 
-static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
-				   unsigend int ctrl)
+static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
 {
 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
 	struct nand_chip *chip = mtd->priv;
@@ -281,7 +281,7 @@ static void s3c2410_nand_hwcontrol(struc
 	if (cmd == NAND_CMD_NONE)
 		return;
 
-	if (cmd & NAND_CLE)
+	if (ctrl & NAND_CLE)
 		writeb(cmd, info->regs + S3C2440_NFCMD);
 	else
 		writeb(cmd, info->regs + S3C2440_NFADDR);


From linux-mtd at lists.infradead.org  Wed Jun 14 12:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Wed, 14 Jun 2006 17:59:01 +0100
Subject: [MTD] assume mtd->writesize is 1 for NOR flashes
Message-ID: <E1FqYhp-0004u6-Po@pentafluge.infradead.org>

Commit:     783ed81ff39d3f938a6b2efd09fbad96e41e5c1f
Parent:     f9068876f5ef583f8e9ebf4acd2ef5b35b113db9
Author:     Artem B. Bityutskiy <dedekind at sauron.oktetlabs.ru>
AuthorDate: Wed Jun 14 19:53:44 2006 +0400
Commit:     Artem B. Bityutskiy <dedekind at sauron.oktetlabs.ru>
CommitDate: Wed Jun 14 19:53:44 2006 +0400

    [MTD] assume mtd->writesize is 1 for NOR flashes
    
    Signed-off-by: Artem B. Bityitskiy

 drivers/mtd/chips/amd_flash.c       |    1 +
 drivers/mtd/chips/cfi_cmdset_0002.c |    1 +
 drivers/mtd/chips/sharp.c           |    1 +
 drivers/mtd/devices/lart.c          |    1 +
 drivers/mtd/devices/m25p80.c        |    1 +
 drivers/mtd/devices/mtdram.c        |    1 +
 drivers/mtd/mtdcore.c               |    1 +
 include/linux/mtd/mtd.h             |    9 ++++++---
 8 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 9e46650..16eaca6 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -730,6 +730,7 @@ static struct mtd_info *amd_flash_probe(
 		offset += dev_size;
 	}
 	mtd->type = MTD_NORFLASH;
+	mtd->writesize = 1;
 	mtd->flags = MTD_CAP_NORFLASH;
 	mtd->name = map->name;
 	mtd->erase = amd_flash_erase;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 3aeb0c7..1e01ad3 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -236,6 +236,7 @@ struct mtd_info *cfi_cmdset_0002(struct 
 	mtd->resume  = cfi_amdstd_resume;
 	mtd->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
+	mtd->writesize = 1;
 
 	if (cfi->cfi_mode==CFI_MODE_CFI){
 		unsigned char bootloc;
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 3cc0b23..967abbe 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -140,6 +140,7 @@ static struct mtd_info *sharp_probe(stru
 	mtd->suspend = sharp_suspend;
 	mtd->resume = sharp_resume;
 	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->writesize = 1;
 	mtd->name = map->name;
 
 	memset(sharp, 0, sizeof(*sharp));
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 29b0dda..4ea50a1 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -635,6 +635,7 @@ int __init lart_flash_init (void)
    printk ("%s: This looks like a LART board to me.\n",module_name);
    mtd.name = module_name;
    mtd.type = MTD_NORFLASH;
+   mtd.writesize = 1;
    mtd.flags = MTD_CAP_NORFLASH;
    mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN;
    mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 04e65d5..a846614 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -465,6 +465,7 @@ static int __devinit m25p_probe(struct s
 		flash->mtd.name = spi->dev.bus_id;
 
 	flash->mtd.type = MTD_NORFLASH;
+	flash->mtd.writesize = 1;
 	flash->mtd.flags = MTD_CAP_NORFLASH;
 	flash->mtd.size = info->sector_size * info->n_sectors;
 	flash->mtd.erasesize = info->sector_size;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index f284c96..8ab4b93 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -106,6 +106,7 @@ int mtdram_init_device(struct mtd_info *
 	mtd->type = MTD_GENERIC_TYPE;
 	mtd->flags = MTD_CAP_RAM;
 	mtd->size = size;
+	mtd->writesize = 1;
 	mtd->erasesize = MTDRAM_ERASE_SIZE;
 	mtd->priv = mapped_address;
 
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 49bc9fd..16a952d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -47,6 +47,7 @@ int add_mtd_device(struct mtd_info *mtd)
 {
 	int i;
 
+	BUG_ON(mtd->writesize == 0);
 	mutex_lock(&mtd_table_mutex);
 
 	for (i=0; i < MAX_MTD_DEVICES; i++)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9536567..e1d2a3d 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -110,9 +110,12 @@ struct mtd_info {
 	 * information below if they desire
 	 */
 	u_int32_t erasesize;
-	/* Smallest availlable size for writing to the device.  For NAND,
-	 * this is the page size, for some NOR chips, the size of ECC
-	 * covered blocks.
+	/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
+	 * though individual bits can be cleared), in case of NAND flash it is
+	 * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
+	 * it is of ECC block size, etc. It is illegal to have writesize = 0.
+	 * Any driver registering a struct mtd_info must ensure a writesize of
+	 * 1 or larger.
 	 */
 	u_int32_t writesize;
 


From linux-mtd at lists.infradead.org  Wed Jun 14 16:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Wed, 14 Jun 2006 21:59:02 +0100
Subject: [MTD] Restore MTD_ROM and MTD_RAM types
Message-ID: <E1FqcS5-0004mj-VR@pentafluge.infradead.org>

Commit:     21c8db9eff95260e543535dfc6f27164c4c0c0ff
Parent:     783ed81ff39d3f938a6b2efd09fbad96e41e5c1f
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Wed Jun 14 21:39:48 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Wed Jun 14 21:39:48 2006 +0100

    [MTD] Restore MTD_ROM and MTD_RAM types
    
    Let's not attempt the abolition of mtd->type until/unless it's properly
    thought through. And certainly, let's not do it by halves.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>

 drivers/mtd/chips/map_ram.c     |    2 +-
 drivers/mtd/chips/map_rom.c     |    2 +-
 drivers/mtd/devices/block2mtd.c |    2 +-
 drivers/mtd/devices/ms02-nv.c   |    2 +-
 drivers/mtd/devices/mtdram.c    |    2 +-
 drivers/mtd/devices/phram.c     |    2 +-
 drivers/mtd/devices/pmc551.c    |    2 +-
 drivers/mtd/devices/slram.c     |    2 +-
 include/mtd/mtd-abi.h           |    3 ++-
 9 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 9b7c499..7639257 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -64,7 +64,7 @@ #endif
 	map->fldrv = &mapram_chipdrv;
 	mtd->priv = map;
 	mtd->name = map->name;
-	mtd->type = MTD_GENERIC_TYPE;
+	mtd->type = MTD_RAM;
 	mtd->size = map->size;
 	mtd->erase = mapram_erase;
 	mtd->read = mapram_read;
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index d59ac01..bc6ee9e 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -40,7 +40,7 @@ static struct mtd_info *map_rom_probe(st
 	map->fldrv = &maprom_chipdrv;
 	mtd->priv = map;
 	mtd->name = map->name;
-	mtd->type = MTD_GENERIC_TYPE;
+	mtd->type = MTD_ROM;
 	mtd->size = map->size;
 	mtd->read = maprom_read;
 	mtd->write = maprom_write;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 1157182..0d98c22 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -324,7 +324,7 @@ static struct block2mtd_dev *add_device(
 
 	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
 	dev->mtd.erasesize = erase_size;
-	dev->mtd.type = MTD_GENERIC_TYPE;
+	dev->mtd.type = MTD_RAM;
 	dev->mtd.flags = MTD_CAP_RAM;
 	dev->mtd.erase = block2mtd_erase;
 	dev->mtd.write = block2mtd_write;
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index a6466f9..4ab7670 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -218,7 +218,7 @@ static int __init ms02nv_init_one(ulong 
 	fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1);
 	mp->uaddr = phys_to_virt(fixaddr);
 
-	mtd->type = MTD_GENERIC_TYPE;
+	mtd->type = MTD_RAM;
 	mtd->flags = MTD_CAP_RAM;
 	mtd->size = fixsize;
 	mtd->name = (char *)ms02nv_name;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index 8ab4b93..b4438ea 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -103,7 +103,7 @@ int mtdram_init_device(struct mtd_info *
 
 	/* Setup the MTD structure */
 	mtd->name = name;
-	mtd->type = MTD_GENERIC_TYPE;
+	mtd->type = MTD_RAM;
 	mtd->flags = MTD_CAP_RAM;
 	mtd->size = size;
 	mtd->writesize = 1;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index e6daa74..e09e416 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -149,7 +149,7 @@ static int register_device(char *name, u
 	new->mtd.read = phram_read;
 	new->mtd.write = phram_write;
 	new->mtd.owner = THIS_MODULE;
-	new->mtd.type = MTD_GENERIC_TYPE;
+	new->mtd.type = MTD_RAM;
 	new->mtd.erasesize = PAGE_SIZE;
 
 	ret = -EAGAIN;
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index aa9f6c9..666cce1 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -775,7 +775,7 @@ #endif
                 mtd->write 	= pmc551_write;
                 mtd->point 	= pmc551_point;
                 mtd->unpoint 	= pmc551_unpoint;
-                mtd->type	= MTD_GENERIC_TYPE;
+                mtd->type 	= MTD_RAM;
                 mtd->name 	= "PMC551 RAM board";
                 mtd->erasesize 	= 0x10000;
 		mtd->owner = THIS_MODULE;
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index fdb7a78..b3f665e 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -207,7 +207,7 @@ static int register_device(char *name, u
 	(*curmtd)->mtdinfo->read = slram_read;
 	(*curmtd)->mtdinfo->write = slram_write;
 	(*curmtd)->mtdinfo->owner = THIS_MODULE;
-	(*curmtd)->mtdinfo->type = MTD_GENERIC_TYPE;
+	(*curmtd)->mtdinfo->type = MTD_RAM;
 	(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
 
 	if (add_mtd_device((*curmtd)->mtdinfo))	{
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 7ccadb1..ee2afba 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -24,10 +24,11 @@ struct mtd_oob_buf {
 };
 
 #define MTD_ABSENT		0
+#define MTD_RAM			1
+#define MTD_ROM			2
 #define MTD_NORFLASH		3
 #define MTD_NANDFLASH		4
 #define MTD_DATAFLASH		6
-#define MTD_GENERIC_TYPE	7
 
 #define MTD_WRITEABLE		0x400	/* Device is writeable */
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */


From linux-mtd at lists.infradead.org  Sat Jun 17 19:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Sun, 18 Jun 2006 00:59:02 +0100
Subject: diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
Message-ID: <E1Frkgv-0005JU-T7@pentafluge.infradead.org>

Commit:     3877f0b6c9f54d43e55e532404a935b90393b635
Parent:     21c8db9eff95260e543535dfc6f27164c4c0c0ff
commit 3877f0b6c9f54d43e55e532404a935b90393b635
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sun Jun 18 00:05:26 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sun Jun 18 00:05:26 2006 +0100

    [JFFS2] Don't trust node headers before the CRC is checked.
    
    Especially when summary code is used, we can have in-memory data
    structures referencing certain nodes without them actually being readable
    on the flash. Discard the nodes gracefully in that case, rather than
    triggering a BUG().
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/readinode.c |   62 +++++++++++++++++++++++++++-----------------------
 1 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index e1acce8..5351b34 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -343,7 +343,7 @@ free_out:
  * Helper function for jffs2_get_inode_nodes().
  * It is called every time an unknown node is found.
  *
- * Returns: 0 on succes;
+ * Returns: 0 on success;
  * 	    1 if the node should be marked obsolete;
  * 	    negative error code on failure.
  */
@@ -354,37 +354,30 @@ static inline int read_unknown(struct jf
 
 	un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
 
-	if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) {
-		/* Hmmm. This should have been caught at scan time. */
-		JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref));
-		jffs2_dbg_dump_node(c, ref_offset(ref));
-		return 1;
-	} else {
-		switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
+	switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
 
-		case JFFS2_FEATURE_INCOMPAT:
-			JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n",
-				je16_to_cpu(un->nodetype), ref_offset(ref));
-			/* EEP */
-			BUG();
-			break;
+	case JFFS2_FEATURE_INCOMPAT:
+		JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n",
+			    je16_to_cpu(un->nodetype), ref_offset(ref));
+		/* EEP */
+		BUG();
+		break;
 
-		case JFFS2_FEATURE_ROCOMPAT:
-			JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n",
-					je16_to_cpu(un->nodetype), ref_offset(ref));
-			BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
-			break;
+	case JFFS2_FEATURE_ROCOMPAT:
+		JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n",
+			    je16_to_cpu(un->nodetype), ref_offset(ref));
+		BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
+		break;
 
-		case JFFS2_FEATURE_RWCOMPAT_COPY:
-			JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
-					je16_to_cpu(un->nodetype), ref_offset(ref));
-			break;
+	case JFFS2_FEATURE_RWCOMPAT_COPY:
+		JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
+			     je16_to_cpu(un->nodetype), ref_offset(ref));
+		break;
 
-		case JFFS2_FEATURE_RWCOMPAT_DELETE:
-			JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
-					je16_to_cpu(un->nodetype), ref_offset(ref));
-			return 1;
-		}
+	case JFFS2_FEATURE_RWCOMPAT_DELETE:
+		JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
+			     je16_to_cpu(un->nodetype), ref_offset(ref));
+		return 1;
 	}
 
 	return 0;
@@ -549,6 +542,18 @@ static int jffs2_get_inode_nodes(struct 
 
 		node = (union jffs2_node_union *)bufstart;
 
+		/* No need to mask in the valid bit; it shouldn't be invalid */
+		if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) {
+			JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n",
+				     ref_offset(ref), je16_to_cpu(node->u.magic),
+				     je16_to_cpu(node->u.nodetype),
+				     je32_to_cpu(node->u.totlen),
+				     je32_to_cpu(node->u.hdr_crc));
+			jffs2_dbg_dump_node(c, ref_offset(ref));
+			jffs2_mark_node_obsolete(c, ref);
+			goto cont;
+		}
+
 		switch (je16_to_cpu(node->u.nodetype)) {
 
 		case JFFS2_NODETYPE_DIRENT:
@@ -606,6 +611,7 @@ static int jffs2_get_inode_nodes(struct 
 				goto free_out;
 
 		}
+	cont:
 		spin_lock(&c->erase_completion_lock);
 	}
 


From linux-mtd at lists.infradead.org  Sun Jun 18 05:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Sun, 18 Jun 2006 10:59:01 +0100
Subject: [JFFS2] Mark XATTR support as experimental, for now
Message-ID: <E1Fru3Z-0001Dh-RZ@pentafluge.infradead.org>

Commit:     2ba72cb754bb091bb24a44e9682f7105110f7f38
Parent:     3877f0b6c9f54d43e55e532404a935b90393b635
commit 2ba72cb754bb091bb24a44e9682f7105110f7f38
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sun Jun 18 10:22:40 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sun Jun 18 10:22:40 2006 +0100

    [JFFS2] Mark XATTR support as experimental, for now
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/Kconfig |   56 ++++++++++++++++++++++++++++----------------------------
 1 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index 2496ccb..572cc43 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1075,9 +1075,35 @@ config JFFS2_FS_DEBUG
 	  If reporting bugs, please try to have available a full dump of the
 	  messages at debug level 1 while the misbehaviour was occurring.
 
-config JFFS2_FS_XATTR
-	bool "JFFS2 XATTR support"
+config JFFS2_FS_WRITEBUFFER
+	bool "JFFS2 write-buffering support"
 	depends on JFFS2_FS
+	default y
+	help
+	  This enables the write-buffering support in JFFS2.
+
+	  This functionality is required to support JFFS2 on the following
+	  types of flash devices:
+	    - NAND flash
+	    - NOR flash with transparent ECC
+	    - DataFlash
+
+config JFFS2_SUMMARY
+	bool "JFFS2 summary support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL
+	default n
+	help
+	  This feature makes it possible to use summary information
+	  for faster filesystem mount.
+
+	  The summary information can be inserted into a filesystem image
+	  by the utility 'sumtool'.
+
+	  If unsure, say 'N'.
+
+config JFFS2_FS_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL && !JFFS2_FS_WRITEBUFFER
 	default n
 	help
 	  Extended attributes are name:value pairs associated with inodes by
@@ -1113,32 +1139,6 @@ config JFFS2_FS_SECURITY
 	  If you are not using a security module that requires using
 	  extended attributes for file security labels, say N.
 
-config JFFS2_FS_WRITEBUFFER
-	bool "JFFS2 write-buffering support"
-	depends on JFFS2_FS
-	default y
-	help
-	  This enables the write-buffering support in JFFS2.
-
-	  This functionality is required to support JFFS2 on the following
-	  types of flash devices:
-	    - NAND flash
-	    - NOR flash with transparent ECC
-	    - DataFlash
-
-config JFFS2_SUMMARY
-	bool "JFFS2 summary support (EXPERIMENTAL)"
-	depends on JFFS2_FS && EXPERIMENTAL
-	default n
-	help
-	  This feature makes it possible to use summary information
-	  for faster filesystem mount.
-
-	  The summary information can be inserted into a filesystem image
-	  by the utility 'sumtool'.
-
-	  If unsure, say 'N'.
-
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	depends on JFFS2_FS


From linux-mtd at lists.infradead.org  Sun Jun 18 13:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Sun, 18 Jun 2006 18:59:01 +0100
Subject: [JFFS2] When retiring nextblock,
	allocate a node_ref for the wasted space
Message-ID: <E1Fs1Y5-0000IU-A0@pentafluge.infradead.org>

Commit:     fc6612f627c697b348a4ef64f16fb373d86dbd76
Parent:     2ba72cb754bb091bb24a44e9682f7105110f7f38
commit fc6612f627c697b348a4ef64f16fb373d86dbd76
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sun Jun 18 18:35:10 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sun Jun 18 18:39:38 2006 +0100

    [JFFS2] When retiring nextblock, allocate a node_ref for the wasted space
    
    Failing to do so makes the calculated length of the last node incorrect,
    when we're not using eraseblock summaries.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/nodemgmt.c |   26 ++++++++++++++++++++++----
 1 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 71d1630..8bedfd2 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -317,6 +317,8 @@ static int jffs2_do_reserve_space(struct
 		}
 	} else {
 		if (jeb && minsize > jeb->free_size) {
+			uint32_t waste;
+
 			/* Skip the end of this block and file it as having some dirty space */
 			/* If there's a pending write to it, flush now */
 
@@ -329,10 +331,26 @@ static int jffs2_do_reserve_space(struct
 				goto restart;
 			}
 
-			c->wasted_size += jeb->free_size;
-			c->free_size -= jeb->free_size;
-			jeb->wasted_size += jeb->free_size;
-			jeb->free_size = 0;
+			spin_unlock(&c->erase_completion_lock);
+
+			ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
+			if (ret)
+				return ret;
+			/* Just lock it again and continue. Nothing much can change because
+			   we hold c->alloc_sem anyway. In fact, it's not entirely clear why
+			   we hold c->erase_completion_lock in the majority of this function...
+			   but that's a question for another (more caffeine-rich) day. */
+			spin_lock(&c->erase_completion_lock);
+
+			waste = jeb->free_size;
+			jffs2_link_node_ref(c, jeb,
+					    (jeb->offset + c->sector_size - waste) | REF_OBSOLETE,
+					    waste, NULL);
+			/* FIXME: that made it count as dirty. Convert to wasted */
+			jeb->dirty_size -= waste;
+			c->dirty_size -= waste;
+			jeb->wasted_size += waste;
+			c->wasted_size += waste;
 
 			jffs2_close_nextblock(c, jeb);
 			jeb = NULL;


From linux-mtd at lists.infradead.org  Mon Jun 19 04:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Mon, 19 Jun 2006 09:59:01 +0100
Subject: [JFFS2] Check CRC32 on dirent and data nodes each time they're read
Message-ID: <E1FsFb3-0004Nl-No@pentafluge.infradead.org>

Commit:     1046d88001e7b8819f60dece2eaf1b44bf4b4460
Parent:     fc6612f627c697b348a4ef64f16fb373d86dbd76
commit 1046d88001e7b8819f60dece2eaf1b44bf4b4460
Author:     David Woodhouse <dwmw2 at infradead.org>
AuthorDate: Sun Jun 18 22:44:21 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Sun Jun 18 22:44:21 2006 +0100

    [JFFS2] Check CRC32 on dirent and data nodes each time they're read
    
    Also, make sure dirents are marked REF_UNCHECKED when we 'discover' them
    through eraseblock summary.
    
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/readinode.c |   51 ++++++++++++++++++++++++++++++++++++--------------
 fs/jffs2/summary.c   |    2 +-
 2 files changed, 38 insertions(+), 15 deletions(-)

diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 5351b34..5ea4faa 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -116,19 +116,42 @@ static inline int read_direntry(struct j
 				uint32_t *latest_mctime, uint32_t *mctime_ver)
 {
 	struct jffs2_full_dirent *fd;
+	uint32_t crc;
 
-	/* The direntry nodes are checked during the flash scanning */
-	BUG_ON(ref_flags(ref) == REF_UNCHECKED);
 	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
 	BUG_ON(ref_obsolete(ref));
 
-	/* Sanity check */
-	if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
-		JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
-		       ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
+	crc = crc32(0, rd, sizeof(*rd) - 8);
+	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
+		JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n",
+			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
 		return 1;
 	}
 
+	/* If we've never checked the CRCs on this node, check them now */
+	if (ref_flags(ref) == REF_UNCHECKED) {
+		struct jffs2_eraseblock *jeb;
+		int len;
+
+		/* Sanity check */
+		if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
+			JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
+				    ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
+			return 1;
+		}
+
+		jeb = &c->blocks[ref->flash_offset / c->sector_size];
+		len = ref_totlen(c, jeb, ref);
+
+		spin_lock(&c->erase_completion_lock);
+		jeb->used_size += len;
+		jeb->unchecked_size -= len;
+		c->used_size += len;
+		c->unchecked_size -= len;
+		ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
+		spin_unlock(&c->erase_completion_lock);
+	}
+
 	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
 	if (unlikely(!fd))
 		return -ENOMEM;
@@ -198,10 +221,18 @@ static inline int read_dnode(struct jffs
 	struct jffs2_tmp_dnode_info *tn;
 	uint32_t len, csize;
 	int ret = 1;
+	uint32_t crc;
 
 	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
 	BUG_ON(ref_obsolete(ref));
 
+	crc = crc32(0, rd, sizeof(*rd) - 8);
+	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
+		JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n",
+			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
+		return 1;
+	}
+
 	tn = jffs2_alloc_tmp_dnode_info();
 	if (!tn) {
 		JFFS2_ERROR("failed to allocate tn (%zu bytes).\n", sizeof(*tn));
@@ -213,14 +244,6 @@ static inline int read_dnode(struct jffs
 
 	/* If we've never checked the CRCs on this node, check them now */
 	if (ref_flags(ref) == REF_UNCHECKED) {
-		uint32_t crc;
-
-		crc = crc32(0, rd, sizeof(*rd) - 8);
-		if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
-			JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
-					ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
-			goto free_out;
-		}
 
 		/* Sanity checks */
 		if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 51bf165..0b02fc7 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -453,7 +453,7 @@ static int jffs2_sum_process_sum_data(st
 					return -ENOMEM;
 				}
 
-				fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_PRISTINE,
+				fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_UNCHECKED,
 							    PAD(je32_to_cpu(spd->totlen)), ic);
 
 				fd->next = NULL;


From linux-mtd at lists.infradead.org  Mon Jun 19 04:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Mon, 19 Jun 2006 09:59:02 +0100
Subject: [MTD NAND] s3c24x0 board: Fix clock handling,
	ensure proper initialisation.
Message-ID: <E1FsFb3-0004O5-TI@pentafluge.infradead.org>

Commit:     d1fef3c5e16327661be6cb127d68f5be379697a5
Parent:     1046d88001e7b8819f60dece2eaf1b44bf4b4460
commit d1fef3c5e16327661be6cb127d68f5be379697a5
Author:     Ben Dooks <ben-linux at fluff.org>
AuthorDate: Mon Jun 19 09:29:38 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Mon Jun 19 09:29:38 2006 +0100

    [MTD NAND] s3c24x0 board: Fix clock handling, ensure proper initialisation.
    
    Signed-off-by: Ben Dooks <ben-linux at fluff.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/Kconfig   |   10 ++++++
 drivers/mtd/nand/s3c2410.c |   76 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 203f90a..3db77ee 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -135,6 +135,16 @@ config MTD_NAND_NDFC
 	help
 	 NDFC Nand Flash Controllers are integrated in EP44x SoCs
 
+config MTD_NAND_S3C2410_CLKSTOP
+	bool "S3C2410 NAND IDLE clock stop"
+	depends on MTD_NAND_S3C2410
+	default n
+	help
+	  Stop the clock to the NAND controller when there is no chip
+	  selected to save power. This will mean there is a small delay
+	  when the is NAND chip selected or released, but will save
+	  approximately 5mA of power when there is nothing happening.
+
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
 	depends on MTD_NAND && EXPERIMENTAL
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d6365a6..fd78fb8 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -18,8 +18,9 @@
  *	20-Jun-2005  BJD  Updated s3c2440 support, fixed timing bug
  *	08-Jul-2005  BJD  Fix OOPS when no platform data supplied
  *	20-Oct-2005  BJD  Fix timing calculation bug
+ *	14-Jan-2006  BJD  Allow clock to be stopped when idle
  *
- * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $
+ * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,9 +37,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#include <config/mtd/nand/s3c2410/hwecc.h>
-#include <config/mtd/nand/s3c2410/debug.h>
-
 #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
 #define DEBUG
 #endif
@@ -73,6 +71,13 @@ #else
 static int hardware_ecc = 0;
 #endif
 
+#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
+static int clock_stop = 1;
+#else
+static const int clock_stop = 0;
+#endif
+
+
 /* new oob placement block for use with hardware ecc generation
  */
 
@@ -134,6 +139,11 @@ static struct s3c2410_platform_nand *to_
 	return dev->dev.platform_data;
 }
 
+static inline int allow_clk_stop(struct s3c2410_nand_info *info)
+{
+	return clock_stop;
+}
+
 /* timing calculations */
 
 #define NS_IN_KHZ 1000000
@@ -201,6 +211,11 @@ static int s3c2410_nand_inithw(struct s3
 		cfg = S3C2440_NFCONF_TACLS(tacls - 1);
 		cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
 		cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
+
+		/* enable the controller and de-assert nFCE */
+
+		writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
+		       info->regs + S3C2440_NFCONT);
 	}
 
 	pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
@@ -226,6 +241,9 @@ static void s3c2410_nand_select_chip(str
 	bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
 	reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
 
+	if (chip != -1 && allow_clk_stop(info))
+		clk_enable(info->clk);
+
 	cur = readl(reg);
 
 	if (chip == -1) {
@@ -245,6 +263,9 @@ static void s3c2410_nand_select_chip(str
 	}
 
 	writel(cur, reg);
+
+	if (chip == -1 && allow_clk_stop(info))
+		clk_disable(info->clk);
 }
 
 /* command and control functions
@@ -417,7 +438,8 @@ static int s3c2410_nand_remove(struct pl
 	/* free the common resources */
 
 	if (info->clk != NULL && !IS_ERR(info->clk)) {
-		clk_disable(info->clk);
+		if (!allow_clk_stop(info))
+			clk_disable(info->clk);
 		clk_put(info->clk);
 	}
 
@@ -627,6 +649,11 @@ static int s3c24xx_nand_probe(struct pla
 			sets++;
 	}
 
+	if (allow_clk_stop(info)) {
+		dev_info(&pdev->dev, "clock idle support enabled\n");
+		clk_disable(info->clk);
+	}
+
 	pr_debug("initialised ok\n");
 	return 0;
 
@@ -638,6 +665,41 @@ static int s3c24xx_nand_probe(struct pla
 	return err;
 }
 
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+
+	if (info) {
+		if (!allow_clk_stop(info))
+			clk_disable(info->clk);
+	}
+
+	return 0;
+}
+
+static int s3c24xx_nand_resume(struct platform_device *dev)
+{
+	struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+
+	if (info) {
+		clk_enable(info->clk);
+		s3c2410_nand_inithw(info, dev);
+
+		if (allow_clk_stop(info))
+			clk_disable(info->clk);
+	}
+
+	return 0;
+}
+
+#else
+#define s3c24xx_nand_suspend NULL
+#define s3c24xx_nand_resume NULL
+#endif
+
 /* driver device registration */
 
 static int s3c2410_nand_probe(struct platform_device *dev)
@@ -653,6 +715,8 @@ static int s3c2440_nand_probe(struct pla
 static struct platform_driver s3c2410_nand_driver = {
 	.probe		= s3c2410_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
 	.driver		= {
 		.name	= "s3c2410-nand",
 		.owner	= THIS_MODULE,
@@ -662,6 +726,8 @@ static struct platform_driver s3c2410_na
 static struct platform_driver s3c2440_nand_driver = {
 	.probe		= s3c2440_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
 	.driver		= {
 		.name	= "s3c2440-nand",
 		.owner	= THIS_MODULE,


From linux-mtd at lists.infradead.org  Mon Jun 19 04:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Mon, 19 Jun 2006 09:59:02 +0100
Subject: [MTD NAND] S3C2410 driver cleanup
Message-ID: <E1FsFb4-0004OO-5R@pentafluge.infradead.org>

Commit:     ad3b5fb772e6a824f1ac341eb8e392eca6fc524f
Parent:     d1fef3c5e16327661be6cb127d68f5be379697a5
commit ad3b5fb772e6a824f1ac341eb8e392eca6fc524f
Author:     Ben Dooks <ben-linux at fluff.org>
AuthorDate: Mon Jun 19 09:43:23 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Mon Jun 19 09:43:23 2006 +0100

    [MTD NAND] S3C2410 driver cleanup
    
    Fix unused variables and commenting since tglx's
    new NAND updates
    
    Signed-off-by: Ben Dooks <ben-linux at fluff.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/s3c2410.c |   11 +++--------
 1 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index fd78fb8..2c262fe 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -268,20 +268,16 @@ static void s3c2410_nand_select_chip(str
 		clk_disable(info->clk);
 }
 
-/* command and control functions
- *
- * Note, these all use tglx's method of changing the IO_ADDR_W field
- * to make the code simpler, and use the nand layer's code to issue the
- * command and address sequences via the proper IO ports.
+/* s3c2410_nand_hwcontrol
  *
+ * Issue command and address cycles to the chip
 */
 
 static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
 				   unsigned int ctrl)
 {
 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	struct nand_chip *chip = mtd->priv;
-
+	
 	if (cmd == NAND_CMD_NONE)
 		return;
 
@@ -297,7 +293,6 @@ static void s3c2440_nand_hwcontrol(struc
 				   unsigned int ctrl)
 {
 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-	struct nand_chip *chip = mtd->priv;
 
 	if (cmd == NAND_CMD_NONE)
 		return;


From linux-mtd at lists.infradead.org  Tue Jun 20 15:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 20 Jun 2006 20:59:02 +0100
Subject: [MTD] NAND Fixup NDFC merge brokeness
Message-ID: <E1FsmNK-0001Fk-2j@pentafluge.infradead.org>

Commit:     b6d5ee00e397b20dc88f7ffaa6f7651b71996a5c
Parent:     ad3b5fb772e6a824f1ac341eb8e392eca6fc524f
commit b6d5ee00e397b20dc88f7ffaa6f7651b71996a5c
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Fri Jun 16 18:10:09 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 20 20:31:23 2006 +0100

    [MTD] NAND Fixup NDFC merge brokeness
    
    Remove the remains of a broken merge.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/ndfc.c |   13 ++++---------
 1 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 551702d..fe8d385 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -203,16 +203,11 @@ static int ndfc_chip_probe(struct platfo
 #ifdef CONFIG_MTD_PARTITIONS
 	printk("Number of partitions %d\n", nc->nr_partitions);
 	if (nc->nr_partitions) {
-		struct mtd_info *mtd_ubi;
-		nc->partitions[NAND_PARTS_CONTENT_IDX].mtdp = &mtd_ubi;
-
-		add_mtd_device(&nandmtd->mtd); /* for testing */
-		add_mtd_partitions(&nandmtd->mtd,
-				   nc->partitions,
+		/* Add the full device, so complete dumps can be made */
+		add_mtd_device(&nandmtd->mtd);
+		add_mtd_partitions(&nandmtd->mtd, nc->partitions,
 				   nc->nr_partitions);
 
-		add_mtd_device(mtd_ubi);
-
 	} else
 #else
 		add_mtd_device(&nandmtd->mtd);
@@ -233,7 +228,7 @@ static int ndfc_nand_probe(struct platfo
 	struct ndfc_controller_settings *settings = nc->priv;
 	struct resource *res = pdev->resource;
 	struct ndfc_controller *ndfc = &ndfc_ctrl;
-	unsigned long long phys = setting->erpn | res->start;
+	unsigned long long phys = settings->ndfc_erpn | res->start;
 
 	ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
 	if (!ndfc->ndfcbase) {


From linux-mtd at lists.infradead.org  Tue Jun 20 15:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 20 Jun 2006 20:59:02 +0100
Subject: [MTD] NAND: Fix breakage all over the place
Message-ID: <E1FsmNK-0001GM-Hn@pentafluge.infradead.org>

Commit:     7bc3312bef4d6f220812500c0de7868fb7625a41
Parent:     7e4178f90eec862affc97469118d5008bd1b5bda
commit 7bc3312bef4d6f220812500c0de7868fb7625a41
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Tue Jun 20 20:05:05 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 20 20:31:24 2006 +0100

    [MTD] NAND: Fix breakage all over the place
    
    Following problems are addressed:
    
    - wrong status caused early break out of nand_wait()
    - removed the bogus status check in nand_wait() which
      is a relict of the abandoned support for interrupted
      erase.
    - status check moved to the correct place in read_oob
    - oob support for syndrom based ecc with strange layouts
    - use given offset in the AUTOOOB based oob operations
    
    Partially based on a patch from Vitaly Vool <vwool at ru.mvista.com>
    Thanks to Savin Zlobec <savin at epico.si> for tracking down the
    status problem.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/mtdchar.c         |    8 +
 drivers/mtd/nand/diskonchip.c |    2 
 drivers/mtd/nand/nand_base.c  |  297 ++++++++++++++++++++++++++++++-----------
 include/linux/mtd/nand.h      |   12 ++
 4 files changed, 231 insertions(+), 88 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 5dd0b8d..aa18d45 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -504,12 +504,12 @@ static int mtd_ioctl(struct inode *inode
 			return ret;
 
 		ops.len = buf.length;
-		ops.ooblen = mtd->oobsize;
+		ops.ooblen = buf.length;
 		ops.ooboffs = buf.start & (mtd->oobsize - 1);
 		ops.datbuf = NULL;
 		ops.mode = MTD_OOB_PLACE;
 
-		if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
+		if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
 			return -EINVAL;
 
 		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
@@ -553,12 +553,12 @@ static int mtd_ioctl(struct inode *inode
 			return ret;
 
 		ops.len = buf.length;
-		ops.ooblen = mtd->oobsize;
+		ops.ooblen = buf.length;
 		ops.ooboffs = buf.start & (mtd->oobsize - 1);
 		ops.datbuf = NULL;
 		ops.mode = MTD_OOB_PLACE;
 
-		if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
+		if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
 			return -EINVAL;
 
 		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 463e12c..6107f53 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -464,7 +464,7 @@ static void __init doc2000_count_chips(s
 	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
 }
 
-static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this)
 {
 	struct doc_priv *doc = this->priv;
 
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e74678e..27083ed 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -501,7 +501,6 @@ static void nand_command(struct mtd_info
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_STATUS:
-		chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
 		return;
 
 	case NAND_CMD_RESET:
@@ -595,6 +594,7 @@ static void nand_command_lp(struct mtd_i
 	case NAND_CMD_ERASE1:
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
+	case NAND_CMD_RNDIN:
 	case NAND_CMD_STATUS:
 	case NAND_CMD_DEPLETE1:
 		return;
@@ -621,6 +621,14 @@ static void nand_command_lp(struct mtd_i
 		while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
 		return;
 
+	case NAND_CMD_RNDOUT:
+		/* No ready / busy check necessary */
+		chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
+			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+		chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+			       NAND_NCE | NAND_CTRL_CHANGE);
+		return;
+
 	case NAND_CMD_READ0:
 		chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
 			       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
@@ -689,18 +697,17 @@ nand_get_device(struct nand_chip *chip, 
  * nand_wait - [DEFAULT]  wait until the command is done
  * @mtd:	MTD device structure
  * @this:	NAND chip structure
- * @state:	state to select the max. timeout value
  *
  * Wait for command done. This applies to erase and program only
  * Erase can take up to 400ms and program up to 20ms according to
  * general NAND and SmartMedia specs
  *
 */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state)
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 
 	unsigned long timeo = jiffies;
-	int status;
+	int status, state = chip->state;
 
 	if (state == FL_ERASING)
 		timeo += (HZ * 400) / 1000;
@@ -719,10 +726,6 @@ static int nand_wait(struct mtd_info *mt
 		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
 
 	while (time_before(jiffies, timeo)) {
-		/* Check, if we were interrupted */
-		if (chip->state != state)
-			return 0;
-
 		if (chip->dev_ready) {
 			if (chip->dev_ready(mtd))
 				break;
@@ -909,12 +912,25 @@ static uint8_t *nand_transfer_oob(struct
 
 	case MTD_OOB_AUTO: {
 		struct nand_oobfree *free = chip->ecc.layout->oobfree;
-		size_t bytes;
+		uint32_t boffs = 0, roffs = ops->ooboffs;
+		size_t bytes = 0;
 
 		for(; free->length && len; free++, len -= bytes) {
-			bytes = min_t(size_t, len, free->length);
-
-			memcpy(oob, chip->oob_poi + free->offset, bytes);
+			/* Read request not from offset 0 ? */
+			if (unlikely(roffs)) {
+				if (roffs >= free->length) {
+					roffs -= free->length;
+					continue;
+				}
+				boffs = free->offset + roffs;
+				bytes = min_t(size_t, len,
+					      (free->length - roffs));
+				roffs = 0;
+			} else {
+				bytes = min_t(size_t, len, free->length);
+				boffs = free->offset;
+			}
+			memcpy(oob, chip->oob_poi + boffs, bytes);
 			oob += bytes;
 		}
 		return oob;
@@ -1084,6 +1100,145 @@ static int nand_read(struct mtd_info *mt
 }
 
 /**
+ * nand_read_oob_std - [REPLACABLE] the most common OOB data read function
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @page:	page number to read
+ * @sndcmd:	flag whether to issue read command or not
+ */
+static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+			     int page, int sndcmd)
+{
+	if (sndcmd) {
+		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+		sndcmd = 0;
+	}
+	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+	return sndcmd;
+}
+
+/**
+ * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC
+ *			    with syndromes
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @page:	page number to read
+ * @sndcmd:	flag whether to issue read command or not
+ */
+static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+				  int page, int sndcmd)
+{
+	uint8_t *buf = chip->oob_poi;
+	int length = mtd->oobsize;
+	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+	int eccsize = chip->ecc.size;
+	uint8_t *bufpoi = buf;
+	int i, toread, sndrnd = 0, pos;
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
+	for (i = 0; i < chip->ecc.steps; i++) {
+		if (sndrnd) {
+			pos = eccsize + i * (eccsize + chunk);
+			if (mtd->writesize > 512)
+				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
+			else
+				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
+		} else
+			sndrnd = 1;
+		toread = min_t(int, length, chunk);
+		chip->read_buf(mtd, bufpoi, toread);
+		bufpoi += toread;
+		length -= toread;
+	}
+	if (length > 0)
+		chip->read_buf(mtd, bufpoi, length);
+
+	return 1;
+}
+
+/**
+ * nand_write_oob_std - [REPLACABLE] the most common OOB data write function
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @page:	page number to write
+ */
+static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+			      int page)
+{
+	int status = 0;
+	const uint8_t *buf = chip->oob_poi;
+	int length = mtd->oobsize;
+
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+	chip->write_buf(mtd, buf, length);
+	/* Send command to program the OOB data */
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	status = chip->waitfunc(mtd, chip);
+
+	return status;
+}
+
+/**
+ * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC
+ *			     with syndrome - only for large page flash !
+ * @mtd:	mtd info structure
+ * @chip:	nand chip info structure
+ * @page:	page number to write
+ */
+static int nand_write_oob_syndrome(struct mtd_info *mtd,
+				   struct nand_chip *chip, int page)
+{
+	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+	int eccsize = chip->ecc.size, length = mtd->oobsize;
+	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
+	const uint8_t *bufpoi = chip->oob_poi;
+
+	/*
+	 * data-ecc-data-ecc ... ecc-oob
+	 * or
+	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob
+	 */
+	if (!chip->ecc.prepad && !chip->ecc.postpad) {
+		pos = steps * (eccsize + chunk);
+		steps = 0;
+	} else
+		pos = eccsize + chunk;
+
+	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
+	for (i = 0; i < steps; i++) {
+		if (sndcmd) {
+			if (mtd->writesize <= 512) {
+				uint32_t fill = 0xFFFFFFFF;
+
+				len = eccsize;
+				while (len > 0) {
+					int num = min_t(int, len, 4);
+					chip->write_buf(mtd, (uint8_t *)&fill,
+							num);
+					len -= num;
+				}
+			} else {
+				pos = eccsize + i * (eccsize + chunk);
+				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
+			}
+		} else
+			sndcmd = 1;
+		len = min_t(int, length, chunk);
+		chip->write_buf(mtd, bufpoi, len);
+		bufpoi += len;
+		length -= len;
+	}
+	if (length > 0)
+		chip->write_buf(mtd, bufpoi, length);
+
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
+
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/**
  * nand_do_read_oob - [Intern] NAND read out-of-band
  * @mtd:	MTD device structure
  * @from:	offset to read from
@@ -1094,11 +1249,11 @@ static int nand_read(struct mtd_info *mt
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 			    struct mtd_oob_ops *ops)
 {
-	int col, page, realpage, chipnr, sndcmd = 1;
+	int page, realpage, chipnr, sndcmd = 1;
 	struct nand_chip *chip = mtd->priv;
 	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-	int direct, bytes, readlen = ops->len;
-	uint8_t *bufpoi, *buf = ops->oobbuf;
+	int readlen = ops->len;
+	uint8_t *buf = ops->oobbuf;
 
 	DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
 	      (unsigned long long)from, readlen);
@@ -1110,29 +1265,11 @@ static int nand_do_read_oob(struct mtd_i
 	realpage = (int)(from >> chip->page_shift);
 	page = realpage & chip->pagemask;
 
-	if (ops->mode != MTD_OOB_AUTO) {
-		col = ops->ooboffs;
-		direct = 1;
-	} else {
-		col = 0;
-		direct = 0;
-	}
+	chip->oob_poi = chip->buffers.oobrbuf;
 
 	while(1) {
-		bytes = direct ? ops->ooblen : mtd->oobsize;
-		bufpoi = direct ? buf : chip->buffers.oobrbuf;
-
-		if (likely(sndcmd)) {
-			chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page);
-			sndcmd = 0;
-		}
-
-		chip->read_buf(mtd, bufpoi, bytes);
-
-		if (unlikely(!direct))
-			buf = nand_transfer_oob(chip, buf, ops);
-		else
-			buf += ops->ooblen;
+		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
+		buf = nand_transfer_oob(chip, buf, ops);
 
 		readlen -= ops->ooblen;
 		if (!readlen)
@@ -1365,7 +1502,7 @@ static int nand_write_page(struct mtd_in
 	if (!cached || !(chip->options & NAND_CACHEPRG)) {
 
 		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-		status = chip->waitfunc(mtd, chip, FL_WRITING);
+		status = chip->waitfunc(mtd, chip);
 		/*
 		 * See if operation failed and additional status checks are
 		 * available
@@ -1378,7 +1515,7 @@ static int nand_write_page(struct mtd_in
 			return -EIO;
 	} else {
 		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-		status = chip->waitfunc(mtd, chip, FL_WRITING);
+		status = chip->waitfunc(mtd, chip);
 	}
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
@@ -1411,11 +1548,25 @@ static uint8_t *nand_fill_oob(struct nan
 
 	case MTD_OOB_AUTO: {
 		struct nand_oobfree *free = chip->ecc.layout->oobfree;
-		size_t bytes;
+		uint32_t boffs = 0, woffs = ops->ooboffs;
+		size_t bytes = 0;
 
 		for(; free->length && len; free++, len -= bytes) {
-			bytes = min_t(size_t, len, free->length);
-			memcpy(chip->oob_poi + free->offset, oob, bytes);
+			/* Write request not from offset 0 ? */
+			if (unlikely(woffs)) {
+				if (woffs >= free->length) {
+					woffs -= free->length;
+					continue;
+				}
+				boffs = free->offset + woffs;
+				bytes = min_t(size_t, len,
+					      (free->length - woffs));
+				woffs = 0;
+			} else {
+				bytes = min_t(size_t, len, free->length);
+				boffs = free->offset;
+			}
+			memcpy(chip->oob_poi + woffs, oob, bytes);
 			oob += bytes;
 		}
 		return oob;
@@ -1532,7 +1683,7 @@ static int nand_write(struct mtd_info *m
 	if (!len)
 		return 0;
 
-	nand_get_device(chip, mtd, FL_READING);
+	nand_get_device(chip, mtd, FL_WRITING);
 
 	chip->ops.len = len;
 	chip->ops.datbuf = (uint8_t *)buf;
@@ -1592,48 +1743,18 @@ static int nand_do_write_oob(struct mtd_
 	if (page == chip->pagebuf)
 		chip->pagebuf = -1;
 
-	if (ops->mode == MTD_OOB_AUTO || NAND_MUST_PAD(chip)) {
-		chip->oob_poi = chip->buffers.oobwbuf;
-		memset(chip->oob_poi, 0xff, mtd->oobsize);
-		nand_fill_oob(chip, ops->oobbuf, ops);
-		chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize,
-			      page & chip->pagemask);
-		chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-		memset(chip->oob_poi, 0xff, mtd->oobsize);
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_SEQIN,
-			      mtd->writesize + ops->ooboffs,
-			      page & chip->pagemask);
-		chip->write_buf(mtd, ops->oobbuf, ops->len);
-	}
-
-	/* Send command to program the OOB data */
-	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	chip->oob_poi = chip->buffers.oobwbuf;
+	memset(chip->oob_poi, 0xff, mtd->oobsize);
+	nand_fill_oob(chip, ops->oobbuf, ops);
+	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+	memset(chip->oob_poi, 0xff, mtd->oobsize);
 
-	status = chip->waitfunc(mtd, chip, FL_WRITING);
+	if (status)
+		return status;
 
-	/* See if device thinks it succeeded */
-	if (status & NAND_STATUS_FAIL) {
-		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
-		      "Failed write, page 0x%08x\n", page);
-		return -EIO;
-	}
 	ops->retlen = ops->len;
 
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-	if (ops->mode != MTD_OOB_AUTO) {
-		/* Send command to read back the data */
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, ops->ooboffs,
-			      page & chip->pagemask);
-
-		if (chip->verify_buf(mtd, ops->oobbuf, ops->len)) {
-			DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
-			      "Failed write verify, page 0x%08x\n", page);
-			return -EIO;
-		}
-	}
-#endif
-		return 0;
+	return 0;
 }
 
 /**
@@ -1659,7 +1780,7 @@ static int nand_write_oob(struct mtd_inf
 		return -EINVAL;
 	}
 
-	nand_get_device(chip, mtd, FL_READING);
+	nand_get_device(chip, mtd, FL_WRITING);
 
 	switch(ops->mode) {
 	case MTD_OOB_PLACE:
@@ -1833,7 +1954,7 @@ int nand_erase_nand(struct mtd_info *mtd
 
 		chip->erase_cmd(mtd, page & chip->pagemask);
 
-		status = chip->waitfunc(mtd, chip, FL_ERASING);
+		status = chip->waitfunc(mtd, chip);
 
 		/*
 		 * See if operation failed and additional status checks are
@@ -2265,6 +2386,10 @@ int nand_scan(struct mtd_info *mtd, int 
 			chip->ecc.read_page = nand_read_page_hwecc;
 		if (!chip->ecc.write_page)
 			chip->ecc.write_page = nand_write_page_hwecc;
+		if (!chip->ecc.read_oob)
+			chip->ecc.read_oob = nand_read_oob_std;
+		if (!chip->ecc.write_oob)
+			chip->ecc.write_oob = nand_write_oob_std;
 
 	case NAND_ECC_HW_SYNDROME:
 		if (!chip->ecc.calculate || !chip->ecc.correct ||
@@ -2278,6 +2403,10 @@ int nand_scan(struct mtd_info *mtd, int 
 			chip->ecc.read_page = nand_read_page_syndrome;
 		if (!chip->ecc.write_page)
 			chip->ecc.write_page = nand_write_page_syndrome;
+		if (!chip->ecc.read_oob)
+			chip->ecc.read_oob = nand_read_oob_syndrome;
+		if (!chip->ecc.write_oob)
+			chip->ecc.write_oob = nand_write_oob_syndrome;
 
 		if (mtd->writesize >= chip->ecc.size)
 			break;
@@ -2291,6 +2420,8 @@ int nand_scan(struct mtd_info *mtd, int 
 		chip->ecc.correct = nand_correct_data;
 		chip->ecc.read_page = nand_read_page_swecc;
 		chip->ecc.write_page = nand_write_page_swecc;
+		chip->ecc.read_oob = nand_read_oob_std;
+		chip->ecc.write_oob = nand_write_oob_std;
 		chip->ecc.size = 256;
 		chip->ecc.bytes = 3;
 		break;
@@ -2300,6 +2431,8 @@ int nand_scan(struct mtd_info *mtd, int 
 		       "This is not recommended !!\n");
 		chip->ecc.read_page = nand_read_page_raw;
 		chip->ecc.write_page = nand_write_page_raw;
+		chip->ecc.read_oob = nand_read_oob_std;
+		chip->ecc.write_oob = nand_write_oob_std;
 		chip->ecc.size = mtd->writesize;
 		chip->ecc.bytes = 0;
 		break;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index bf2ce68..a30969e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -63,18 +63,21 @@ #define NAND_CTRL_CHANGE	0x80
  */
 #define NAND_CMD_READ0		0
 #define NAND_CMD_READ1		1
+#define NAND_CMD_RNDOUT		5
 #define NAND_CMD_PAGEPROG	0x10
 #define NAND_CMD_READOOB	0x50
 #define NAND_CMD_ERASE1		0x60
 #define NAND_CMD_STATUS		0x70
 #define NAND_CMD_STATUS_MULTI	0x71
 #define NAND_CMD_SEQIN		0x80
+#define NAND_CMD_RNDIN		0x85
 #define NAND_CMD_READID		0x90
 #define NAND_CMD_ERASE2		0xd0
 #define NAND_CMD_RESET		0xff
 
 /* Extended commands for large page devices */
 #define NAND_CMD_READSTART	0x30
+#define NAND_CMD_RNDOUTSTART	0xE0
 #define NAND_CMD_CACHEDPROG	0x15
 
 /* Extended commands for AG-AND device */
@@ -250,6 +253,13 @@ struct nand_ecc_ctrl {
 	void			(*write_page)(struct mtd_info *mtd,
 					      struct nand_chip *chip,
 					      const uint8_t *buf);
+	int			(*read_oob)(struct mtd_info *mtd,
+					    struct nand_chip *chip,
+					    int page,
+					    int sndcmd);
+	int			(*write_oob)(struct mtd_info *mtd,
+					     struct nand_chip *chip,
+					     int page);
 };
 
 /**
@@ -339,7 +349,7 @@ struct nand_chip {
 				    unsigned int ctrl);
 	int		(*dev_ready)(struct mtd_info *mtd);
 	void		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
-	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
+	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
 	void		(*erase_cmd)(struct mtd_info *mtd, int page);
 	int		(*scan_bbt)(struct mtd_info *mtd);
 	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);


From linux-mtd at lists.infradead.org  Tue Jun 20 15:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 20 Jun 2006 20:59:02 +0100
Subject: [PATCH] NAND: fix remaining OOB length calculation
Message-ID: <E1FsmNK-0001G3-AX@pentafluge.infradead.org>

Commit:     7e4178f90eec862affc97469118d5008bd1b5bda
Parent:     b6d5ee00e397b20dc88f7ffaa6f7651b71996a5c
commit 7e4178f90eec862affc97469118d5008bd1b5bda
Author:     Vitaly Wool <vwool at ru.mvista.com>
AuthorDate: Wed Jun 7 09:34:37 2006 +0400
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 20 20:31:23 2006 +0100

    [PATCH] NAND: fix remaining OOB length calculation
    
    In nand_read_page_syndrome/nand_write_page_syndrome the calculation of
    the remaining oob length which is not used by the prepad/ecc/postpad
    areas is wrong.
    
    Signed-off-by: Vitaly Wool <vwool at ru.mvista.com>
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/nand_base.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77406fc..e74678e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -883,7 +883,7 @@ static int nand_read_page_syndrome(struc
 	}
 
 	/* Calculate remaining oob bytes */
-	i = oob - chip->oob_poi;
+	i = mtd->oobsize - (oob - chip->oob_poi);
 	if (i)
 		chip->read_buf(mtd, oob, i);
 
@@ -1334,7 +1334,7 @@ static void nand_write_page_syndrome(str
 	}
 
 	/* Calculate remaining oob bytes */
-	i = oob - chip->oob_poi;
+	i = mtd->oobsize - (oob - chip->oob_poi);
 	if (i)
 		chip->write_buf(mtd, oob, i);
 }


From linux-mtd at lists.infradead.org  Wed Jun 21 08:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Wed, 21 Jun 2006 13:59:01 +0100
Subject: [MTD] NAND: Missing fixups
Message-ID: <E1Ft2IP-0000N4-F3@pentafluge.infradead.org>

Commit:     0d420f9d6111b3a2fb7d5dd0180456eed469055d
Parent:     22ae813b85df7c0b0fc7c8d6f336d6a9f566ff97
commit 0d420f9d6111b3a2fb7d5dd0180456eed469055d
Author:     Savin Zlobec <tglx at cruncher.tec.linutronix.de>
AuthorDate: Wed Jun 21 11:51:20 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Wed Jun 21 13:11:56 2006 +0100

    [MTD] NAND: Missing fixups
    
    The oob fixups broke a return value and missed one patch from
    the Mailing List.
    
    Signed-off-by: Savin Zlobec <savin at epico.si>
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/nand_base.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 27083ed..8df184f 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1176,7 +1176,7 @@ static int nand_write_oob_std(struct mtd
 
 	status = chip->waitfunc(mtd, chip);
 
-	return status;
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
 
 /**
@@ -1271,10 +1271,6 @@ static int nand_do_read_oob(struct mtd_i
 		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
 		buf = nand_transfer_oob(chip, buf, ops);
 
-		readlen -= ops->ooblen;
-		if (!readlen)
-			break;
-
 		if (!(chip->options & NAND_NO_READRDY)) {
 			/*
 			 * Apply delay or wait for ready/busy pin. Do this
@@ -1288,6 +1284,10 @@ static int nand_do_read_oob(struct mtd_i
 				nand_wait_ready(mtd);
 		}
 
+		readlen -= ops->ooblen;
+		if (!readlen)
+			break;
+
 		/* Increment page address */
 		realpage++;
 


From linux-mtd at lists.infradead.org  Wed Jun 21 19:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 22 Jun 2006 00:59:01 +0100
Subject: [MTD] NAND: S3C2410 convert prinks to dev_*()s
Message-ID: <E1FtCb7-0007Q5-FU@pentafluge.infradead.org>

Commit:     99974c62b6acd4093b6f485132067089c39f967c
Parent:     0d420f9d6111b3a2fb7d5dd0180456eed469055d
commit 99974c62b6acd4093b6f485132067089c39f967c
Author:     Ben Dooks <ben-linux at fluff.org>
AuthorDate: Wed Jun 21 15:43:05 2006 +0100
Commit:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
CommitDate: Wed Jun 21 18:56:34 2006 +0200

    [MTD] NAND: S3C2410 convert prinks to dev_*()s
    
    Convert the use of printk() to the correct dev_info/dev_err
    functions
    
    Signed-off-by: Ben Dooks <ben-linux at fluff.org>
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/s3c2410.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 2c262fe..5219bd2 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -63,8 +63,6 @@ #include <asm/io.h>
 #include <asm/arch/regs-nand.h>
 #include <asm/arch/nand.h>
 
-#define PFX "s3c2410-nand: "
-
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int hardware_ecc = 1;
 #else
@@ -195,11 +193,11 @@ static int s3c2410_nand_inithw(struct s3
 	}
 
 	if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
-		printk(KERN_ERR PFX "cannot get timings suitable for board\n");
+		dev_err(info->device, "cannot get suitable timings\n");
 		return -EINVAL;
 	}
 
-	printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
 	       tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
 
 	if (!info->is_s3c2440) {
@@ -218,7 +216,7 @@ static int s3c2410_nand_inithw(struct s3
 		       info->regs + S3C2440_NFCONT);
 	}
 
-	pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
+	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
 
 	writel(cfg, info->regs + S3C2410_NFCONF);
 	return 0;
@@ -250,7 +248,7 @@ static void s3c2410_nand_select_chip(str
 		cur |= bit;
 	} else {
 		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
-			printk(KERN_ERR PFX "chip %d out of range\n", chip);
+			dev_err(info->device, "invalid chip %d\n", chip);
 			return;
 		}
 


From linux-mtd at lists.infradead.org  Thu Jun 22 07:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 22 Jun 2006 12:59:02 +0100
Subject: [MTD] NAND: ndfc fix address offset thinko
Message-ID: <E1FtNpu-0002fM-3M@pentafluge.infradead.org>

Commit:     1794c13002918c2216e2e11913eb299d071a5731
Parent:     99974c62b6acd4093b6f485132067089c39f967c
commit 1794c13002918c2216e2e11913eb299d071a5731
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Thu Jun 22 13:06:43 2006 +0200
Commit:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
CommitDate: Thu Jun 22 13:06:43 2006 +0200

    [MTD] NAND: ndfc fix address offset thinko
    
    The rework of the command handling in the nand driver
    led to wrong address setting in the command control
    function. Use the correct address again.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/ndfc.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index fe8d385..e5bd88f 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_
 
 static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-	struct nand_chip *chip = mtd->priv;
+	struct ndfc_controller *ndfc = &ndfc_ctrl;
 
 	if (cmd == NAND_CMD_NONE)
 		return;
 
 	if (ctrl & NAND_CLE)
-		writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
+		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
 	else
-		writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
+		writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
 }
 
 static int ndfc_ready(struct mtd_info *mtd)


From linux-mtd at lists.infradead.org  Thu Jun 22 12:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 22 Jun 2006 17:59:01 +0100
Subject: [MTD] Initialize 'writesize'
Message-ID: <E1FtSWD-0003VC-Av@pentafluge.infradead.org>

Commit:     17ffc7ba6d7ea68b8d5f55a5ca1b87163e69720d
Parent:     1794c13002918c2216e2e11913eb299d071a5731
commit 17ffc7ba6d7ea68b8d5f55a5ca1b87163e69720d
Author:     Artem B. Bityutskiy <dedekind at sauron.oktetlabs.ru>
AuthorDate: Thu Jun 22 18:15:48 2006 +0400
Commit:     Artem B. Bityutskiy <dedekind at sauron.oktetlabs.ru>
CommitDate: Thu Jun 22 18:15:48 2006 +0400

    [MTD] Initialize 'writesize'
    
    Signed-off-by: Artem B. Bityutskiy <dedekind at infradead.org>
---
 drivers/mtd/chips/cfi_cmdset_0001.c |    1 +
 drivers/mtd/chips/jedec.c           |    1 +
 drivers/mtd/chips/map_absent.c      |    3 ++-
 drivers/mtd/chips/map_ram.c         |    1 +
 drivers/mtd/chips/map_rom.c         |    1 +
 drivers/mtd/devices/block2mtd.c     |    1 +
 drivers/mtd/devices/ms02-nv.c       |    1 +
 drivers/mtd/devices/mtd_dataflash.c |    1 +
 drivers/mtd/devices/phram.c         |    1 +
 drivers/mtd/devices/pmc551.c        |    3 ++-
 drivers/mtd/devices/slram.c         |    1 +
 11 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 0d43581..39edb82 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct 
 	mtd->resume  = cfi_intelext_resume;
 	mtd->flags   = MTD_CAP_NORFLASH;
 	mtd->name    = map->name;
+	mtd->writesize = 1;
 
 	mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
 
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
index c40b48d..2c3f019 100644
--- a/drivers/mtd/chips/jedec.c
+++ b/drivers/mtd/chips/jedec.c
@@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(stru
    MTD->name = map->name;
    MTD->type = MTD_NORFLASH;
    MTD->flags = MTD_CAP_NORFLASH;
+   MTD->writesize = 1;
    MTD->erasesize = SectorSize*(map->buswidth);
    //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
    MTD->size = priv->size;
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c
index a611de9..ac01a94 100644
--- a/drivers/mtd/chips/map_absent.c
+++ b/drivers/mtd/chips/map_absent.c
@@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe
 	mtd->write 	= map_absent_write;
 	mtd->sync 	= map_absent_sync;
 	mtd->flags 	= 0;
-	mtd->erasesize = PAGE_SIZE;
+	mtd->erasesize  = PAGE_SIZE;
+	mtd->writesize  = 1;
 
 	__module_get(THIS_MODULE);
 	return mtd;
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 7639257..3a66680 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -71,6 +71,7 @@ #endif
 	mtd->write = mapram_write;
 	mtd->sync = mapram_nop;
 	mtd->flags = MTD_CAP_RAM;
+	mtd->writesize = 1;
 
 	mtd->erasesize = PAGE_SIZE;
  	while(mtd->size & (mtd->erasesize - 1))
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index bc6ee9e..1b328b1 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(st
 	mtd->sync = maprom_nop;
 	mtd->flags = MTD_CAP_ROM;
 	mtd->erasesize = map->size;
+	mtd->writesize = 1;
 
 	__module_get(THIS_MODULE);
 	return mtd;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 0d98c22..be3f1c1 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -324,6 +324,7 @@ static struct block2mtd_dev *add_device(
 
 	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
 	dev->mtd.erasesize = erase_size;
+	dev->mtd.writesize = 1;
 	dev->mtd.type = MTD_RAM;
 	dev->mtd.flags = MTD_CAP_RAM;
 	dev->mtd.erase = block2mtd_erase;
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 4ab7670..08dfb89 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong 
 	mtd->owner = THIS_MODULE;
 	mtd->read = ms02nv_read;
 	mtd->write = ms02nv_write;
+	mtd->writesize = 1;
 
 	ret = -EIO;
 	if (add_mtd_device(mtd)) {
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index a19480d..04271d0 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -478,6 +478,7 @@ add_dataflash(struct spi_device *spi, ch
 	device->name = (pdata && pdata->name) ? pdata->name : priv->name;
 	device->size = nr_pages * pagesize;
 	device->erasesize = pagesize;
+	device->writesize = pagesize;
 	device->owner = THIS_MODULE;
 	device->type = MTD_DATAFLASH;
 	device->flags = MTD_CAP_NORFLASH;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index e09e416..6c7337f 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -151,6 +151,7 @@ static int register_device(char *name, u
 	new->mtd.owner = THIS_MODULE;
 	new->mtd.type = MTD_RAM;
 	new->mtd.erasesize = PAGE_SIZE;
+	new->mtd.writesize = 1;
 
 	ret = -EAGAIN;
 	if (add_mtd_device(&new->mtd)) {
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 666cce1..f620d74 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -778,7 +778,8 @@ #endif
                 mtd->type 	= MTD_RAM;
                 mtd->name 	= "PMC551 RAM board";
                 mtd->erasesize 	= 0x10000;
-		mtd->owner = THIS_MODULE;
+                mtd->writesize  = 1;
+                mtd->owner = THIS_MODULE;
 
                 if (add_mtd_device(mtd)) {
                         printk(KERN_NOTICE "pmc551: Failed to register new device\n");
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index b3f665e..542a0c0 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -209,6 +209,7 @@ static int register_device(char *name, u
 	(*curmtd)->mtdinfo->owner = THIS_MODULE;
 	(*curmtd)->mtdinfo->type = MTD_RAM;
 	(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
+	(*curmtd)->mtdinfo->writesize = 1;
 
 	if (add_mtd_device((*curmtd)->mtdinfo))	{
 		E("slram: Failed to register new device\n");


From linux-mtd at lists.infradead.org  Tue Jun 27 09:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 14:59:01 +0100
Subject: [MTD NAND] s3c2412 support in s3c2410.c
Message-ID: <E1FvE5l-0008Gi-TU@pentafluge.infradead.org>

Commit:     2c06a0821711a53d51a3d0492a9be0671b7152e5
Parent:     62ed948cb1405fe95d61d8c6445c102e0c9da0a6
commit 2c06a0821711a53d51a3d0492a9be0671b7152e5
Author:     Ben Dooks <ben-mtd at fluff.org>
AuthorDate: Tue Jun 27 14:35:46 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 14:35:46 2006 +0100

    [MTD NAND] s3c2412 support in s3c2410.c
    
    Add support for both the S3C2412 and S3C2412 Samsung SoCs to
    the increasingly mis-named s3c2410.c driver.
    
    This currently only supports SLC ECCs, and a chip on nFCE0.
    
    Signed-off-by: Ben Dooks <ben-linux at fluff.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/s3c2410.c               |  154 ++++++++++++++++++++++--------
 include/asm-arm/arch-s3c2410/regs-nand.h |   48 +++++++++
 2 files changed, 158 insertions(+), 44 deletions(-)

diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 5219bd2..ff5cef2 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -97,6 +97,12 @@ struct s3c2410_nand_mtd {
 	int				scan_res;
 };
 
+enum s3c_cpu_type {
+	TYPE_S3C2410,
+	TYPE_S3C2412,
+	TYPE_S3C2440,
+};
+
 /* overview of the s3c2410 nand state */
 
 struct s3c2410_nand_info {
@@ -110,9 +116,11 @@ struct s3c2410_nand_info {
 	struct resource			*area;
 	struct clk			*clk;
 	void __iomem			*regs;
+	void __iomem			*sel_reg;
+	int				sel_bit;
 	int				mtd_count;
 
-	unsigned char			is_s3c2440;
+	enum s3c_cpu_type		cpu_type;
 };
 
 /* conversion functions */
@@ -146,7 +154,7 @@ static inline int allow_clk_stop(struct 
 
 #define NS_IN_KHZ 1000000
 
-static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
+static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
 {
 	int result;
 
@@ -170,24 +178,26 @@ #define to_ns(ticks,clk) (((ticks) * NS_
 
 /* controller setup */
 
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+			       struct platform_device *pdev)
 {
 	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
 	unsigned long clkrate = clk_get_rate(info->clk);
+	int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
 	int tacls, twrph0, twrph1;
-	unsigned long cfg;
+	unsigned long cfg = 0;
 
 	/* calculate the timing information for the controller */
 
 	clkrate /= 1000;	/* turn clock into kHz for ease of use */
 
 	if (plat != NULL) {
-		tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
-		twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
-		twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
+		tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+		twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+		twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
 	} else {
 		/* default timings */
-		tacls = 4;
+		tacls = tacls_max;
 		twrph0 = 8;
 		twrph1 = 8;
 	}
@@ -200,20 +210,23 @@ static int s3c2410_nand_inithw(struct s3
 	dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
 	       tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
 
-	if (!info->is_s3c2440) {
+ 	switch (info->cpu_type) {
+ 	case TYPE_S3C2410:
 		cfg = S3C2410_NFCONF_EN;
 		cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
 		cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
 		cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
-	} else {
+		break;
+
+ 	case TYPE_S3C2440:
+ 	case TYPE_S3C2412:
 		cfg = S3C2440_NFCONF_TACLS(tacls - 1);
 		cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
 		cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
 
 		/* enable the controller and de-assert nFCE */
 
-		writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
-		       info->regs + S3C2440_NFCONT);
+		writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
 	}
 
 	dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
@@ -229,23 +242,18 @@ static void s3c2410_nand_select_chip(str
 	struct s3c2410_nand_info *info;
 	struct s3c2410_nand_mtd *nmtd;
 	struct nand_chip *this = mtd->priv;
-	void __iomem *reg;
 	unsigned long cur;
-	unsigned long bit;
 
 	nmtd = this->priv;
 	info = nmtd->info;
 
-	bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
-	reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
-
 	if (chip != -1 && allow_clk_stop(info))
 		clk_enable(info->clk);
 
-	cur = readl(reg);
+	cur = readl(info->sel_reg);
 
 	if (chip == -1) {
-		cur |= bit;
+		cur |= info->sel_bit;
 	} else {
 		if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
 			dev_err(info->device, "invalid chip %d\n", chip);
@@ -257,10 +265,10 @@ static void s3c2410_nand_select_chip(str
 				(info->platform->select_chip) (nmtd->set, chip);
 		}
 
-		cur &= ~bit;
+		cur &= ~info->sel_bit;
 	}
 
-	writel(cur, reg);
+	writel(cur, info->sel_reg);
 
 	if (chip == -1 && allow_clk_stop(info))
 		clk_disable(info->clk);
@@ -309,15 +317,25 @@ static void s3c2440_nand_hwcontrol(struc
 static int s3c2410_nand_devready(struct mtd_info *mtd)
 {
 	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
-	if (info->is_s3c2440)
-		return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
 	return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
 }
 
+static int s3c2440_nand_devready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+}
+
+static int s3c2412_nand_devready(struct mtd_info *mtd)
+{
+	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+	return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+}
+
 /* ECC handling functions */
 
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+				     u_char *read_ecc, u_char *calc_ecc)
 {
 	pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
 
@@ -485,11 +503,8 @@ static void s3c2410_nand_init_chip(struc
 				   struct s3c2410_nand_set *set)
 {
 	struct nand_chip *chip = &nmtd->chip;
+	void __iomem *regs = info->regs;
 
-	chip->IO_ADDR_R	   = info->regs + S3C2410_NFDATA;
-	chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;
-	chip->cmd_ctrl     = s3c2410_nand_hwcontrol;
-	chip->dev_ready    = s3c2410_nand_devready;
 	chip->write_buf    = s3c2410_nand_write_buf;
 	chip->read_buf     = s3c2410_nand_read_buf;
 	chip->select_chip  = s3c2410_nand_select_chip;
@@ -498,11 +513,37 @@ static void s3c2410_nand_init_chip(struc
 	chip->options	   = 0;
 	chip->controller   = &info->controller;
 
-	if (info->is_s3c2440) {
-		chip->IO_ADDR_R	 = info->regs + S3C2440_NFDATA;
-		chip->IO_ADDR_W  = info->regs + S3C2440_NFDATA;
-		chip->cmd_ctrl   = s3c2440_nand_hwcontrol;
-	}
+	switch (info->cpu_type) {
+	case TYPE_S3C2410:
+		chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+		info->sel_reg   = regs + S3C2410_NFCONF;
+		info->sel_bit	= S3C2410_NFCONF_nFCE;
+		chip->cmd_ctrl  = s3c2410_nand_hwcontrol;
+		chip->dev_ready = s3c2410_nand_devready;
+		break;
+
+	case TYPE_S3C2440:
+		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+		info->sel_reg   = regs + S3C2440_NFCONT;
+		info->sel_bit	= S3C2440_NFCONT_nFCE;
+		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+		chip->dev_ready = s3c2440_nand_devready;
+		break;
+
+	case TYPE_S3C2412:
+		chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+		info->sel_reg   = regs + S3C2440_NFCONT;
+		info->sel_bit	= S3C2412_NFCONT_nFCE0;
+		chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
+		chip->dev_ready = s3c2412_nand_devready;
+
+		if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+			dev_info(info->device, "System booted from NAND\n");
+
+		break;
+  	}
+
+	chip->IO_ADDR_R = chip->IO_ADDR_W;
 
 	nmtd->info	   = info;
 	nmtd->mtd.priv	   = chip;
@@ -510,17 +551,25 @@ static void s3c2410_nand_init_chip(struc
 	nmtd->set	   = set;
 
 	if (hardware_ecc) {
-		chip->ecc.correct   = s3c2410_nand_correct_data;
-		chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
 		chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+		chip->ecc.correct   = s3c2410_nand_correct_data;
 		chip->ecc.mode	    = NAND_ECC_HW;
 		chip->ecc.size	    = 512;
 		chip->ecc.bytes	    = 3;
 		chip->ecc.layout    = &nand_hw_eccoob;
 
-		if (info->is_s3c2440) {
-			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
-			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+		switch (info->cpu_type) {
+		case TYPE_S3C2410:
+			chip->ecc.hwctl	    = s3c2410_nand_enable_hwecc;
+			chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+			break;
+
+		case TYPE_S3C2412:
+		case TYPE_S3C2440:
+  			chip->ecc.hwctl     = s3c2440_nand_enable_hwecc;
+  			chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+			break;
+
 		}
 	} else {
 		chip->ecc.mode	    = NAND_ECC_SOFT;
@@ -535,7 +584,8 @@ static void s3c2410_nand_init_chip(struc
  * nand layer to look for devices
 */
 
-static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
+static int s3c24xx_nand_probe(struct platform_device *pdev,
+			      enum s3c_cpu_type cpu_type)
 {
 	struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
 	struct s3c2410_nand_info *info;
@@ -590,7 +640,7 @@ static int s3c24xx_nand_probe(struct pla
 	info->device     = &pdev->dev;
 	info->platform   = plat;
 	info->regs       = ioremap(res->start, size);
-	info->is_s3c2440 = is_s3c2440;
+	info->cpu_type   = cpu_type;
 
 	if (info->regs == NULL) {
 		dev_err(&pdev->dev, "cannot reserve register region\n");
@@ -697,12 +747,17 @@ #endif
 
 static int s3c2410_nand_probe(struct platform_device *dev)
 {
-	return s3c24xx_nand_probe(dev, 0);
+	return s3c24xx_nand_probe(dev, TYPE_S3C2410);
 }
 
 static int s3c2440_nand_probe(struct platform_device *dev)
 {
-	return s3c24xx_nand_probe(dev, 1);
+	return s3c24xx_nand_probe(dev, TYPE_S3C2440);
+}
+
+static int s3c2412_nand_probe(struct platform_device *dev)
+{
+	return s3c24xx_nand_probe(dev, TYPE_S3C2412);
 }
 
 static struct platform_driver s3c2410_nand_driver = {
@@ -727,16 +782,29 @@ static struct platform_driver s3c2440_na
 	},
 };
 
+static struct platform_driver s3c2412_nand_driver = {
+	.probe		= s3c2412_nand_probe,
+	.remove		= s3c2410_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
+	.driver		= {
+		.name	= "s3c2412-nand",
+		.owner	= THIS_MODULE,
+	},
+};
+
 static int __init s3c2410_nand_init(void)
 {
 	printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
 
+	platform_driver_register(&s3c2412_nand_driver);
 	platform_driver_register(&s3c2440_nand_driver);
 	return platform_driver_register(&s3c2410_nand_driver);
 }
 
 static void __exit s3c2410_nand_exit(void)
 {
+	platform_driver_unregister(&s3c2412_nand_driver);
 	platform_driver_unregister(&s3c2440_nand_driver);
 	platform_driver_unregister(&s3c2410_nand_driver);
 }
diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/arch-s3c2410/regs-nand.h
index 7cff235..c1470c6 100644
--- a/include/asm-arm/arch-s3c2410/regs-nand.h
+++ b/include/asm-arm/arch-s3c2410/regs-nand.h
@@ -39,10 +39,19 @@ #define S3C2440_NFESTAT0 S3C2410_NFREG(0
 #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
 #define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
 #define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
-#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSECC   S3C24E10_NFREG(0x34)
 #define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
 #define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
 
+#define S3C2412_NFSBLK		S3C2410_NFREG(0x20)
+#define S3C2412_NFEBLK		S3C2410_NFREG(0x24)
+#define S3C2412_NFSTAT		S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC_ERR0	S3C2410_NFREG(0x2C)
+#define S3C2412_NFMECC_ERR1	S3C2410_NFREG(0x30)
+#define S3C2412_NFMECC0		S3C2410_NFREG(0x34)
+#define S3C2412_NFMECC1		S3C2410_NFREG(0x38)
+#define S3C2412_NFSECC		S3C2410_NFREG(0x3C)
+
 #define S3C2410_NFCONF_EN          (1<<15)
 #define S3C2410_NFCONF_512BYTE     (1<<14)
 #define S3C2410_NFCONF_4STEP       (1<<13)
@@ -77,5 +86,42 @@ #define S3C2440_NFSTAT_nCE		(1<<1)
 #define S3C2440_NFSTAT_RnB_CHANGE	(1<<2)
 #define S3C2440_NFSTAT_ILLEGAL_ACCESS	(1<<3)
 
+#define S3C2412_NFCONF_NANDBOOT		(1<<31)
+#define S3C2412_NFCONF_ECCCLKCON	(1<<30)
+#define S3C2412_NFCONF_ECC_MLC		(1<<24)
+#define S3C2412_NFCONF_TACLS_MASK	(7<<12)	/* 1 extra bit of Tacls */
+
+#define S3C2412_NFCONT_ECC4_DIRWR	(1<<18)
+#define S3C2412_NFCONT_LOCKTIGHT	(1<<17)
+#define S3C2412_NFCONT_SOFTLOCK		(1<<16)
+#define S3C2412_NFCONT_ECC4_ENCINT	(1<<13)
+#define S3C2412_NFCONT_ECC4_DECINT	(1<<12)
+#define S3C2412_NFCONT_MAIN_ECC_LOCK	(1<<7)
+#define S3C2412_NFCONT_INIT_MAIN_ECC	(1<<5)
+#define S3C2412_NFCONT_nFCE1		(1<<2)
+#define S3C2412_NFCONT_nFCE0		(1<<1)
+
+#define S3C2412_NFSTAT_ECC_ENCDONE	(1<<7)
+#define S3C2412_NFSTAT_ECC_DECDONE	(1<<6)
+#define S3C2412_NFSTAT_ILLEGAL_ACCESS	(1<<5)
+#define S3C2412_NFSTAT_RnB_CHANGE	(1<<4)
+#define S3C2412_NFSTAT_nFCE1		(1<<3)
+#define S3C2412_NFSTAT_nFCE0		(1<<2)
+#define S3C2412_NFSTAT_Res1		(1<<1)
+#define S3C2412_NFSTAT_READY		(1<<0)
+
+#define S3C2412_NFECCERR_SERRDATA(x)	(((x) >> 21) & 0xf)
+#define S3C2412_NFECCERR_SERRBIT(x)	(((x) >> 18) & 0x7)
+#define S3C2412_NFECCERR_MERRDATA(x)	(((x) >> 7) & 0x3ff)
+#define S3C2412_NFECCERR_MERRBIT(x)	(((x) >> 4) & 0x7)
+#define S3C2412_NFECCERR_SPARE_ERR(x)	(((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_MAIN_ERR(x)	(((x) >> 2) & 0x3)
+#define S3C2412_NFECCERR_NONE		(0)
+#define S3C2412_NFECCERR_1BIT		(1)
+#define S3C2412_NFECCERR_MULTIBIT	(2)
+#define S3C2412_NFECCERR_ECCAREA	(3)
+
+
+
 #endif /* __ASM_ARM_REGS_NAND */
 


From linux-mtd at lists.infradead.org  Tue Jun 27 09:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 14:59:02 +0100
Subject: [MTD] Remove unused 'nr_banks' variable from ixp2000 map driver
Message-ID: <E1FvE5m-0008H2-3D@pentafluge.infradead.org>

Commit:     ce5b0968b1caa6b93e366e88a3c5fa2fd59029ce
Parent:     2c06a0821711a53d51a3d0492a9be0671b7152e5
commit ce5b0968b1caa6b93e366e88a3c5fa2fd59029ce
Author:     Lennert Buytenhek <buytenh at wantstofly.org>
AuthorDate: Tue Jun 27 14:36:20 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 14:36:20 2006 +0100

    [MTD] Remove unused 'nr_banks' variable from ixp2000 map driver
    
    Signed-off-by: Lennert Buytenhek <buytenh at wantstofly.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/maps/ixp2000.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index 2c9cc7f..c26488a 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -42,7 +42,6 @@ struct ixp2000_flash_info {
 	struct		map_info map;
 	struct		mtd_partition *partitions;
 	struct		resource *res;
-	int		nr_banks;
 };
 
 static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
@@ -183,7 +182,6 @@ static int ixp2000_flash_probe(struct pl
 	 */
 	info->map.phys = NO_XIP;
 
-	info->nr_banks = ixp_data->nr_banks;
 	info->map.size = ixp_data->nr_banks * window_size;
 	info->map.bankwidth = 1;
 


From linux-mtd at lists.infradead.org  Tue Jun 27 09:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 14:59:02 +0100
Subject: [MTD] Fix off-by-one error in physmap.c
Message-ID: <E1FvE5m-0008HL-B3@pentafluge.infradead.org>

Commit:     6d4f8224d4ee065e0e3186cc554468d735e6015d
Parent:     ce5b0968b1caa6b93e366e88a3c5fa2fd59029ce
commit 6d4f8224d4ee065e0e3186cc554468d735e6015d
Author:     Sascha Hauer <s.hauer at pengutronix.de>
AuthorDate: Tue Jun 27 14:38:15 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 14:38:15 2006 +0100

    [MTD] Fix off-by-one error in physmap.c
    
    This patch fixes a simple off-by-one error in the mtd physmap driver.
    
    Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
    Signed-off-by: Lennert Buytenhek <buytenh at wantstofly.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/maps/physmap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 433c3ca..d6301f0 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -182,7 +182,7 @@ static struct physmap_flash_data physmap
 
 static struct resource physmap_flash_resource = {
 	.start		= CONFIG_MTD_PHYSMAP_START,
-	.end		= CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
+	.end		= CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
 	.flags		= IORESOURCE_MEM,
 };
 


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:02 +0100
Subject: [JFFS2][XATTR] Re-define xd->refcnt as atomic_t
Message-ID: <E1FvFxu-0003Mu-RF@pentafluge.infradead.org>

Commit:     2c887e2359f6e7217cdaa17994ca94ef328b658f
Parent:     355ed4e141203fd7266ef9d90d57be0c61bd1aa4
commit 2c887e2359f6e7217cdaa17994ca94ef328b658f
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sat Jun 24 09:16:50 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:19:06 2006 +0100

    [JFFS2][XATTR] Re-define xd->refcnt as atomic_t
    
    In jffs2_release_xattr_datum(), it refers xd->refcnt to ensure
    whether releasing xd is allowed or not.
    But we can't hold xattr_sem since this function is called under
    spin_lock(&c->erase_completion_lock). Thus we have to refer it
    without any locking.
    
    This patch redefine xd->refcnt as atomic_t. It enables to refer
    xd->refcnt without any locking.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/xattr.c |   25 +++++++++++--------------
 fs/jffs2/xattr.h |    2 +-
 2 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 7622f79..18e66db 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -345,7 +345,7 @@ static struct jffs2_xattr_datum *create_
 		    && xd->value_len==xsize
 		    && !strcmp(xd->xname, xname)
 		    && !memcmp(xd->xvalue, xvalue, xsize)) {
-			xd->refcnt++;
+			atomic_inc(&xd->refcnt);
 			return xd;
 		}
 	}
@@ -365,7 +365,7 @@ static struct jffs2_xattr_datum *create_
 	strcpy(data, xname);
 	memcpy(data + name_len + 1, xvalue, xsize);
 
-	xd->refcnt = 1;
+	atomic_set(&xd->refcnt, 1);
 	xd->xid = ++c->highest_xid;
 	xd->flags |= JFFS2_XFLAGS_HOT;
 	xd->xprefix = xprefix;
@@ -397,7 +397,7 @@ static struct jffs2_xattr_datum *create_
 static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
-	BUG_ON(xd->refcnt);
+	BUG_ON(atomic_read(&xd->refcnt));
 
 	unload_xattr_datum(c, xd);
 	xd->flags |= JFFS2_XFLAGS_DEAD;
@@ -580,7 +580,7 @@ static void delete_xattr_ref(struct jffs
 	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
 		  ref->ino, ref->xid, ref->xseqno);
 
-	if (!--xd->refcnt)
+	if (atomic_dec_and_test(&xd->refcnt))
 		delete_xattr_datum(c, xd);
 }
 
@@ -612,8 +612,7 @@ void jffs2_xattr_free_inode(struct jffs2
 	for (ref = ic->xref; ref; ref = _ref) {
 		_ref = ref->next;
 		xd = ref->xd;
-		xd->refcnt--;
-		if (!xd->refcnt) {
+		if (atomic_dec_and_test(&xd->refcnt)) {
 			unload_xattr_datum(c, xd);
 			jffs2_free_xattr_datum(xd);
 		}
@@ -835,7 +834,7 @@ void jffs2_build_xattr_subsystem(struct 
 			}
 			ref->xd = xd;
 			ref->ic = ic;
-			xd->refcnt++;
+			atomic_inc(&xd->refcnt);
 			ref->next = ic->xref;
 			ic->xref = ref;
 		}
@@ -846,7 +845,7 @@ void jffs2_build_xattr_subsystem(struct 
 		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
 			xdatum_count++;
 			list_del_init(&xd->xindex);
-			if (!xd->refcnt) {
+			if (!atomic_read(&xd->refcnt)) {
 				dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n",
 					  xd->xid, xd->version);
 				xd->flags |= JFFS2_XFLAGS_DEAD;
@@ -1120,7 +1119,7 @@ int do_jffs2_setxattr(struct inode *inod
 					ref->next = c->xref_dead_list;
 					c->xref_dead_list = ref;
 					spin_unlock(&c->erase_completion_lock);
-					if (!--xd->refcnt)
+					if (atomic_dec_and_test(&xd->refcnt))
 						delete_xattr_datum(c, xd);
 				} else {
 					ref->ic = ic;
@@ -1157,8 +1156,7 @@ int do_jffs2_setxattr(struct inode *inod
 	down_write(&c->xattr_sem);
 	if (rc) {
 		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-		xd->refcnt--;
-		if (!xd->refcnt)
+		if (atomic_dec_and_test(&xd->refcnt))
 			delete_xattr_datum(c, xd);
 		up_write(&c->xattr_sem);
 		return rc;
@@ -1172,8 +1170,7 @@ int do_jffs2_setxattr(struct inode *inod
 			ic->xref = ref;
 		}
 		rc = PTR_ERR(newref);
-		xd->refcnt--;
-		if (!xd->refcnt)
+		if (atomic_dec_and_test(&xd->refcnt))
 			delete_xattr_datum(c, xd);
 	} else if (ref) {
 		delete_xattr_ref(c, ref);
@@ -1304,7 +1301,7 @@ int jffs2_verify_xattr(struct jffs2_sb_i
 void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under spin_lock(&c->erase_completion_lock) */
-	if (xd->refcnt > 0 || xd->node != (void *)xd)
+	if (atomic_read(&xd->refcnt) || xd->node != (void *)xd)
 		return;
 
 	list_del(&xd->xindex);
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 4a10abc..06a5c69 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -28,7 +28,7 @@ struct jffs2_xattr_datum
 	uint16_t xprefix;		/* see JFFS2_XATTR_PREFIX_* */
 
 	struct list_head xindex;	/* chained from c->xattrindex[n] */
-	uint32_t refcnt;		/* # of xattr_ref refers this */
+	atomic_t refcnt;		/* # of xattr_ref refers this */
 	uint32_t xid;
 	uint32_t version;
 


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:03 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:03 +0100
Subject: [JFFS2][XATTR] Fix wrong copyright
Message-ID: <E1FvFxv-0003ND-3Y@pentafluge.infradead.org>

Commit:     332a6b99c587161a972eaa1b00ae0e0dc49fbbfd
Parent:     2c887e2359f6e7217cdaa17994ca94ef328b658f
commit 332a6b99c587161a972eaa1b00ae0e0dc49fbbfd
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sat Jun 24 09:17:42 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:19:39 2006 +0100

    [JFFS2][XATTR] Fix wrong copyright
    
    summary.c was modified at 2006.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/summary.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index c430f1d..1deb92a 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -5,7 +5,7 @@
  *                     Zoltan Sogor <weth at inf.u-szeged.hu>,
  *                     Patrik Kluba <pajko at halom.u-szeged.hu>,
  *                     University of Szeged, Hungary
- *               2005  KaiGai Kohei <kaigai at ak.jp.nec.com>
+ *               2006  KaiGai Kohei <kaigai at ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:01 +0100
Subject: [JFFS2][XATTR] using 'delete marker' for xdatum/xref deletion
Message-ID: <E1FvFxt-0003Lg-P9@pentafluge.infradead.org>

Commit:     c9f700f840bd481b3e01fcad1ba8da01794a6726
Parent:     6d4f8224d4ee065e0e3186cc554468d735e6015d
commit c9f700f840bd481b3e01fcad1ba8da01794a6726
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sun Jun 11 10:35:15 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:16:26 2006 +0100

    [JFFS2][XATTR] using 'delete marker' for xdatum/xref deletion
    
    - When xdatum is removed, a new xdatum with 'delete marker' is
      written. (version==0xffffffff means 'delete marker')
    - When xref is removed, a new xref with 'delete marker' is written.
      (odd-numbered xseqno means 'delete marker')
    
    - delete_xattr_(datum/xref)_delay() are new deletion functions
      are added. We can only use them if we can detect the target
      obsolete xdatum/xref as a orphan or errir one.
      (e.g when inode deletion, or detecting crc error)
    
    [1/3] jffs2-xattr-v6-01-delete_marker.patch
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/erase.c       |   19 +
 fs/jffs2/gc.c          |    5 
 fs/jffs2/jffs2_fs_sb.h |    3 
 fs/jffs2/malloc.c      |    2 
 fs/jffs2/nodemgmt.c    |   21 +
 fs/jffs2/scan.c        |   57 ++--
 fs/jffs2/summary.c     |   39 +--
 fs/jffs2/xattr.c       |  736 ++++++++++++++++++++++++++++++------------------
 fs/jffs2/xattr.h       |   40 ++-
 include/linux/jffs2.h  |    1 
 10 files changed, 584 insertions(+), 339 deletions(-)

diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 1862e8b..1644e34 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -230,7 +230,6 @@ static inline void jffs2_remove_node_ref
 			   at the end of the linked list. Stash it and continue
 			   from the beginning of the list */
 			ic = (struct jffs2_inode_cache *)(*prev);
-			BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
 			prev = &ic->nodes;
 			continue;
 		}
@@ -254,7 +253,8 @@ static inline void jffs2_remove_node_ref
 
 	/* PARANOIA */
 	if (!ic) {
-		printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!\n");
+		JFFS2_WARNING("inode_cache/xattr_datum/xattr_ref"
+			      " not found in remove_node_refs()!!\n");
 		return;
 	}
 
@@ -279,8 +279,19 @@ static inline void jffs2_remove_node_ref
 		printk("\n");
 	});
 
-	if (ic->nodes == (void *)ic && ic->nlink == 0)
-		jffs2_del_ino_cache(c, ic);
+	switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+		case RAWNODE_CLASS_XATTR_DATUM:
+			jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+			break;
+		case RAWNODE_CLASS_XATTR_REF:
+			jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+			break;
+#endif
+		default:
+			if (ic->nodes == (void *)ic && ic->nlink == 0)
+				jffs2_del_ino_cache(c, ic);
+	}
 }
 
 void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 477c526..f59b147 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -275,13 +275,12 @@ #ifdef CONFIG_JFFS2_FS_XATTR
 	 * We can decide whether this node is inode or xattr by ic->class.     */
 	if (ic->class == RAWNODE_CLASS_XATTR_DATUM
 	    || ic->class == RAWNODE_CLASS_XATTR_REF) {
-		BUG_ON(raw->next_in_ino != (void *)ic);
 		spin_unlock(&c->erase_completion_lock);
 
 		if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
-			ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+			ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw);
 		} else {
-			ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+			ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
 		}
 		goto release_sem;
 	}
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 935fec1..b985949 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -119,8 +119,11 @@ #endif
 #ifdef CONFIG_JFFS2_FS_XATTR
 #define XATTRINDEX_HASHSIZE	(57)
 	uint32_t highest_xid;
+	uint32_t highest_xseqno;
 	struct list_head xattrindex[XATTRINDEX_HASHSIZE];
 	struct list_head xattr_unchecked;
+	struct list_head xattr_dead_list;
+	struct jffs2_xattr_ref *xref_dead_list;
 	struct jffs2_xattr_ref *xref_temp;
 	struct rw_semaphore xattr_sem;
 	uint32_t xdatum_mem_usage;
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 4889d07..8310c95 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -291,6 +291,7 @@ struct jffs2_xattr_datum *jffs2_alloc_xa
 
 	memset(xd, 0, sizeof(struct jffs2_xattr_datum));
 	xd->class = RAWNODE_CLASS_XATTR_DATUM;
+	xd->node = (void *)xd;
 	INIT_LIST_HEAD(&xd->xindex);
 	return xd;
 }
@@ -309,6 +310,7 @@ struct jffs2_xattr_ref *jffs2_alloc_xatt
 
 	memset(ref, 0, sizeof(struct jffs2_xattr_ref));
 	ref->class = RAWNODE_CLASS_XATTR_REF;
+	ref->node = (void *)ref;
 	return ref;
 }
 
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 8bedfd2..01594a2 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -684,19 +684,26 @@ void jffs2_mark_node_obsolete(struct jff
 		spin_lock(&c->erase_completion_lock);
 
 		ic = jffs2_raw_ref_to_ic(ref);
-		/* It seems we should never call jffs2_mark_node_obsolete() for
-		   XATTR nodes.... yet. Make sure we notice if/when we change
-		   that :) */
-		BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE);
 		for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
 			;
 
 		*p = ref->next_in_ino;
 		ref->next_in_ino = NULL;
 
-		if (ic->nodes == (void *)ic && ic->nlink == 0)
-			jffs2_del_ino_cache(c, ic);
-
+		switch (ic->class) {
+#ifdef CONFIG_JFFS2_FS_XATTR
+			case RAWNODE_CLASS_XATTR_DATUM:
+				jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+				break;
+			case RAWNODE_CLASS_XATTR_REF:
+				jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+				break;
+#endif
+			default:
+				if (ic->nodes == (void *)ic && ic->nlink == 0)
+					jffs2_del_ino_cache(c, ic);
+				break;
+		}
 		spin_unlock(&c->erase_completion_lock);
 	}
 
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 6161808..79638f5 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -317,20 +317,25 @@ static int jffs2_scan_xattr_node(struct 
 				 struct jffs2_summary *s)
 {
 	struct jffs2_xattr_datum *xd;
-	uint32_t totlen, crc;
+	uint32_t xid, version, totlen, crc;
 	int err;
 
 	crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
 	if (crc != je32_to_cpu(rx->node_crc)) {
-		if (je32_to_cpu(rx->node_crc) != 0xffffffff)
-			JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-				      ofs, je32_to_cpu(rx->node_crc), crc);
+		JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+			      ofs, je32_to_cpu(rx->node_crc), crc);
 		if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
 			return err;
 		return 0;
 	}
 
-	totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
+	xid = je32_to_cpu(rx->xid);
+	version = je32_to_cpu(rx->version);
+
+	totlen = sizeof(struct jffs2_raw_xattr);
+	if (version != XDATUM_DELETE_MARKER)
+		totlen += rx->name_len + 1 + je16_to_cpu(rx->value_len);
+	totlen = PAD(totlen);
 	if (totlen != je32_to_cpu(rx->totlen)) {
 		JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
 			      ofs, je32_to_cpu(rx->totlen), totlen);
@@ -339,22 +344,24 @@ static int jffs2_scan_xattr_node(struct 
 		return 0;
 	}
 
-	xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
-	if (IS_ERR(xd)) {
-		if (PTR_ERR(xd) == -EEXIST) {
-			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen)))))
-				return err;
-			return 0;
-		}
+	xd = jffs2_setup_xattr_datum(c, xid, version);
+	if (IS_ERR(xd))
 		return PTR_ERR(xd);
-	}
-	xd->xprefix = rx->xprefix;
-	xd->name_len = rx->name_len;
-	xd->value_len = je16_to_cpu(rx->value_len);
-	xd->data_crc = je32_to_cpu(rx->data_crc);
 
-	xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
-	/* FIXME */ xd->node->next_in_ino = (void *)xd;
+	if (xd->version > version) {
+		struct jffs2_raw_node_ref *raw
+			= jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL);
+		raw->next_in_ino = xd->node->next_in_ino;
+		xd->node->next_in_ino = raw;
+	} else {
+		xd->version = version;
+		xd->xprefix = rx->xprefix;
+		xd->name_len = rx->name_len;
+		xd->value_len = je16_to_cpu(rx->value_len);
+		xd->data_crc = je32_to_cpu(rx->data_crc);
+
+		jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd);
+	}
 
 	if (jffs2_sum_active())
 		jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
@@ -373,9 +380,8 @@ static int jffs2_scan_xref_node(struct j
 
 	crc = crc32(0, rr, sizeof(*rr) - 4);
 	if (crc != je32_to_cpu(rr->node_crc)) {
-		if (je32_to_cpu(rr->node_crc) != 0xffffffff)
-			JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-				      ofs, je32_to_cpu(rr->node_crc), crc);
+		JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+			      ofs, je32_to_cpu(rr->node_crc), crc);
 		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen)))))
 			return err;
 		return 0;
@@ -395,6 +401,7 @@ static int jffs2_scan_xref_node(struct j
 		return -ENOMEM;
 
 	/* BEFORE jffs2_build_xattr_subsystem() called, 
+	 * and AFTER xattr_ref is marked as a dead xref,
 	 * ref->xid is used to store 32bit xid, xd is not used
 	 * ref->ino is used to store 32bit inode-number, ic is not used
 	 * Thoes variables are declared as union, thus using those
@@ -404,11 +411,13 @@ static int jffs2_scan_xref_node(struct j
 	 */
 	ref->ino = je32_to_cpu(rr->ino);
 	ref->xid = je32_to_cpu(rr->xid);
+	ref->xseqno = je32_to_cpu(rr->xseqno);
+	if (ref->xseqno > c->highest_xseqno)
+		c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
 	ref->next = c->xref_temp;
 	c->xref_temp = ref;
 
-	ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL);
-	/* FIXME */ ref->node->next_in_ino = (void *)ref;
+	jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), (void *)ref);
 
 	if (jffs2_sum_active())
 		jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 0b02fc7..c430f1d 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -310,8 +310,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_i
 #ifdef CONFIG_JFFS2_FS_XATTR
 		case JFFS2_NODETYPE_XATTR: {
 			struct jffs2_sum_xattr_mem *temp;
-			if (je32_to_cpu(node->x.version) == 0xffffffff)
-				return 0;
 			temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
 			if (!temp)
 				goto no_mem;
@@ -327,10 +325,6 @@ #ifdef CONFIG_JFFS2_FS_XATTR
 		}
 		case JFFS2_NODETYPE_XREF: {
 			struct jffs2_sum_xref_mem *temp;
-
-			if (je32_to_cpu(node->r.ino) == 0xffffffff
-			    && je32_to_cpu(node->r.xid) == 0xffffffff)
-				return 0;
 			temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
 			if (!temp)
 				goto no_mem;
@@ -483,22 +477,20 @@ #ifdef CONFIG_JFFS2_FS_XATTR
 
 				xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
 								je32_to_cpu(spx->version));
-				if (IS_ERR(xd)) {
-					if (PTR_ERR(xd) == -EEXIST) {
-						/* a newer version of xd exists */
-						if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen))))
-							return err;
-						sp += JFFS2_SUMMARY_XATTR_SIZE;
-						break;
-					}
-					JFFS2_NOTICE("allocation of xattr_datum failed\n");
+				if (IS_ERR(xd))
 					return PTR_ERR(xd);
+				if (xd->version > je32_to_cpu(spx->version)) {
+					/* node is not the newest one */
+					struct jffs2_raw_node_ref *raw
+						= sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+								    PAD(je32_to_cpu(spx->totlen)), NULL);
+					raw->next_in_ino = xd->node->next_in_ino;
+					xd->node->next_in_ino = raw;
+				} else {
+					xd->version = je32_to_cpu(spx->version);
+					sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
+							  PAD(je32_to_cpu(spx->totlen)), (void *)xd);
 				}
-
-				xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
-							     PAD(je32_to_cpu(spx->totlen)), NULL);
-				/* FIXME */ xd->node->next_in_ino = (void *)xd;
-
 				*pseudo_random += je32_to_cpu(spx->xid);
 				sp += JFFS2_SUMMARY_XATTR_SIZE;
 
@@ -519,14 +511,11 @@ #ifdef CONFIG_JFFS2_FS_XATTR
 					JFFS2_NOTICE("allocation of xattr_datum failed\n");
 					return -ENOMEM;
 				}
-				ref->ino = 0xfffffffe;
-				ref->xid = 0xfffffffd;
 				ref->next = c->xref_temp;
 				c->xref_temp = ref;
 
-				ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
-							      PAD(sizeof(struct jffs2_raw_xref)), NULL);
-				/* FIXME */ ref->node->next_in_ino = (void *)ref;
+				sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
+						  PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
 
 				*pseudo_random += ref->node->flash_offset;
 				sp += JFFS2_SUMMARY_XREF_SIZE;
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 2d82e25..03871ab 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -23,18 +23,15 @@ #include "nodelist.h"
  * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
  *   is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
  *   the index of the xattr name/value pair cache (c->xattrindex).
+ * is_xattr_datum_unchecked(c, xd)
+ *   returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not
+ *   unchecked, it returns 0.
  * unload_xattr_datum(c, xd)
  *   is used to release xattr name/value pair and detach from c->xattrindex.
  * reclaim_xattr_datum(c)
  *   is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
  *   memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold 
  *   is hard coded as 32KiB.
- * delete_xattr_datum_node(c, xd)
- *   is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is
- *   enabled, it overwrites the obsolete node by myself.
- * delete_xattr_datum(c, xd)
- *   is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference
- *   counter. (It means how many jffs2_xattr_ref object refers this xdatum.)
  * do_verify_xattr_datum(c, xd)
  *   is used to load the xdatum informations without name/value pair from the medium.
  *   It's necessary once, because those informations are not collected during mounting
@@ -53,8 +50,13 @@ #include "nodelist.h"
  *   is used to write xdatum to medium. xd->version will be incremented.
  * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
  *   is used to create new xdatum and write to medium.
+ * delete_xattr_datum_delay(c, xd)
+ *   is used to delete a xdatum without 'delete marker'. It has a possibility to detect
+ *   orphan xdatum on next mounting.
+ * delete_xattr_datum(c, xd)
+ *   is used to delete a xdatum with 'delete marker'. Calling jffs2_reserve_space() is
+ *   necessary before this function.
  * -------------------------------------------------- */
-
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
 	int name_len = strlen(xname);
@@ -62,6 +64,22 @@ static uint32_t xattr_datum_hashkey(int 
 	return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
 }
 
+static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+	struct jffs2_raw_node_ref *raw;
+	int rc = 0;
+
+	spin_lock(&c->erase_completion_lock);
+	for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+		if (ref_flags(raw) == REF_UNCHECKED) {
+			rc = 1;
+			break;
+		}
+	}
+	spin_unlock(&c->erase_completion_lock);
+	return rc;
+}
+
 static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
@@ -107,80 +125,39 @@ static void reclaim_xattr_datum(struct j
 		     before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
 }
 
-static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-	/* must be called under down_write(xattr_sem) */
-	struct jffs2_raw_xattr rx;
-	size_t length;
-	int rc;
-
-	if (!xd->node) {
-		JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid);
-		return;
-	}
-	if (jffs2_sum_active()) {
-		memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr));
-		rc = jffs2_flash_read(c, ref_offset(xd->node),
-				      sizeof(struct jffs2_unknown_node),
-				      &length, (char *)&rx);
-		if (rc || length != sizeof(struct jffs2_unknown_node)) {
-			JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-				    rc, sizeof(struct jffs2_unknown_node),
-				    length, ref_offset(xd->node));
-		}
-		rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx),
-				       &length, (char *)&rx);
-		if (rc || length != sizeof(struct jffs2_raw_xattr)) {
-			JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu ar %#08x\n",
-				    rc, sizeof(rx), length, ref_offset(xd->node));
-		}
-	}
-	spin_lock(&c->erase_completion_lock);
-	xd->node->next_in_ino = NULL;
-	spin_unlock(&c->erase_completion_lock);
-	jffs2_mark_node_obsolete(c, xd->node);
-	xd->node = NULL;
-}
-
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-	/* must be called under down_write(xattr_sem) */
-	BUG_ON(xd->refcnt);
-
-	unload_xattr_datum(c, xd);
-	if (xd->node) {
-		delete_xattr_datum_node(c, xd);
-		xd->node = NULL;
-	}
-	jffs2_free_xattr_datum(xd);
-}
-
 static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
 	struct jffs2_eraseblock *jeb;
+	struct jffs2_raw_node_ref *raw;
 	struct jffs2_raw_xattr rx;
 	size_t readlen;
-	uint32_t crc, totlen;
+	uint32_t crc, offset, totlen;
 	int rc;
 
-	BUG_ON(!xd->node);
-	BUG_ON(ref_flags(xd->node) != REF_UNCHECKED);
+	spin_lock(&c->erase_completion_lock);
+	offset = ref_offset(xd->node);
+	if (ref_flags(xd->node) == REF_PRISTINE)
+		goto complete;
+	spin_unlock(&c->erase_completion_lock);
 
-	rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx);
+	rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx);
 	if (rc || readlen != sizeof(rx)) {
 		JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-			      rc, sizeof(rx), readlen, ref_offset(xd->node));
+			      rc, sizeof(rx), readlen, offset);
 		return rc ? rc : -EIO;
 	}
 	crc = crc32(0, &rx, sizeof(rx) - 4);
 	if (crc != je32_to_cpu(rx.node_crc)) {
-		if (je32_to_cpu(rx.node_crc) != 0xffffffff)
-			JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-				    ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc);
+		JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+			    offset, je32_to_cpu(rx.hdr_crc), crc);
+		xd->flags |= JFFS2_XFLAGS_INVALID;
 		return EIO;
 	}
-	totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
+	totlen = sizeof(rx);
+	if (xd->version != XDATUM_DELETE_MARKER)
+		totlen += rx.name_len + 1 + je16_to_cpu(rx.value_len);
+	totlen = PAD(totlen);
 	if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
 	    || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR
 	    || je32_to_cpu(rx.totlen) != totlen
@@ -188,11 +165,12 @@ static int do_verify_xattr_datum(struct 
 	    || je32_to_cpu(rx.version) != xd->version) {
 		JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
 			    "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
-			    ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
+			    offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
 			    je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
 			    je32_to_cpu(rx.totlen), totlen,
 			    je32_to_cpu(rx.xid), xd->xid,
 			    je32_to_cpu(rx.version), xd->version);
+		xd->flags |= JFFS2_XFLAGS_INVALID;
 		return EIO;
 	}
 	xd->xprefix = rx.xprefix;
@@ -200,14 +178,17 @@ static int do_verify_xattr_datum(struct 
 	xd->value_len = je16_to_cpu(rx.value_len);
 	xd->data_crc = je32_to_cpu(rx.data_crc);
 
-	/* This JFFS2_NODETYPE_XATTR node is checked */
-	jeb = &c->blocks[ref_offset(xd->node) / c->sector_size];
-	totlen = PAD(je32_to_cpu(rx.totlen));
-
 	spin_lock(&c->erase_completion_lock);
-	c->unchecked_size -= totlen; c->used_size += totlen;
-	jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-	xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE;
+ complete:
+	for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+		jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+		totlen = PAD(ref_totlen(c, jeb, raw));
+		if (ref_flags(raw) == REF_UNCHECKED) {
+			c->unchecked_size -= totlen; c->used_size += totlen;
+			jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+		}
+		raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL);
+	}
 	spin_unlock(&c->erase_completion_lock);
 
 	/* unchecked xdatum is chained with c->xattr_unchecked */
@@ -227,7 +208,6 @@ static int do_load_xattr_datum(struct jf
 	uint32_t crc, length;
 	int i, ret, retry = 0;
 
-	BUG_ON(!xd->node);
 	BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
 	BUG_ON(!list_empty(&xd->xindex));
  retry:
@@ -253,6 +233,7 @@ static int do_load_xattr_datum(struct jf
 			      " at %#08x, read: 0x%08x calculated: 0x%08x\n",
 			      ref_offset(xd->node), xd->data_crc, crc);
 		kfree(data);
+		xd->flags |= JFFS2_XFLAGS_INVALID;
 		return EIO;
 	}
 
@@ -286,16 +267,13 @@ static int load_xattr_datum(struct jffs2
 	 * rc > 0 : Unrecoverable error, this node should be deleted.
 	 */
 	int rc = 0;
-	BUG_ON(xd->xname);
-	if (!xd->node)
+
+	if (xd->xname)
+		return 0;
+	if (xd->flags & JFFS2_XFLAGS_INVALID)
 		return EIO;
-	if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) {
+	if (unlikely(is_xattr_datum_unchecked(c, xd)))
 		rc = do_verify_xattr_datum(c, xd);
-		if (rc > 0) {
-			list_del_init(&xd->xindex);
-			delete_xattr_datum_node(c, xd);
-		}
-	}
 	if (!rc)
 		rc = do_load_xattr_datum(c, xd);
 	return rc;
@@ -304,36 +282,43 @@ static int load_xattr_datum(struct jffs2
 static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
-	struct jffs2_raw_node_ref *raw;
 	struct jffs2_raw_xattr rx;
 	struct kvec vecs[2];
 	size_t length;
-	int rc, totlen;
+	int rc, totlen, nvecs = 1;
 	uint32_t phys_ofs = write_ofs(c);
 
-	BUG_ON(!xd->xname);
+	BUG_ON(is_xattr_datum_dead(xd) || (xd->flags & JFFS2_XFLAGS_INVALID)
+	       ? !!xd->xname : !xd->xname);
 
 	vecs[0].iov_base = &rx;
-	vecs[0].iov_len = PAD(sizeof(rx));
-	vecs[1].iov_base = xd->xname;
-	vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
-	totlen = vecs[0].iov_len + vecs[1].iov_len;
-
+	vecs[0].iov_len = totlen = sizeof(rx);
+	if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) {
+		nvecs++;
+		vecs[1].iov_base = xd->xname;
+		vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
+		totlen += vecs[1].iov_len;
+	}
 	/* Setup raw-xattr */
+	memset(&rx, 0, sizeof(rx));
 	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
 	rx.totlen = cpu_to_je32(PAD(totlen));
 	rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
 
 	rx.xid = cpu_to_je32(xd->xid);
-	rx.version = cpu_to_je32(++xd->version);
-	rx.xprefix = xd->xprefix;
-	rx.name_len = xd->name_len;
-	rx.value_len = cpu_to_je16(xd->value_len);
-	rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
+	if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) {
+		rx.version = cpu_to_je32(++xd->version);
+		rx.xprefix = xd->xprefix;
+		rx.name_len = xd->name_len;
+		rx.value_len = cpu_to_je16(xd->value_len);
+		rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
+	} else {
+		rx.version = cpu_to_je32(XDATUM_DELETE_MARKER);
+	}
 	rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));
 
-	rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);
+	rc = jffs2_flash_writev(c, vecs, nvecs, phys_ofs, &length, 0);
 	if (rc || totlen != length) {
 		JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n",
 			      rc, totlen, length, phys_ofs);
@@ -343,14 +328,8 @@ static int save_xattr_datum(struct jffs2
 
 		return rc;
 	}
-
 	/* success */
-	raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL);
-	/* FIXME */ raw->next_in_ino = (void *)xd;
-
-	if (xd->node)
-		delete_xattr_datum_node(c, xd);
-	xd->node = raw;
+	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd);
 
 	dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
 		  xd->xid, xd->version, xd->xprefix, xd->xname);
@@ -426,6 +405,39 @@ static struct jffs2_xattr_datum *create_
 	return xd;
 }
 
+static void delete_xattr_datum_delay(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+	/* must be called under down_write(xattr_sem) */
+	BUG_ON(xd->refcnt);
+
+	unload_xattr_datum(c, xd);
+	set_xattr_datum_dead(xd);
+	spin_lock(&c->erase_completion_lock);
+	list_add(&xd->xindex, &c->xattr_dead_list);
+	spin_unlock(&c->erase_completion_lock);
+	JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. "
+		     "An orphan xdatum may be detected on next mounting.\n", xd->xid);
+}
+
+static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+	/* must be called under jffs2_reserve_space() and down_write(xattr_sem) */
+	int rc;
+	BUG_ON(xd->refcnt);
+
+	unload_xattr_datum(c, xd);
+	set_xattr_datum_dead(xd);	
+	rc = save_xattr_datum(c, xd);
+	if (rc) {
+		JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. "
+			     "An orphan xdatum may be detected on next mounting.\n",
+			     xd->xid);
+	}
+	spin_lock(&c->erase_completion_lock);
+	list_add(&xd->xindex, &c->xattr_dead_list);
+	spin_unlock(&c->erase_completion_lock);
+}
+
 /* -------- xref related functions ------------------
  * verify_xattr_ref(c, ref)
  *   is used to load xref information from medium. Because summary data does not
@@ -450,25 +462,29 @@ static struct jffs2_xattr_datum *create_
 static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
 	struct jffs2_eraseblock *jeb;
+	struct jffs2_raw_node_ref *raw;
 	struct jffs2_raw_xref rr;
 	size_t readlen;
-	uint32_t crc, totlen;
+	uint32_t crc, offset, totlen;
 	int rc;
 
-	BUG_ON(ref_flags(ref->node) != REF_UNCHECKED);
+	spin_lock(&c->erase_completion_lock);
+	if (ref_flags(ref->node) != REF_UNCHECKED)
+		goto complete;
+	offset = ref_offset(ref->node);
+	spin_unlock(&c->erase_completion_lock);
 
-	rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr);
+	rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr);
 	if (rc || sizeof(rr) != readlen) {
 		JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n",
-			      rc, sizeof(rr), readlen, ref_offset(ref->node));
+			      rc, sizeof(rr), readlen, offset);
 		return rc ? rc : -EIO;
 	}
 	/* obsolete node */
 	crc = crc32(0, &rr, sizeof(rr) - 4);
 	if (crc != je32_to_cpu(rr.node_crc)) {
-		if (je32_to_cpu(rr.node_crc) != 0xffffffff)
-			JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
-				    ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc);
+		JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+			    offset, je32_to_cpu(rr.node_crc), crc);
 		return EIO;
 	}
 	if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
@@ -476,22 +492,28 @@ static int verify_xattr_ref(struct jffs2
 	    || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
 		JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
 			    "nodetype=%#04x/%#04x, totlen=%u/%zu\n",
-			    ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
+			    offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
 			    je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
 			    je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
 		return EIO;
 	}
 	ref->ino = je32_to_cpu(rr.ino);
 	ref->xid = je32_to_cpu(rr.xid);
-
-	/* fixup superblock/eraseblock info */
-	jeb = &c->blocks[ref_offset(ref->node) / c->sector_size];
-	totlen = PAD(sizeof(rr));
+	ref->xseqno = je32_to_cpu(rr.xseqno);
+	if (ref->xseqno > c->highest_xseqno)
+		c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER);
 
 	spin_lock(&c->erase_completion_lock);
-	c->unchecked_size -= totlen; c->used_size += totlen;
-	jeb->unchecked_size -= totlen; jeb->used_size += totlen;
-	ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE;
+ complete:
+	for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) {
+		jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+		totlen = PAD(ref_totlen(c, jeb, raw));
+		if (ref_flags(raw) == REF_UNCHECKED) {
+			c->unchecked_size -= totlen; c->used_size += totlen;
+			jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+		}
+		raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL);
+	}
 	spin_unlock(&c->erase_completion_lock);
 
 	dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
@@ -499,58 +521,12 @@ static int verify_xattr_ref(struct jffs2
 	return 0;
 }
 
-static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-	struct jffs2_raw_xref rr;
-	size_t length;
-	int rc;
-
-	if (jffs2_sum_active()) {
-		memset(&rr, 0xff, sizeof(rr));
-		rc = jffs2_flash_read(c, ref_offset(ref->node),
-				      sizeof(struct jffs2_unknown_node),
-				      &length, (char *)&rr);
-		if (rc || length != sizeof(struct jffs2_unknown_node)) {
-			JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n",
-				    rc, sizeof(struct jffs2_unknown_node),
-				    length, ref_offset(ref->node));
-		}
-		rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr),
-				       &length, (char *)&rr);
-		if (rc || length != sizeof(struct jffs2_raw_xref)) {
-			JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu at %#08x\n",
-				    rc, sizeof(rr), length, ref_offset(ref->node));
-		}
-	}
-	spin_lock(&c->erase_completion_lock);
-	ref->node->next_in_ino = NULL;
-	spin_unlock(&c->erase_completion_lock);
-	jffs2_mark_node_obsolete(c, ref->node);
-	ref->node = NULL;
-}
-
-static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
-{
-	/* must be called under down_write(xattr_sem) */
-	struct jffs2_xattr_datum *xd;
-
-	BUG_ON(!ref->node);
-	delete_xattr_ref_node(c, ref);
-
-	xd = ref->xd;
-	xd->refcnt--;
-	if (!xd->refcnt)
-		delete_xattr_datum(c, xd);
-	jffs2_free_xattr_ref(ref);
-}
-
 static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
 	/* must be called under down_write(xattr_sem) */
-	struct jffs2_raw_node_ref *raw;
 	struct jffs2_raw_xref rr;
 	size_t length;
-	uint32_t phys_ofs = write_ofs(c);
+	uint32_t xseqno, phys_ofs = write_ofs(c);
 	int ret;
 
 	rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -558,8 +534,16 @@ static int save_xattr_ref(struct jffs2_s
 	rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
 	rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
 
-	rr.ino = cpu_to_je32(ref->ic->ino);
-	rr.xid = cpu_to_je32(ref->xd->xid);
+	xseqno = (c->highest_xseqno += 2);
+	if (is_xattr_ref_dead(ref)) {
+		xseqno |= XREF_DELETE_MARKER;
+		rr.ino = cpu_to_je32(ref->ino);
+		rr.xid = cpu_to_je32(ref->xid);
+	} else {
+		rr.ino = cpu_to_je32(ref->ic->ino);
+		rr.xid = cpu_to_je32(ref->xd->xid);
+	}
+	rr.xseqno = cpu_to_je32(xseqno);
 	rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
 
 	ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
@@ -572,12 +556,9 @@ static int save_xattr_ref(struct jffs2_s
 
 		return ret;
 	}
-
-	raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL);
-	/* FIXME */ raw->next_in_ino = (void *)ref;
-	if (ref->node)
-		delete_xattr_ref_node(c, ref);
-	ref->node = raw;
+	/* success */
+	ref->xseqno = xseqno;
+	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref);
 
 	dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
 
@@ -610,22 +591,116 @@ static struct jffs2_xattr_ref *create_xa
 	return ref; /* success */
 }
 
+static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+	/* must be called under down_write(xattr_sem) */
+	struct jffs2_xattr_datum *xd;
+
+	set_xattr_ref_dead(ref);
+	xd = ref->xd;
+	ref->ino = ref->ic->ino;
+	ref->xid = ref->xd->xid;
+	spin_lock(&c->erase_completion_lock);
+	ref->next = c->xref_dead_list;
+	c->xref_dead_list = ref;
+	spin_unlock(&c->erase_completion_lock);
+
+	JFFS2_NOTICE("xref(ino=%u, xid=%u) was removed without delete marker. "
+		     "An orphan xref may be detected on next mounting.\n",
+		     ref->ino, ref->xid);
+
+	if (!--xd->refcnt)
+		delete_xattr_datum_delay(c, xd);
+}
+
+static int delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, int enforce)
+{
+	/* must be called under jffs2_reserve_space() and down_write(xattr_sem) */
+	struct jffs2_inode_cache *ic;
+	struct jffs2_xattr_datum *xd;
+	uint32_t length;
+	int rc;
+
+	set_xattr_ref_dead(ref);
+	ic = ref->ic;
+	xd = ref->xd;
+	ref->ino = ic->ino;
+	ref->xid = xd->xid;
+	rc = save_xattr_ref(c, ref);
+	if (rc) {
+		if (!enforce) {
+			clr_xattr_ref_dead(ref);
+			ref->ic = ic;
+			ref->xd = xd;
+			return rc;
+		}
+		JFFS2_WARNING("could not write delete marker of xref(ino=%u, xid=%u). "
+			      "An orphan xref may be detected on next mounting.\n",
+			      ref->ic->ino, ref->xd->xid);
+	}
+	spin_lock(&c->erase_completion_lock);
+	ref->next = c->xref_dead_list;
+	c->xref_dead_list = ref;
+	spin_unlock(&c->erase_completion_lock);
+
+	xd->refcnt--;
+	if (xd->refcnt)
+		return 0;
+
+	/* delete xdatum */
+	unload_xattr_datum(c, xd);
+	up_write(&c->xattr_sem);
+	jffs2_complete_reservation(c);
+
+	rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xattr)), &length,
+				 ALLOC_DELETION, JFFS2_SUMMARY_XATTR_SIZE);
+	if (rc) {
+		down(&c->alloc_sem);
+		down_write(&c->xattr_sem);
+		delete_xattr_datum_delay(c, xd);
+	} else {
+		down_write(&c->xattr_sem);
+		delete_xattr_datum(c, xd);
+	}
+	return 0;
+}
+
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
 {
 	/* It's called from jffs2_clear_inode() on inode removing.
 	   When an inode with XATTR is removed, those XATTRs must be removed. */
-	struct jffs2_xattr_ref *ref, *_ref;
+	struct jffs2_xattr_ref *ref;
+	uint32_t length;
+	int rc, retry;
 
 	if (!ic || ic->nlink > 0)
 		return;
 
+	down_read(&c->xattr_sem);
+	if (!ic->xref) {
+		up_read(&c->xattr_sem);
+		return;
+	}
+	up_read(&c->xattr_sem);
+ retry:
+	rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xref)), &length,
+				 ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE);
 	down_write(&c->xattr_sem);
-	for (ref = ic->xref; ref; ref = _ref) {
-		_ref = ref->next;
-		delete_xattr_ref(c, ref);
+	if (ic->xref) {
+		ref = ic->xref;
+		ic->xref = ref->next;
+		if (rc) {
+			delete_xattr_ref_delay(c, ref);
+		} else {
+			delete_xattr_ref(c, ref, 1);
+		}
 	}
-	ic->xref = NULL;
+	retry = ic->xref ? 1 : 0;
 	up_write(&c->xattr_sem);
+	if (!rc)
+		jffs2_complete_reservation(c);
+	if (retry)
+		goto retry;
 }
 
 void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
@@ -655,7 +730,7 @@ static int check_xattr_ref_inode(struct 
 	 * duplicate name/value pairs. If duplicate name/value pair would be found,
 	 * one will be removed.
 	 */
-	struct jffs2_xattr_ref *ref, *cmp, **pref;
+	struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp;
 	int rc = 0;
 
 	if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
@@ -668,27 +743,32 @@ static int check_xattr_ref_inode(struct 
 			rc = load_xattr_datum(c, ref->xd);
 			if (unlikely(rc > 0)) {
 				*pref = ref->next;
-				delete_xattr_ref(c, ref);
+				delete_xattr_ref_delay(c, ref);
 				goto retry;
 			} else if (unlikely(rc < 0))
 				goto out;
 		}
-		for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) {
+		for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) {
 			if (!cmp->xd->xname) {
 				ref->xd->flags |= JFFS2_XFLAGS_BIND;
 				rc = load_xattr_datum(c, cmp->xd);
 				ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
 				if (unlikely(rc > 0)) {
-					*pref = cmp->next;
-					delete_xattr_ref(c, cmp);
+					*pcmp = cmp->next;
+					delete_xattr_ref_delay(c, cmp);
 					goto retry;
 				} else if (unlikely(rc < 0))
 					goto out;
 			}
 			if (ref->xd->xprefix == cmp->xd->xprefix
 			    && !strcmp(ref->xd->xname, cmp->xd->xname)) {
-				*pref = cmp->next;
-				delete_xattr_ref(c, cmp);
+				if (ref->xseqno > cmp->xseqno) {
+					*pcmp = cmp->next;
+					delete_xattr_ref_delay(c, cmp);
+				} else {
+					*pref = ref->next;
+					delete_xattr_ref_delay(c, ref);
+				}
 				goto retry;
 			}
 		}
@@ -719,9 +799,13 @@ void jffs2_init_xattr_subsystem(struct j
 	for (i=0; i < XATTRINDEX_HASHSIZE; i++)
 		INIT_LIST_HEAD(&c->xattrindex[i]);
 	INIT_LIST_HEAD(&c->xattr_unchecked);
+	INIT_LIST_HEAD(&c->xattr_dead_list);
+	c->xref_dead_list = NULL;
 	c->xref_temp = NULL;
 
 	init_rwsem(&c->xattr_sem);
+	c->highest_xid = 0;
+	c->highest_xseqno = 0;
 	c->xdatum_mem_usage = 0;
 	c->xdatum_mem_threshold = 32 * 1024;	/* Default 32KB */
 }
@@ -751,7 +835,11 @@ void jffs2_clear_xattr_subsystem(struct 
 		_ref = ref->next;
 		jffs2_free_xattr_ref(ref);
 	}
-	c->xref_temp = NULL;
+
+	for (ref=c->xref_dead_list; ref; ref = _ref) {
+		_ref = ref->next;
+		jffs2_free_xattr_ref(ref);
+	}
 
 	for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
 		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
@@ -761,64 +849,120 @@ void jffs2_clear_xattr_subsystem(struct 
 			jffs2_free_xattr_datum(xd);
 		}
 	}
+
+	list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) {
+		list_del(&xd->xindex);
+		jffs2_free_xattr_datum(xd);
+	}
 }
 
+#define XREF_TMPHASH_SIZE	(128)
 void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
 {
 	struct jffs2_xattr_ref *ref, *_ref;
+	struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE];
 	struct jffs2_xattr_datum *xd, *_xd;
 	struct jffs2_inode_cache *ic;
-	int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
+	struct jffs2_raw_node_ref *raw;
+	int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0;
 
 	BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
+	/* Phase.1 : Drop dead xdatum */
+	for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
+		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+			BUG_ON(xd->node == (void *)xd);
+			if (is_xattr_datum_dead(xd)) {
+				list_del_init(&xd->xindex);
+				list_add(&xd->xindex, &c->xattr_unchecked);
+			}
+		}
+	}
 
-	/* Phase.1 */
+	/* Phase.2 : Merge same xref */
+	for (i=0; i < XREF_TMPHASH_SIZE; i++)
+		xref_tmphash[i] = NULL;
 	for (ref=c->xref_temp; ref; ref=_ref) {
+		struct jffs2_xattr_ref *tmp;
+
 		_ref = ref->next;
-		/* checking REF_UNCHECKED nodes */
 		if (ref_flags(ref->node) != REF_PRISTINE) {
 			if (verify_xattr_ref(c, ref)) {
-				delete_xattr_ref_node(c, ref);
+				BUG_ON(ref->node->next_in_ino != (void *)ref);
+				ref->node->next_in_ino = NULL;
+				jffs2_mark_node_obsolete(c, ref->node);
 				jffs2_free_xattr_ref(ref);
 				continue;
 			}
 		}
-		/* At this point, ref->xid and ref->ino contain XID and inode number.
-		   ref->xd and ref->ic are not valid yet. */
-		xd = jffs2_find_xattr_datum(c, ref->xid);
-		ic = jffs2_get_ino_cache(c, ref->ino);
-		if (!xd || !ic) {
-			if (ref_flags(ref->node) != REF_UNCHECKED)
-				JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
-					      ref->ino, ref->xid);
-			delete_xattr_ref_node(c, ref);
+
+		i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE;
+		for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) {
+			if (tmp->ino == ref->ino && tmp->xid == ref->xid)
+				break;
+		}
+		if (tmp) {
+			raw = ref->node;
+			if (ref->xseqno > tmp->xseqno) {
+				tmp->xseqno = ref->xseqno;
+				raw->next_in_ino = tmp->node;
+				tmp->node = raw;
+			} else {
+				raw->next_in_ino = tmp->node->next_in_ino;
+				tmp->node->next_in_ino = raw;
+			}
 			jffs2_free_xattr_ref(ref);
 			continue;
+		} else {
+			ref->next = xref_tmphash[i];
+			xref_tmphash[i] = ref;
 		}
-		ref->xd = xd;
-		ref->ic = ic;
-		xd->refcnt++;
-		ref->next = ic->xref;
-		ic->xref = ref;
-		xref_count++;
 	}
 	c->xref_temp = NULL;
-	/* After this, ref->xid/ino are NEVER used. */
 
-	/* Phase.2 */
+	/* Phase.3 : Bind xref with inode_cache and xattr_datum */
+	for (i=0; i < XREF_TMPHASH_SIZE; i++) {
+		for (ref=xref_tmphash[i]; ref; ref=_ref) {
+			_ref = ref->next;
+			if (is_xattr_ref_dead(ref)) {
+				ref->next = c->xref_dead_list;
+				c->xref_dead_list = ref;
+				continue;
+			}
+			/* At this point, ref->xid and ref->ino contain XID and inode number.
+			   ref->xd and ref->ic are not valid yet. */
+			xd = jffs2_find_xattr_datum(c, ref->xid);
+			ic = jffs2_get_ino_cache(c, ref->ino);
+			if (!xd || !ic) {
+				JFFS2_WARNING("xref(ino=%u, xid=%u, xseqno=%u) is orphan. \n",
+					      ref->ino, ref->xid, ref->xseqno);
+				set_xattr_ref_dead(ref);
+				ref->next = c->xref_dead_list;
+				c->xref_dead_list = ref;
+				continue;
+			}
+			ref->xd = xd;
+			ref->ic = ic;
+			xd->refcnt++;
+			ref->next = ic->xref;
+			ic->xref = ref;
+			xref_count++;
+		}
+	}
+
+	/* Phase.4 : Link unchecked xdatum to xattr_unchecked list */
 	for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
 		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
 			list_del_init(&xd->xindex);
 			if (!xd->refcnt) {
-				if (ref_flags(xd->node) != REF_UNCHECKED)
-					JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
-						      xd->xid, xd->version, ref_offset(xd->node));
-				delete_xattr_datum(c, xd);
+				JFFS2_WARNING("orphan xdatum(xid=%u, version=%u)\n",
+					      xd->xid, xd->version);
+				set_xattr_datum_dead(xd);
+				list_add(&xd->xindex, &c->xattr_unchecked);
 				continue;
 			}
-			if (ref_flags(xd->node) != REF_PRISTINE) {
-				dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
-					  xd->xid, ref_offset(xd->node));
+			if (is_xattr_datum_unchecked(c, xd)) {
+				dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n",
+					  xd->xid, xd->version);
 				list_add(&xd->xindex, &c->xattr_unchecked);
 				xdatum_unchecked_count++;
 			}
@@ -833,28 +977,18 @@ void jffs2_build_xattr_subsystem(struct 
 struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
 						  uint32_t xid, uint32_t version)
 {
-	struct jffs2_xattr_datum *xd, *_xd;
+	struct jffs2_xattr_datum *xd;
 
-	_xd = jffs2_find_xattr_datum(c, xid);
-	if (_xd) {
-		dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
-			  xid, version, _xd->version, ref_offset(_xd->node));
-		if (version < _xd->version)
-			return ERR_PTR(-EEXIST);
-	}
-	xd = jffs2_alloc_xattr_datum();
-	if (!xd)
-		return ERR_PTR(-ENOMEM);
-	xd->xid = xid;
-	xd->version = version;
-	if (xd->xid > c->highest_xid)
-		c->highest_xid = xd->xid;
-	list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
-
-	if (_xd) {
-		list_del_init(&_xd->xindex);
-		delete_xattr_datum_node(c, _xd);
-		jffs2_free_xattr_datum(_xd);
+	xd = jffs2_find_xattr_datum(c, xid);
+	if (!xd) {
+		xd = jffs2_alloc_xattr_datum();
+		if (!xd)
+			return ERR_PTR(-ENOMEM);
+		xd->xid = xid;
+		xd->version = version;
+		if (xd->xid > c->highest_xid)
+			c->highest_xid = xd->xid;
+		list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
 	}
 	return xd;
 }
@@ -945,7 +1079,7 @@ ssize_t jffs2_listxattr(struct dentry *d
 				rc = load_xattr_datum(c, xd);
 				if (unlikely(rc > 0)) {
 					*pref = ref->next;
-					delete_xattr_ref(c, ref);
+					delete_xattr_ref_delay(c, ref);
 					goto retry;
 				} else if (unlikely(rc < 0))
 					goto out;
@@ -1006,7 +1140,7 @@ int do_jffs2_getxattr(struct inode *inod
 				rc = load_xattr_datum(c, xd);
 				if (unlikely(rc > 0)) {
 					*pref = ref->next;
-					delete_xattr_ref(c, ref);
+					delete_xattr_ref_delay(c, ref);
 					goto retry;
 				} else if (unlikely(rc < 0)) {
 					goto out;
@@ -1069,7 +1203,7 @@ int do_jffs2_setxattr(struct inode *inod
 			rc = load_xattr_datum(c, xd);
 			if (unlikely(rc > 0)) {
 				*pref = ref->next;
-				delete_xattr_ref(c, ref);
+				delete_xattr_ref_delay(c, ref);
 				goto retry;
 			} else if (unlikely(rc < 0))
 				goto out;
@@ -1081,8 +1215,7 @@ int do_jffs2_setxattr(struct inode *inod
 			}
 			if (!buffer) {
 				*pref = ref->next;
-				delete_xattr_ref(c, ref);
-				rc = 0;
+				rc = delete_xattr_ref(c, ref, 0);
 				goto out;
 			}
 			goto found;
@@ -1094,7 +1227,7 @@ int do_jffs2_setxattr(struct inode *inod
 		goto out;
 	}
 	if (!buffer) {
-		rc = -EINVAL;
+		rc = -ENODATA;
 		goto out;
 	}
  found:
@@ -1110,16 +1243,15 @@ int do_jffs2_setxattr(struct inode *inod
 	request = PAD(sizeof(struct jffs2_raw_xref));
 	rc = jffs2_reserve_space(c, request, &length,
 				 ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
+	down_write(&c->xattr_sem);
 	if (rc) {
 		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-		down_write(&c->xattr_sem);
 		xd->refcnt--;
 		if (!xd->refcnt)
-			delete_xattr_datum(c, xd);
+			delete_xattr_datum_delay(c, xd);
 		up_write(&c->xattr_sem);
 		return rc;
 	}
-	down_write(&c->xattr_sem);
 	if (ref)
 		*pref = ref->next;
 	newref = create_xattr_ref(c, ic, xd);
@@ -1131,9 +1263,21 @@ int do_jffs2_setxattr(struct inode *inod
 		rc = PTR_ERR(newref);
 		xd->refcnt--;
 		if (!xd->refcnt)
-			delete_xattr_datum(c, xd);
+			delete_xattr_datum_delay(c, xd);
 	} else if (ref) {
-		delete_xattr_ref(c, ref);
+		up_write(&c->xattr_sem);
+		jffs2_complete_reservation(c);
+
+		rc = jffs2_reserve_space(c, request, &length,
+					 ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE);
+		down_write(&c->xattr_sem);
+		if (rc) {
+			JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
+			delete_xattr_ref_delay(c, ref);
+			up_write(&c->xattr_sem);
+			return 0;
+		}
+		delete_xattr_ref(c, ref, 1);
 	}
  out:
 	up_write(&c->xattr_sem);
@@ -1142,38 +1286,37 @@ int do_jffs2_setxattr(struct inode *inod
 }
 
 /* -------- garbage collector functions -------------
- * jffs2_garbage_collect_xattr_datum(c, xd)
+ * jffs2_garbage_collect_xattr_datum(c, xd, raw)
  *   is used to move xdatum into new node.
- * jffs2_garbage_collect_xattr_ref(c, ref)
+ * jffs2_garbage_collect_xattr_ref(c, ref, raw)
  *   is used to move xref into new node.
  * jffs2_verify_xattr(c)
  *   is used to call do_verify_xattr_datum() before garbage collecting.
  * -------------------------------------------------- */
-int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+				      struct jffs2_raw_node_ref *raw)
 {
 	uint32_t totlen, length, old_ofs;
-	int rc = -EINVAL;
+	int rc = 0;
 
 	down_write(&c->xattr_sem);
-	BUG_ON(!xd->node);
+	if (xd->node != raw)
+		goto out;
+	if (is_xattr_datum_dead(xd) && (raw->next_in_ino == (void *)xd))
+		goto out;
 
 	old_ofs = ref_offset(xd->node);
 	totlen = ref_totlen(c, c->gcblock, xd->node);
-	if (totlen < sizeof(struct jffs2_raw_xattr))
-		goto out;
 
-	if (!xd->xname) {
+	if (!is_xattr_datum_dead(xd)) {
 		rc = load_xattr_datum(c, xd);
-		if (unlikely(rc > 0)) {
-			delete_xattr_datum_node(c, xd);
-			rc = 0;
-			goto out;
-		} else if (unlikely(rc < 0))
+		if (unlikely(rc < 0))
 			goto out;
 	}
+
 	rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE);
-	if (rc || length < totlen) {
-		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
+	if (rc) {
+		JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen);
 		rc = rc ? rc : -EBADFD;
 		goto out;
 	}
@@ -1182,27 +1325,33 @@ int jffs2_garbage_collect_xattr_datum(st
 		dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
 			  xd->xid, xd->version, old_ofs, ref_offset(xd->node));
  out:
+	if (!rc)
+		jffs2_mark_node_obsolete(c, raw);
 	up_write(&c->xattr_sem);
 	return rc;
 }
 
 
-int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+				    struct jffs2_raw_node_ref *raw)
 {
 	uint32_t totlen, length, old_ofs;
-	int rc = -EINVAL;
+	int rc = 0;
 
 	down_write(&c->xattr_sem);
 	BUG_ON(!ref->node);
 
+	if (ref->node != raw)
+		goto out;
+	if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref))
+		goto out;
+
 	old_ofs = ref_offset(ref->node);
 	totlen = ref_totlen(c, c->gcblock, ref->node);
-	if (totlen != sizeof(struct jffs2_raw_xref))
-		goto out;
 
 	rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE);
-	if (rc || length < totlen) {
-		JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
+	if (rc) {
+		JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
 			      __FUNCTION__, rc, totlen);
 		rc = rc ? rc : -EBADFD;
 		goto out;
@@ -1212,6 +1361,8 @@ int jffs2_garbage_collect_xattr_ref(stru
 		dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
 			  ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
  out:
+	if (!rc)
+		jffs2_mark_node_obsolete(c, raw);
 	up_write(&c->xattr_sem);
 	return rc;
 }
@@ -1219,20 +1370,59 @@ int jffs2_garbage_collect_xattr_ref(stru
 int jffs2_verify_xattr(struct jffs2_sb_info *c)
 {
 	struct jffs2_xattr_datum *xd, *_xd;
+	struct jffs2_eraseblock *jeb;
+	struct jffs2_raw_node_ref *raw;
+	uint32_t totlen;
 	int rc;
 
 	down_write(&c->xattr_sem);
 	list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
 		rc = do_verify_xattr_datum(c, xd);
-		if (rc == 0) {
-			list_del_init(&xd->xindex);
-			break;
-		} else if (rc > 0) {
-			list_del_init(&xd->xindex);
-			delete_xattr_datum_node(c, xd);
+		if (rc < 0)
+			continue;
+		list_del_init(&xd->xindex);
+		spin_lock(&c->erase_completion_lock);
+		for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) {
+			if (ref_flags(raw) != REF_UNCHECKED)
+				continue;
+			jeb = &c->blocks[ref_offset(raw) / c->sector_size];
+			totlen = PAD(ref_totlen(c, jeb, raw));
+			c->unchecked_size -= totlen; c->used_size += totlen;
+			jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+			raw->flash_offset = ref_offset(raw)
+				| ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL);
 		}
+		if (is_xattr_datum_dead(xd))
+			list_add(&xd->xindex, &c->xattr_dead_list);
+		spin_unlock(&c->erase_completion_lock);
 	}
 	up_write(&c->xattr_sem);
-
 	return list_empty(&c->xattr_unchecked) ? 1 : 0;
 }
+
+void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+	/* must be called under spin_lock(&c->erase_completion_lock) */
+	if (xd->node != (void *)xd)
+		return;
+
+	list_del(&xd->xindex);
+	jffs2_free_xattr_datum(xd);
+}
+
+void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+	/* must be called under spin_lock(&c->erase_completion_lock) */
+	struct jffs2_xattr_ref *tmp, **ptmp;
+
+	if (ref->node != (void *)ref)
+		return;
+
+	for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) {
+		if (ref == tmp) {
+			*ptmp = tmp->next;
+			jffs2_free_xattr_ref(ref);
+			break;
+		}
+	}
+}
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 2c19985..06ab7b8 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -16,6 +16,7 @@ #include <linux/list.h>
 
 #define JFFS2_XFLAGS_HOT	(0x01)	/* This datum is HOT */
 #define JFFS2_XFLAGS_BIND	(0x02)	/* This datum is not reclaimed */
+#define JFFS2_XFLAGS_INVALID	(0x80)	/* This datum contains crc error */
 
 struct jffs2_xattr_datum
 {
@@ -23,7 +24,7 @@ struct jffs2_xattr_datum
 	struct jffs2_raw_node_ref *node;
 	uint8_t class;
 	uint8_t flags;
-	uint16_t xprefix;			/* see JFFS2_XATTR_PREFIX_* */
+	uint16_t xprefix;		/* see JFFS2_XATTR_PREFIX_* */
 
 	struct list_head xindex;	/* chained from c->xattrindex[n] */
 	uint32_t refcnt;		/* # of xattr_ref refers this */
@@ -47,6 +48,7 @@ struct jffs2_xattr_ref
 	uint8_t flags;		/* Currently unused */
 	u16 unused;
 
+	uint32_t xseqno;
 	union {
 		struct jffs2_inode_cache *ic;	/* reference to jffs2_inode_cache */
 		uint32_t ino;			/* only used in scanning/building  */
@@ -58,6 +60,34 @@ struct jffs2_xattr_ref
 	struct jffs2_xattr_ref *next;		/* chained from ic->xref_list */
 };
 
+#define XDATUM_DELETE_MARKER	(0xffffffff)
+#define XREF_DELETE_MARKER	(0x00000001)
+static inline int is_xattr_datum_dead(struct jffs2_xattr_datum *xd)
+{
+	return (xd->version == XDATUM_DELETE_MARKER);
+}
+
+static inline void set_xattr_datum_dead(struct jffs2_xattr_datum *xd)
+{
+	xd->version = XDATUM_DELETE_MARKER;
+}
+
+static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref)
+{
+	return ((ref->xseqno & XREF_DELETE_MARKER) != 0);
+}
+
+static inline void set_xattr_ref_dead(struct jffs2_xattr_ref *ref)
+{
+	ref->xseqno |= XREF_DELETE_MARKER;
+}
+
+static inline void clr_xattr_ref_dead(struct jffs2_xattr_ref *ref)
+{
+	ref->xseqno &= ~XREF_DELETE_MARKER;
+}
+
+
 #ifdef CONFIG_JFFS2_FS_XATTR
 
 extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
@@ -70,9 +100,13 @@ extern struct jffs2_xattr_datum *jffs2_s
 extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 
-extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
-extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
+extern int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
+					     struct jffs2_raw_node_ref *raw);
+extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
+					   struct jffs2_raw_node_ref *raw);
 extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
+extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
+extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
 
 extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
 			     char *buffer, size_t size);
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index c6f7066..c9c7607 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -186,6 +186,7 @@ struct jffs2_raw_xref
 	jint32_t hdr_crc;
 	jint32_t ino;		/* inode number */
 	jint32_t xid;		/* XATTR identifier number */
+	jint32_t xseqno;	/* xref sequencial number */
 	jint32_t node_crc;
 } __attribute__((packed));
 


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:02 +0100
Subject: [JFFS2][XATTR] Fix memory leak with jffs2_xattr_ref
Message-ID: <E1FvFxu-0003Me-Is@pentafluge.infradead.org>

Commit:     355ed4e141203fd7266ef9d90d57be0c61bd1aa4
Parent:     8a13695cbe4e8311b363f9bd25162904b984ca74
commit 355ed4e141203fd7266ef9d90d57be0c61bd1aa4
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sat Jun 24 09:15:36 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:18:30 2006 +0100

    [JFFS2][XATTR] Fix memory leak with jffs2_xattr_ref
    
    If xattr_ref is associated with an orphan inode_cache
    on filesystem mounting, those xattr_refs are not
    released even if this inode_cache is released.
    
    This patch enables to call jffs2_xattr_delete_inode()
    for such a irregular inode_cachde too.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/fs.c        |    2 --
 fs/jffs2/gc.c        |    1 +
 fs/jffs2/nodelist.c  |    3 +++
 fs/jffs2/readinode.c |    1 +
 4 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 2900ec3..97caa77 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -227,8 +227,6 @@ void jffs2_clear_inode (struct inode *in
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
-
-	jffs2_xattr_delete_inode(c, f->inocache);
 	jffs2_do_clear_inode(c, f);
 }
 
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index f59b147..daff334 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -165,6 +165,7 @@ int jffs2_garbage_collect_pass(struct jf
 			D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
 				  ic->ino));
 			spin_unlock(&c->inocache_lock);
+			jffs2_xattr_delete_inode(c, ic);
 			continue;
 		}
 		switch(ic->state) {
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 927dfe4..7675b33 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -906,6 +906,9 @@ void jffs2_del_ino_cache(struct jffs2_sb
 {
 	struct jffs2_inode_cache **prev;
 
+#ifdef CONFIG_JFFS2_FS_XATTR
+	BUG_ON(old->xref);
+#endif
 	dbg_inocache("del %p (ino #%u)\n", old, old->ino);
 	spin_lock(&c->inocache_lock);
 
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 5fec012..cc18992 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -968,6 +968,7 @@ void jffs2_do_clear_inode(struct jffs2_s
 	struct jffs2_full_dirent *fd, *fds;
 	int deleted;
 
+	jffs2_xattr_delete_inode(c, f->inocache);
 	down(&f->sem);
 	deleted = f->inocache && !f->inocache->nlink;
 


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:02 +0100
Subject: [JFFS2][XATTR] Fix ACL bug when updating null xattr by null ACL.
Message-ID: <E1FvFxu-0003Lz-2F@pentafluge.infradead.org>

Commit:     a1ae76e96a18edf4b8a4d4e102762060c26d1c6a
Parent:     c9f700f840bd481b3e01fcad1ba8da01794a6726
commit a1ae76e96a18edf4b8a4d4e102762060c26d1c6a
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sun Jun 11 10:45:22 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:17:04 2006 +0100

    [JFFS2][XATTR] Fix ACL bug when updating null xattr by null ACL.
    
    This patch enable to handle the case when updating null xattr
    by null ACL.
    
    When we try to set NULL into NULL xattr, xattr subsystem returns
    -ENODATA. This patch enables to handle this error code.
    
    [2/3] jffs2-xattr-v6-02-fix_posixacl_bug.patch
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/acl.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 320dd48..9c2077e 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -267,6 +267,8 @@ static int jffs2_set_acl(struct inode *i
 	}
 
 	rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
+	if (!value && rc == -ENODATA)
+		rc = 0;
 	if (value)
 		kfree(value);
 	if (!rc) {


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:02 +0100
Subject: [JFFS2][XATTR] rid unnecessary writing of delete marker.
Message-ID: <E1FvFxu-0003MH-9c@pentafluge.infradead.org>

Commit:     8a13695cbe4e8311b363f9bd25162904b984ca74
Parent:     a1ae76e96a18edf4b8a4d4e102762060c26d1c6a
commit 8a13695cbe4e8311b363f9bd25162904b984ca74
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sat Jun 24 09:14:13 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:18:02 2006 +0100

    [JFFS2][XATTR] rid unnecessary writing of delete marker.
    
    In the followinf situation, an explicit delete marker is not
    necessary, because we can certainlly detect those obsolete
    xattr_datum or xattr_ref on next mounting.
    
    - When to delete xattr_datum node.
    - When to delete xattr_ref node on removing inode.
    - When to delete xattr_ref node on updating xattr.
    
    This patch rids writing delete marker in those situations.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/scan.c  |    6 -
 fs/jffs2/xattr.c |  303 ++++++++++++++++++------------------------------------
 fs/jffs2/xattr.h |   23 ----
 3 files changed, 105 insertions(+), 227 deletions(-)

diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 79638f5..2bfdc33 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -332,10 +332,8 @@ static int jffs2_scan_xattr_node(struct 
 	xid = je32_to_cpu(rx->xid);
 	version = je32_to_cpu(rx->version);
 
-	totlen = sizeof(struct jffs2_raw_xattr);
-	if (version != XDATUM_DELETE_MARKER)
-		totlen += rx->name_len + 1 + je16_to_cpu(rx->value_len);
-	totlen = PAD(totlen);
+	totlen = PAD(sizeof(struct jffs2_raw_xattr)
+			+ rx->name_len + 1 + je16_to_cpu(rx->value_len));
 	if (totlen != je32_to_cpu(rx->totlen)) {
 		JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
 			      ofs, je32_to_cpu(rx->totlen), totlen);
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 03871ab..7622f79 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -50,12 +50,9 @@ #include "nodelist.h"
  *   is used to write xdatum to medium. xd->version will be incremented.
  * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
  *   is used to create new xdatum and write to medium.
- * delete_xattr_datum_delay(c, xd)
- *   is used to delete a xdatum without 'delete marker'. It has a possibility to detect
- *   orphan xdatum on next mounting.
  * delete_xattr_datum(c, xd)
- *   is used to delete a xdatum with 'delete marker'. Calling jffs2_reserve_space() is
- *   necessary before this function.
+ *   is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows
+ *   GC to reclaim those physical nodes.
  * -------------------------------------------------- */
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
@@ -154,10 +151,7 @@ static int do_verify_xattr_datum(struct 
 		xd->flags |= JFFS2_XFLAGS_INVALID;
 		return EIO;
 	}
-	totlen = sizeof(rx);
-	if (xd->version != XDATUM_DELETE_MARKER)
-		totlen += rx.name_len + 1 + je16_to_cpu(rx.value_len);
-	totlen = PAD(totlen);
+	totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
 	if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
 	    || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR
 	    || je32_to_cpu(rx.totlen) != totlen
@@ -268,6 +262,7 @@ static int load_xattr_datum(struct jffs2
 	 */
 	int rc = 0;
 
+	BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD);
 	if (xd->xname)
 		return 0;
 	if (xd->flags & JFFS2_XFLAGS_INVALID)
@@ -285,20 +280,18 @@ static int save_xattr_datum(struct jffs2
 	struct jffs2_raw_xattr rx;
 	struct kvec vecs[2];
 	size_t length;
-	int rc, totlen, nvecs = 1;
+	int rc, totlen;
 	uint32_t phys_ofs = write_ofs(c);
 
-	BUG_ON(is_xattr_datum_dead(xd) || (xd->flags & JFFS2_XFLAGS_INVALID)
-	       ? !!xd->xname : !xd->xname);
+	BUG_ON(!xd->xname);
+	BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID));
 
 	vecs[0].iov_base = &rx;
-	vecs[0].iov_len = totlen = sizeof(rx);
-	if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) {
-		nvecs++;
-		vecs[1].iov_base = xd->xname;
-		vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
-		totlen += vecs[1].iov_len;
-	}
+	vecs[0].iov_len = sizeof(rx);
+	vecs[1].iov_base = xd->xname;
+	vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
+	totlen = vecs[0].iov_len + vecs[1].iov_len;
+
 	/* Setup raw-xattr */
 	memset(&rx, 0, sizeof(rx));
 	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -307,18 +300,14 @@ static int save_xattr_datum(struct jffs2
 	rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
 
 	rx.xid = cpu_to_je32(xd->xid);
-	if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) {
-		rx.version = cpu_to_je32(++xd->version);
-		rx.xprefix = xd->xprefix;
-		rx.name_len = xd->name_len;
-		rx.value_len = cpu_to_je16(xd->value_len);
-		rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
-	} else {
-		rx.version = cpu_to_je32(XDATUM_DELETE_MARKER);
-	}
+	rx.version = cpu_to_je32(++xd->version);
+	rx.xprefix = xd->xprefix;
+	rx.name_len = xd->name_len;
+	rx.value_len = cpu_to_je16(xd->value_len);
+	rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
 	rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));
 
-	rc = jffs2_flash_writev(c, vecs, nvecs, phys_ofs, &length, 0);
+	rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);
 	if (rc || totlen != length) {
 		JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n",
 			      rc, totlen, length, phys_ofs);
@@ -405,53 +394,36 @@ static struct jffs2_xattr_datum *create_
 	return xd;
 }
 
-static void delete_xattr_datum_delay(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
 	BUG_ON(xd->refcnt);
 
 	unload_xattr_datum(c, xd);
-	set_xattr_datum_dead(xd);
+	xd->flags |= JFFS2_XFLAGS_DEAD;
 	spin_lock(&c->erase_completion_lock);
-	list_add(&xd->xindex, &c->xattr_dead_list);
-	spin_unlock(&c->erase_completion_lock);
-	JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. "
-		     "An orphan xdatum may be detected on next mounting.\n", xd->xid);
-}
-
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
-{
-	/* must be called under jffs2_reserve_space() and down_write(xattr_sem) */
-	int rc;
-	BUG_ON(xd->refcnt);
-
-	unload_xattr_datum(c, xd);
-	set_xattr_datum_dead(xd);	
-	rc = save_xattr_datum(c, xd);
-	if (rc) {
-		JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. "
-			     "An orphan xdatum may be detected on next mounting.\n",
-			     xd->xid);
+	if (xd->node == (void *)xd) {
+		BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
+		jffs2_free_xattr_datum(xd);
+	} else {
+		list_add(&xd->xindex, &c->xattr_dead_list);
 	}
-	spin_lock(&c->erase_completion_lock);
-	list_add(&xd->xindex, &c->xattr_dead_list);
 	spin_unlock(&c->erase_completion_lock);
+	dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version);
 }
 
 /* -------- xref related functions ------------------
  * verify_xattr_ref(c, ref)
  *   is used to load xref information from medium. Because summary data does not
  *   contain xid/ino, it's necessary to verify once while mounting process.
- * delete_xattr_ref_node(c, ref)
- *   is used to delete a jffs2 node is dominated by xref. When EBS is enabled,
- *   it overwrites the obsolete node by myself. 
- * delete_xattr_ref(c, ref)
- *   is used to delete jffs2_xattr_ref object. If the reference counter of xdatum
- *   is refered by this xref become 0, delete_xattr_datum() is called later.
  * save_xattr_ref(c, ref)
- *   is used to write xref to medium.
+ *   is used to write xref to medium. If delete marker is marked, it write
+ *   a delete marker of xref into medium.
  * create_xattr_ref(c, ic, xd)
  *   is used to create a new xref and write to medium.
+ * delete_xattr_ref(c, ref)
+ *   is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER,
+ *   and allows GC to reclaim those physical nodes.
  * jffs2_xattr_delete_inode(c, ic)
  *   is called to remove xrefs related to obsolete inode when inode is unlinked.
  * jffs2_xattr_free_inode(c, ic)
@@ -591,13 +563,13 @@ static struct jffs2_xattr_ref *create_xa
 	return ref; /* success */
 }
 
-static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
 {
 	/* must be called under down_write(xattr_sem) */
 	struct jffs2_xattr_datum *xd;
 
-	set_xattr_ref_dead(ref);
 	xd = ref->xd;
+	ref->xseqno |= XREF_DELETE_MARKER;
 	ref->ino = ref->ic->ino;
 	ref->xid = ref->xd->xid;
 	spin_lock(&c->erase_completion_lock);
@@ -605,102 +577,29 @@ static void delete_xattr_ref_delay(struc
 	c->xref_dead_list = ref;
 	spin_unlock(&c->erase_completion_lock);
 
-	JFFS2_NOTICE("xref(ino=%u, xid=%u) was removed without delete marker. "
-		     "An orphan xref may be detected on next mounting.\n",
-		     ref->ino, ref->xid);
+	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
+		  ref->ino, ref->xid, ref->xseqno);
 
 	if (!--xd->refcnt)
-		delete_xattr_datum_delay(c, xd);
-}
-
-static int delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, int enforce)
-{
-	/* must be called under jffs2_reserve_space() and down_write(xattr_sem) */
-	struct jffs2_inode_cache *ic;
-	struct jffs2_xattr_datum *xd;
-	uint32_t length;
-	int rc;
-
-	set_xattr_ref_dead(ref);
-	ic = ref->ic;
-	xd = ref->xd;
-	ref->ino = ic->ino;
-	ref->xid = xd->xid;
-	rc = save_xattr_ref(c, ref);
-	if (rc) {
-		if (!enforce) {
-			clr_xattr_ref_dead(ref);
-			ref->ic = ic;
-			ref->xd = xd;
-			return rc;
-		}
-		JFFS2_WARNING("could not write delete marker of xref(ino=%u, xid=%u). "
-			      "An orphan xref may be detected on next mounting.\n",
-			      ref->ic->ino, ref->xd->xid);
-	}
-	spin_lock(&c->erase_completion_lock);
-	ref->next = c->xref_dead_list;
-	c->xref_dead_list = ref;
-	spin_unlock(&c->erase_completion_lock);
-
-	xd->refcnt--;
-	if (xd->refcnt)
-		return 0;
-
-	/* delete xdatum */
-	unload_xattr_datum(c, xd);
-	up_write(&c->xattr_sem);
-	jffs2_complete_reservation(c);
-
-	rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xattr)), &length,
-				 ALLOC_DELETION, JFFS2_SUMMARY_XATTR_SIZE);
-	if (rc) {
-		down(&c->alloc_sem);
-		down_write(&c->xattr_sem);
-		delete_xattr_datum_delay(c, xd);
-	} else {
-		down_write(&c->xattr_sem);
 		delete_xattr_datum(c, xd);
-	}
-	return 0;
 }
 
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
 {
 	/* It's called from jffs2_clear_inode() on inode removing.
 	   When an inode with XATTR is removed, those XATTRs must be removed. */
-	struct jffs2_xattr_ref *ref;
-	uint32_t length;
-	int rc, retry;
+	struct jffs2_xattr_ref *ref, *_ref;
 
 	if (!ic || ic->nlink > 0)
 		return;
 
-	down_read(&c->xattr_sem);
-	if (!ic->xref) {
-		up_read(&c->xattr_sem);
-		return;
-	}
-	up_read(&c->xattr_sem);
- retry:
-	rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xref)), &length,
-				 ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE);
 	down_write(&c->xattr_sem);
-	if (ic->xref) {
-		ref = ic->xref;
-		ic->xref = ref->next;
-		if (rc) {
-			delete_xattr_ref_delay(c, ref);
-		} else {
-			delete_xattr_ref(c, ref, 1);
-		}
+	for (ref = ic->xref; ref; ref = _ref) {
+		_ref = ref->next;
+		delete_xattr_ref(c, ref);
 	}
-	retry = ic->xref ? 1 : 0;
+	ic->xref = NULL;
 	up_write(&c->xattr_sem);
-	if (!rc)
-		jffs2_complete_reservation(c);
-	if (retry)
-		goto retry;
 }
 
 void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
@@ -743,7 +642,7 @@ static int check_xattr_ref_inode(struct 
 			rc = load_xattr_datum(c, ref->xd);
 			if (unlikely(rc > 0)) {
 				*pref = ref->next;
-				delete_xattr_ref_delay(c, ref);
+				delete_xattr_ref(c, ref);
 				goto retry;
 			} else if (unlikely(rc < 0))
 				goto out;
@@ -755,7 +654,7 @@ static int check_xattr_ref_inode(struct 
 				ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
 				if (unlikely(rc > 0)) {
 					*pcmp = cmp->next;
-					delete_xattr_ref_delay(c, cmp);
+					delete_xattr_ref(c, cmp);
 					goto retry;
 				} else if (unlikely(rc < 0))
 					goto out;
@@ -764,10 +663,10 @@ static int check_xattr_ref_inode(struct 
 			    && !strcmp(ref->xd->xname, cmp->xd->xname)) {
 				if (ref->xseqno > cmp->xseqno) {
 					*pcmp = cmp->next;
-					delete_xattr_ref_delay(c, cmp);
+					delete_xattr_ref(c, cmp);
 				} else {
 					*pref = ref->next;
-					delete_xattr_ref_delay(c, ref);
+					delete_xattr_ref(c, ref);
 				}
 				goto retry;
 			}
@@ -865,20 +764,11 @@ void jffs2_build_xattr_subsystem(struct 
 	struct jffs2_inode_cache *ic;
 	struct jffs2_raw_node_ref *raw;
 	int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0;
+	int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0;
 
 	BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
-	/* Phase.1 : Drop dead xdatum */
-	for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
-		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
-			BUG_ON(xd->node == (void *)xd);
-			if (is_xattr_datum_dead(xd)) {
-				list_del_init(&xd->xindex);
-				list_add(&xd->xindex, &c->xattr_unchecked);
-			}
-		}
-	}
 
-	/* Phase.2 : Merge same xref */
+	/* Phase.1 : Merge same xref */
 	for (i=0; i < XREF_TMPHASH_SIZE; i++)
 		xref_tmphash[i] = NULL;
 	for (ref=c->xref_temp; ref; ref=_ref) {
@@ -919,13 +809,15 @@ void jffs2_build_xattr_subsystem(struct 
 	}
 	c->xref_temp = NULL;
 
-	/* Phase.3 : Bind xref with inode_cache and xattr_datum */
+	/* Phase.2 : Bind xref with inode_cache and xattr_datum */
 	for (i=0; i < XREF_TMPHASH_SIZE; i++) {
 		for (ref=xref_tmphash[i]; ref; ref=_ref) {
+			xref_count++;
 			_ref = ref->next;
 			if (is_xattr_ref_dead(ref)) {
 				ref->next = c->xref_dead_list;
 				c->xref_dead_list = ref;
+				xref_dead_count++;
 				continue;
 			}
 			/* At this point, ref->xid and ref->ino contain XID and inode number.
@@ -933,11 +825,12 @@ void jffs2_build_xattr_subsystem(struct 
 			xd = jffs2_find_xattr_datum(c, ref->xid);
 			ic = jffs2_get_ino_cache(c, ref->ino);
 			if (!xd || !ic) {
-				JFFS2_WARNING("xref(ino=%u, xid=%u, xseqno=%u) is orphan. \n",
-					      ref->ino, ref->xid, ref->xseqno);
-				set_xattr_ref_dead(ref);
+				dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
+					  ref->ino, ref->xid, ref->xseqno);
+				ref->xseqno |= XREF_DELETE_MARKER;
 				ref->next = c->xref_dead_list;
 				c->xref_dead_list = ref;
+				xref_orphan_count++;
 				continue;
 			}
 			ref->xd = xd;
@@ -945,19 +838,20 @@ void jffs2_build_xattr_subsystem(struct 
 			xd->refcnt++;
 			ref->next = ic->xref;
 			ic->xref = ref;
-			xref_count++;
 		}
 	}
 
-	/* Phase.4 : Link unchecked xdatum to xattr_unchecked list */
+	/* Phase.3 : Link unchecked xdatum to xattr_unchecked list */
 	for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
 		list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+			xdatum_count++;
 			list_del_init(&xd->xindex);
 			if (!xd->refcnt) {
-				JFFS2_WARNING("orphan xdatum(xid=%u, version=%u)\n",
-					      xd->xid, xd->version);
-				set_xattr_datum_dead(xd);
+				dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n",
+					  xd->xid, xd->version);
+				xd->flags |= JFFS2_XFLAGS_DEAD;
 				list_add(&xd->xindex, &c->xattr_unchecked);
+				xdatum_orphan_count++;
 				continue;
 			}
 			if (is_xattr_datum_unchecked(c, xd)) {
@@ -966,12 +860,14 @@ void jffs2_build_xattr_subsystem(struct 
 				list_add(&xd->xindex, &c->xattr_unchecked);
 				xdatum_unchecked_count++;
 			}
-			xdatum_count++;
 		}
 	}
 	/* build complete */
-	JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
-		     "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
+	JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum"
+		     " (%u unchecked, %u orphan) and "
+		     "%u of xref (%u dead, %u orphan) found.\n",
+		     xdatum_count, xdatum_unchecked_count, xdatum_orphan_count,
+		     xref_count, xref_dead_count, xref_orphan_count);
 }
 
 struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
@@ -1079,7 +975,7 @@ ssize_t jffs2_listxattr(struct dentry *d
 				rc = load_xattr_datum(c, xd);
 				if (unlikely(rc > 0)) {
 					*pref = ref->next;
-					delete_xattr_ref_delay(c, ref);
+					delete_xattr_ref(c, ref);
 					goto retry;
 				} else if (unlikely(rc < 0))
 					goto out;
@@ -1140,7 +1036,7 @@ int do_jffs2_getxattr(struct inode *inod
 				rc = load_xattr_datum(c, xd);
 				if (unlikely(rc > 0)) {
 					*pref = ref->next;
-					delete_xattr_ref_delay(c, ref);
+					delete_xattr_ref(c, ref);
 					goto retry;
 				} else if (unlikely(rc < 0)) {
 					goto out;
@@ -1203,7 +1099,7 @@ int do_jffs2_setxattr(struct inode *inod
 			rc = load_xattr_datum(c, xd);
 			if (unlikely(rc > 0)) {
 				*pref = ref->next;
-				delete_xattr_ref_delay(c, ref);
+				delete_xattr_ref(c, ref);
 				goto retry;
 			} else if (unlikely(rc < 0))
 				goto out;
@@ -1214,8 +1110,23 @@ int do_jffs2_setxattr(struct inode *inod
 				goto out;
 			}
 			if (!buffer) {
-				*pref = ref->next;
-				rc = delete_xattr_ref(c, ref, 0);
+				ref->ino = ic->ino;
+				ref->xid = xd->xid;
+				ref->xseqno |= XREF_DELETE_MARKER;
+				rc = save_xattr_ref(c, ref);
+				if (!rc) {
+					*pref = ref->next;
+					spin_lock(&c->erase_completion_lock);
+					ref->next = c->xref_dead_list;
+					c->xref_dead_list = ref;
+					spin_unlock(&c->erase_completion_lock);
+					if (!--xd->refcnt)
+						delete_xattr_datum(c, xd);
+				} else {
+					ref->ic = ic;
+					ref->xd = xd;
+					ref->xseqno &= ~XREF_DELETE_MARKER;
+				}
 				goto out;
 			}
 			goto found;
@@ -1248,7 +1159,7 @@ int do_jffs2_setxattr(struct inode *inod
 		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
 		xd->refcnt--;
 		if (!xd->refcnt)
-			delete_xattr_datum_delay(c, xd);
+			delete_xattr_datum(c, xd);
 		up_write(&c->xattr_sem);
 		return rc;
 	}
@@ -1263,21 +1174,9 @@ int do_jffs2_setxattr(struct inode *inod
 		rc = PTR_ERR(newref);
 		xd->refcnt--;
 		if (!xd->refcnt)
-			delete_xattr_datum_delay(c, xd);
+			delete_xattr_datum(c, xd);
 	} else if (ref) {
-		up_write(&c->xattr_sem);
-		jffs2_complete_reservation(c);
-
-		rc = jffs2_reserve_space(c, request, &length,
-					 ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE);
-		down_write(&c->xattr_sem);
-		if (rc) {
-			JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-			delete_xattr_ref_delay(c, ref);
-			up_write(&c->xattr_sem);
-			return 0;
-		}
-		delete_xattr_ref(c, ref, 1);
+		delete_xattr_ref(c, ref);
 	}
  out:
 	up_write(&c->xattr_sem);
@@ -1292,6 +1191,10 @@ int do_jffs2_setxattr(struct inode *inod
  *   is used to move xref into new node.
  * jffs2_verify_xattr(c)
  *   is used to call do_verify_xattr_datum() before garbage collecting.
+ * jffs2_release_xattr_datum(c, xd)
+ *   is used to release an in-memory object of xdatum.
+ * jffs2_release_xattr_ref(c, ref)
+ *   is used to release an in-memory object of xref.
  * -------------------------------------------------- */
 int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd,
 				      struct jffs2_raw_node_ref *raw)
@@ -1302,18 +1205,17 @@ int jffs2_garbage_collect_xattr_datum(st
 	down_write(&c->xattr_sem);
 	if (xd->node != raw)
 		goto out;
-	if (is_xattr_datum_dead(xd) && (raw->next_in_ino == (void *)xd))
+	if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID))
 		goto out;
 
-	old_ofs = ref_offset(xd->node);
-	totlen = ref_totlen(c, c->gcblock, xd->node);
-
-	if (!is_xattr_datum_dead(xd)) {
-		rc = load_xattr_datum(c, xd);
-		if (unlikely(rc < 0))
-			goto out;
+	rc = load_xattr_datum(c, xd);
+	if (unlikely(rc)) {
+		rc = (rc > 0) ? 0 : rc;
+		goto out;
 	}
-
+	old_ofs = ref_offset(xd->node);
+	totlen = PAD(sizeof(struct jffs2_raw_xattr)
+			+ xd->name_len + 1 + xd->value_len);
 	rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE);
 	if (rc) {
 		JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen);
@@ -1331,7 +1233,6 @@ int jffs2_garbage_collect_xattr_datum(st
 	return rc;
 }
 
-
 int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref,
 				    struct jffs2_raw_node_ref *raw)
 {
@@ -1392,7 +1293,7 @@ int jffs2_verify_xattr(struct jffs2_sb_i
 			raw->flash_offset = ref_offset(raw)
 				| ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL);
 		}
-		if (is_xattr_datum_dead(xd))
+		if (xd->flags & JFFS2_XFLAGS_DEAD)
 			list_add(&xd->xindex, &c->xattr_dead_list);
 		spin_unlock(&c->erase_completion_lock);
 	}
@@ -1403,7 +1304,7 @@ int jffs2_verify_xattr(struct jffs2_sb_i
 void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under spin_lock(&c->erase_completion_lock) */
-	if (xd->node != (void *)xd)
+	if (xd->refcnt > 0 || xd->node != (void *)xd)
 		return;
 
 	list_del(&xd->xindex);
@@ -1421,8 +1322,8 @@ void jffs2_release_xattr_ref(struct jffs
 	for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) {
 		if (ref == tmp) {
 			*ptmp = tmp->next;
-			jffs2_free_xattr_ref(ref);
 			break;
 		}
 	}
+	jffs2_free_xattr_ref(ref);
 }
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 06ab7b8..4a10abc 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -16,6 +16,7 @@ #include <linux/list.h>
 
 #define JFFS2_XFLAGS_HOT	(0x01)	/* This datum is HOT */
 #define JFFS2_XFLAGS_BIND	(0x02)	/* This datum is not reclaimed */
+#define JFFS2_XFLAGS_DEAD	(0x40)	/* This datum is already dead */
 #define JFFS2_XFLAGS_INVALID	(0x80)	/* This datum contains crc error */
 
 struct jffs2_xattr_datum
@@ -60,34 +61,12 @@ struct jffs2_xattr_ref
 	struct jffs2_xattr_ref *next;		/* chained from ic->xref_list */
 };
 
-#define XDATUM_DELETE_MARKER	(0xffffffff)
 #define XREF_DELETE_MARKER	(0x00000001)
-static inline int is_xattr_datum_dead(struct jffs2_xattr_datum *xd)
-{
-	return (xd->version == XDATUM_DELETE_MARKER);
-}
-
-static inline void set_xattr_datum_dead(struct jffs2_xattr_datum *xd)
-{
-	xd->version = XDATUM_DELETE_MARKER;
-}
-
 static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref)
 {
 	return ((ref->xseqno & XREF_DELETE_MARKER) != 0);
 }
 
-static inline void set_xattr_ref_dead(struct jffs2_xattr_ref *ref)
-{
-	ref->xseqno |= XREF_DELETE_MARKER;
-}
-
-static inline void clr_xattr_ref_dead(struct jffs2_xattr_ref *ref)
-{
-	ref->xseqno &= ~XREF_DELETE_MARKER;
-}
-
-
 #ifdef CONFIG_JFFS2_FS_XATTR
 
 extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);


From linux-mtd at lists.infradead.org  Tue Jun 27 11:59:03 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 16:59:03 +0100
Subject: [JFFS2][XATTR] coexistence between xattr and write buffering support.
Message-ID: <E1FvFxv-0003NW-BW@pentafluge.infradead.org>

Commit:     04510dee3c21ac208351cc6de7b70a5459ab3029
Parent:     332a6b99c587161a972eaa1b00ae0e0dc49fbbfd
commit 04510dee3c21ac208351cc6de7b70a5459ab3029
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Sat Jun 24 09:21:13 2006 +0900
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 16:20:06 2006 +0100

    [JFFS2][XATTR] coexistence between xattr and write buffering support.
    
    Drop '&& !JFFS2_FS_WRITEBUFFER' from fs/Kconfig.
    The series of previous patches enables to use those
    functionality at same time.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index 1cdc043..ee5effa 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1116,7 +1116,7 @@ config JFFS2_SUMMARY
 
 config JFFS2_FS_XATTR
 	bool "JFFS2 XATTR support (EXPERIMENTAL)"
-	depends on JFFS2_FS && EXPERIMENTAL && !JFFS2_FS_WRITEBUFFER
+	depends on JFFS2_FS && EXPERIMENTAL
 	default n
 	help
 	  Extended attributes are name:value pairs associated with inodes by


From linux-mtd at lists.infradead.org  Tue Jun 27 18:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 23:59:01 +0100
Subject: [MTD] NAND: Fix typo in mtd/nand/ts7250.c
Message-ID: <E1FvMWL-00074l-GB@pentafluge.infradead.org>

Commit:     0e4ced59de7c0c23588d2b3f6d302592545cd12e
Parent:     04510dee3c21ac208351cc6de7b70a5459ab3029
commit 0e4ced59de7c0c23588d2b3f6d302592545cd12e
Author:     Petr Stetiar <ynezz at true.cz>
AuthorDate: Fri Jun 23 19:17:03 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 23:20:48 2006 +0100

    [MTD] NAND: Fix typo in mtd/nand/ts7250.c
    
    I was unable to compile ts7250.c after your refactor commit,
    it's a typo probably.
    
    -- ynezz
    
    From: Petr Stetiar <ynezz at true.cz>
    Signed-off-by: Thomas Gleixner  <tglx at linutronix.de>
---
 drivers/mtd/nand/ts7250.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c
index a0b4b1e..f400810 100644
--- a/drivers/mtd/nand/ts7250.c
+++ b/drivers/mtd/nand/ts7250.c
@@ -97,7 +97,7 @@ static void ts7250_hwcontrol(struct mtd_
 		unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
 		unsigned char bits;
 
-		bits = (ctrl & NAND_CNE) << 2;
+		bits = (ctrl & NAND_NCE) << 2;
 		bits |= ctrl & NAND_CLE;
 		bits |= (ctrl & NAND_ALE) >> 2;
 


From linux-mtd at lists.infradead.org  Tue Jun 27 18:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 23:59:01 +0100
Subject: [MTD] CORE mtdchar.c: fix off-by-one error in lseek()
Message-ID: <E1FvMWL-000754-Ll@pentafluge.infradead.org>

Commit:     1887f517e3cdf5f1e9c0e4daaa864450415a8f61
Parent:     0e4ced59de7c0c23588d2b3f6d302592545cd12e
commit 1887f517e3cdf5f1e9c0e4daaa864450415a8f61
Author:     Herbert Valerio Riedel <hvr at gnu.org>
AuthorDate: Sat Jun 24 00:03:36 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 23:22:07 2006 +0100

    [MTD] CORE mtdchar.c: fix off-by-one error in lseek()
    
    Allow lseek(mtdchar_fd, 0, SEEK_END) to succeed, which currently fails
    with EINVAL.
    
    lseek(fd, 0, SEEK_END) should result into the same fileposition as
    lseek(fd, 0, SEEK_SET) + read(fd, buf, length(fd))
    
    Furthermore, lseek(fd, 0, SEEK_CUR) should return the current file position,
    which in case of an encountered EOF should not result in EINVAL
    
    Signed-off-by: Herbert Valerio Riedel <hvr at gnu.org>
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/mtdchar.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index aa18d45..9a4b59d 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -78,7 +78,7 @@ static loff_t mtd_lseek (struct file *fi
 		return -EINVAL;
 	}
 
-	if (offset >= 0 && offset < mtd->size)
+	if (offset >= 0 && offset <= mtd->size)
 		return file->f_pos = offset;
 
 	return -EINVAL;


From linux-mtd at lists.infradead.org  Tue Jun 27 18:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Tue, 27 Jun 2006 23:59:01 +0100
Subject: [MTD] NAND: Select chip before checking write protect status
Message-ID: <E1FvMWL-00075N-T9@pentafluge.infradead.org>

Commit:     6a93096195305f6f2a39544a034e77e2e74d5799
Parent:     1887f517e3cdf5f1e9c0e4daaa864450415a8f61
commit 6a93096195305f6f2a39544a034e77e2e74d5799
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Wed Jun 28 00:11:45 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Tue Jun 27 23:24:09 2006 +0100

    [MTD] NAND: Select chip before checking write protect status
    
    The other way round works not really well with boards which have a
    static NAND chipselect.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/nand_base.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8df184f..80a7665 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1610,13 +1610,13 @@ static int nand_do_write_ops(struct mtd_
 	if (!writelen)
 		return 0;
 
+	chipnr = (int)(to >> chip->chip_shift);
+	chip->select_chip(mtd, chipnr);
+
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd))
 		return -EIO;
 
-	chipnr = (int)(to >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
 	realpage = (int)(to >> chip->page_shift);
 	page = realpage & chip->pagemask;
 	blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;


From linux-mtd at lists.infradead.org  Wed Jun 28 05:59:02 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Wed, 28 Jun 2006 10:59:02 +0100
Subject: [MTD] DOC: Fixup read functions and do a little cleanup
Message-ID: <E1FvWp4-0007f5-2f@pentafluge.infradead.org>

Commit:     7f8a894066b826a4baea49c2a3adbba0a56a192f
Parent:     a39727f212426b9d5f9267b3318a2afaf9922d3b
commit 7f8a894066b826a4baea49c2a3adbba0a56a192f
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Wed Jun 28 10:11:33 2006 +0200
Commit:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
CommitDate: Wed Jun 28 10:11:33 2006 +0200

    [MTD] DOC: Fixup read functions and do a little cleanup
    
    The NAND rework resulted in non ECC based reads. Fix it up and
    do a bit of cleanup while at it.
    
    Pointed out by Adrian Bunk.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/devices/doc2000.c     |  179 +++++++++++++++----------------------
 drivers/mtd/devices/doc2001.c     |  179 +++++++++++++++----------------------
 drivers/mtd/devices/doc2001plus.c |  164 +++++++++++++---------------------
 3 files changed, 207 insertions(+), 315 deletions(-)

diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index c54e404..603a795 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -55,10 +55,6 @@ static int doc_read(struct mtd_info *mtd
 		    size_t *retlen, u_char *buf);
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
 			struct mtd_oob_ops *ops);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -615,17 +611,10 @@ EXPORT_SYMBOL_GPL(DoC2k_init);
 static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 		    size_t * retlen, u_char * buf)
 {
-	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
-{
 	struct DiskOnChip *this = mtd->priv;
 	void __iomem *docptr = this->virtadr;
 	struct Nand *mychip;
-	unsigned char syndrome[6];
+	unsigned char syndrome[6], eccbuf[6];
 	volatile char dummy;
 	int i, len256 = 0, ret=0;
 	size_t left = len;
@@ -673,15 +662,9 @@ static int doc_read_ecc(struct mtd_info 
 		DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
 			    CDSN_CTRL_ECC_IO);
 
-		if (eccbuf) {
-			/* Prime the ECC engine */
-			WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-			WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-		} else {
-			/* disable the ECC engine */
-			WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-			WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-		}
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
 
 		/* treat crossing 256-byte sector for 2M x 8bits devices */
 		if (this->page256 && from + len > (from | 0xff) + 1) {
@@ -698,58 +681,59 @@ static int doc_read_ecc(struct mtd_info 
 		/* Let the caller know we completed it */
 		*retlen += len;
 
-		if (eccbuf) {
-			/* Read the ECC data through the DiskOnChip ECC logic */
-			/* Note: this will work even with 2M x 8bit devices as   */
-			/*       they have 8 bytes of OOB per 256 page. mf.      */
-			DoC_ReadBuf(this, eccbuf, 6);
-
-			/* Flush the pipeline */
-			if (DoC_is_Millennium(this)) {
-				dummy = ReadDOC(docptr, ECCConf);
-				dummy = ReadDOC(docptr, ECCConf);
-				i = ReadDOC(docptr, ECCConf);
-			} else {
-				dummy = ReadDOC(docptr, 2k_ECCStatus);
-				dummy = ReadDOC(docptr, 2k_ECCStatus);
-				i = ReadDOC(docptr, 2k_ECCStatus);
-			}
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		/* Note: this will work even with 2M x 8bit devices as   */
+		/*       they have 8 bytes of OOB per 256 page. mf.      */
+		DoC_ReadBuf(this, eccbuf, 6);
 
-			/* Check the ECC Status */
-			if (i & 0x80) {
-				int nb_errors;
-				/* There was an ECC error */
+		/* Flush the pipeline */
+		if (DoC_is_Millennium(this)) {
+			dummy = ReadDOC(docptr, ECCConf);
+			dummy = ReadDOC(docptr, ECCConf);
+			i = ReadDOC(docptr, ECCConf);
+		} else {
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			dummy = ReadDOC(docptr, 2k_ECCStatus);
+			i = ReadDOC(docptr, 2k_ECCStatus);
+		}
+
+		/* Check the ECC Status */
+		if (i & 0x80) {
+			int nb_errors;
+			/* There was an ECC error */
 #ifdef ECC_DEBUG
-				printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
+			printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-				/* Read the ECC syndrom through the DiskOnChip ECC logic.
-				   These syndrome will be all ZERO when there is no error */
-				for (i = 0; i < 6; i++) {
-					syndrome[i] =
-					    ReadDOC(docptr, ECCSyndrome0 + i);
-				}
-	                        nb_errors = doc_decode_ecc(buf, syndrome);
+			/* Read the ECC syndrom through the DiskOnChip ECC
+			   logic.  These syndrome will be all ZERO when there
+			   is no error */
+			for (i = 0; i < 6; i++) {
+				syndrome[i] =
+					ReadDOC(docptr, ECCSyndrome0 + i);
+			}
+			nb_errors = doc_decode_ecc(buf, syndrome);
 
 #ifdef ECC_DEBUG
-				printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
+			printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
 #endif
-	                        if (nb_errors < 0) {
-					/* We return error, but have actually done the read. Not that
-					   this can be told to user-space, via sys_read(), but at least
-					   MTD-aware stuff can know about it by checking *retlen */
-					ret = -EIO;
-	                        }
+			if (nb_errors < 0) {
+				/* We return error, but have actually done the
+				   read. Not that this can be told to
+				   user-space, via sys_read(), but at least
+				   MTD-aware stuff can know about it by
+				   checking *retlen */
+				ret = -EIO;
 			}
+		}
 
 #ifdef PSYCHO_DEBUG
-			printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-				     (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
-				     eccbuf[3], eccbuf[4], eccbuf[5]);
+		printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+		       (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+		       eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
 
-			/* disable the ECC engine */
-			WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
-		}
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
 
 		/* according to 11.4.1, we need to wait for the busy line
 	         * drop if we read to the end of the page.  */
@@ -771,17 +755,10 @@ #endif
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t * retlen, const u_char * buf)
 {
-	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t * retlen, const u_char * buf,
-			 u_char * eccbuf, struct nand_oobinfo *oobsel)
-{
 	struct DiskOnChip *this = mtd->priv;
 	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
 	void __iomem *docptr = this->virtadr;
+	unsigned char eccbuf[6];
 	volatile char dummy;
 	int len256 = 0;
 	struct Nand *mychip;
@@ -835,15 +812,9 @@ static int doc_write_ecc(struct mtd_info
 		DoC_Command(this, NAND_CMD_SEQIN, 0);
 		DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
 
-		if (eccbuf) {
-			/* Prime the ECC engine */
-			WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-			WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-		} else {
-			/* disable the ECC engine */
-			WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-			WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-		}
+		/* Prime the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
 
 		/* treat crossing 256-byte sector for 2M x 8bits devices */
 		if (this->page256 && to + len > (to | 0xff) + 1) {
@@ -873,39 +844,35 @@ static int doc_write_ecc(struct mtd_info
 
 		DoC_WriteBuf(this, &buf[len256], len - len256);
 
-		if (eccbuf) {
-			WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
-				 CDSNControl);
-
-			if (DoC_is_Millennium(this)) {
-				WriteDOC(0, docptr, NOP);
-				WriteDOC(0, docptr, NOP);
-				WriteDOC(0, docptr, NOP);
-			} else {
-				WriteDOC_(0, docptr, this->ioreg);
-				WriteDOC_(0, docptr, this->ioreg);
-				WriteDOC_(0, docptr, this->ioreg);
-			}
+		WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl);
 
-			WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
-				 CDSNControl);
+		if (DoC_is_Millennium(this)) {
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+			WriteDOC(0, docptr, NOP);
+		} else {
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+			WriteDOC_(0, docptr, this->ioreg);
+		}
 
-			/* Read the ECC data through the DiskOnChip ECC logic */
-			for (di = 0; di < 6; di++) {
-				eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-			}
+		WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
+			 CDSNControl);
 
-			/* Reset the ECC engine */
-			WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		for (di = 0; di < 6; di++) {
+			eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+		}
+
+		/* Reset the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
 
 #ifdef PSYCHO_DEBUG
-			printk
-			    ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-			     (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-			     eccbuf[4], eccbuf[5]);
+		printk
+			("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+			 (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+			 eccbuf[4], eccbuf[5]);
 #endif
-		}
-
 		DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
 		DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 0cf022a..0e2a932 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -37,12 +37,6 @@ static int doc_read(struct mtd_info *mtd
 		    size_t *retlen, u_char *buf);
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf,
-			struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf,
-			 struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
 			struct mtd_oob_ops *ops);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -397,17 +391,9 @@ EXPORT_SYMBOL_GPL(DoCMil_init);
 static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
 		     size_t *retlen, u_char *buf)
 {
-	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-			 size_t *retlen, u_char *buf, u_char *eccbuf,
-			 struct nand_oobinfo *oobsel)
-{
 	int i, ret;
 	volatile char dummy;
-	unsigned char syndrome[6];
+	unsigned char syndrome[6], eccbuf[6];
 	struct DiskOnChip *this = mtd->priv;
 	void __iomem *docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -437,15 +423,9 @@ static int doc_read_ecc (struct mtd_info
 	DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
 	DoC_WaitReady(docptr);
 
-	if (eccbuf) {
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_EN, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-	}
+	/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_EN, docptr, ECCConf);
 
 	/* Read the data via the internal pipeline through CDSN IO register,
 	   see Pipelined Read Operations 11.3 */
@@ -465,58 +445,56 @@ #endif
 	*retlen = len;
         ret = 0;
 
-	if (eccbuf) {
-		/* Read the ECC data from Spare Data Area,
-		   see Reed-Solomon EDC/ECC 11.1 */
-		dummy = ReadDOC(docptr, ReadPipeInit);
+	/* Read the ECC data from Spare Data Area,
+	   see Reed-Solomon EDC/ECC 11.1 */
+	dummy = ReadDOC(docptr, ReadPipeInit);
 #ifndef USE_MEMCPY
-		for (i = 0; i < 5; i++) {
-			/* N.B. you have to increase the source address in this way or the
-			   ECC logic will not work properly */
-			eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
-		}
+	for (i = 0; i < 5; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
+	}
 #else
-		memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
+	memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
 #endif
-		eccbuf[5] = ReadDOC(docptr, LastDataRead);
+	eccbuf[5] = ReadDOC(docptr, LastDataRead);
 
-		/* Flush the pipeline */
-		dummy = ReadDOC(docptr, ECCConf);
-		dummy = ReadDOC(docptr, ECCConf);
+	/* Flush the pipeline */
+	dummy = ReadDOC(docptr, ECCConf);
+	dummy = ReadDOC(docptr, ECCConf);
 
-		/* Check the ECC Status */
-		if (ReadDOC(docptr, ECCConf) & 0x80) {
-                        int nb_errors;
-			/* There was an ECC error */
+	/* Check the ECC Status */
+	if (ReadDOC(docptr, ECCConf) & 0x80) {
+		int nb_errors;
+		/* There was an ECC error */
 #ifdef ECC_DEBUG
-			printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+		printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-			/* Read the ECC syndrom through the DiskOnChip ECC logic.
-			   These syndrome will be all ZERO when there is no error */
-			for (i = 0; i < 6; i++) {
-				syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
-			}
-                        nb_errors = doc_decode_ecc(buf, syndrome);
+		/* Read the ECC syndrom through the DiskOnChip ECC logic.
+		   These syndrome will be all ZERO when there is no error */
+		for (i = 0; i < 6; i++) {
+			syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+		}
+		nb_errors = doc_decode_ecc(buf, syndrome);
 #ifdef ECC_DEBUG
-			printk("ECC Errors corrected: %x\n", nb_errors);
+		printk("ECC Errors corrected: %x\n", nb_errors);
 #endif
-                        if (nb_errors < 0) {
-				/* We return error, but have actually done the read. Not that
-				   this can be told to user-space, via sys_read(), but at least
-				   MTD-aware stuff can know about it by checking *retlen */
-				ret = -EIO;
-                        }
+		if (nb_errors < 0) {
+			/* We return error, but have actually done the read. Not that
+			   this can be told to user-space, via sys_read(), but at least
+			   MTD-aware stuff can know about it by checking *retlen */
+			ret = -EIO;
 		}
+	}
 
 #ifdef PSYCHO_DEBUG
-		printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-		       (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-		       eccbuf[4], eccbuf[5]);
+	printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	       (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+	       eccbuf[4], eccbuf[5]);
 #endif
 
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
-	}
+	/* disable the ECC engine */
+	WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
 
 	return ret;
 }
@@ -524,15 +502,8 @@ #endif
 static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
 		      size_t *retlen, const u_char *buf)
 {
-	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const u_char *buf, u_char *eccbuf,
-			 struct nand_oobinfo *oobsel)
-{
 	int i,ret = 0;
+	char eccbuf[6];
 	volatile char dummy;
 	struct DiskOnChip *this = mtd->priv;
 	void __iomem *docptr = this->virtadr;
@@ -573,15 +544,9 @@ #endif
 	DoC_Address(docptr, 3, to, 0x00, 0x00);
 	DoC_WaitReady(docptr);
 
-	if (eccbuf) {
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
-		WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
-	}
+	/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+	WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+	WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
 
 	/* Write the data via the internal pipeline through CDSN IO register,
 	   see Pipelined Write Operations 11.2 */
@@ -596,46 +561,44 @@ #else
 #endif
 	WriteDOC(0x00, docptr, WritePipeTerm);
 
-	if (eccbuf) {
-		/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
-		   see Reed-Solomon EDC/ECC 11.1 */
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
-		WriteDOC(0, docptr, NOP);
+	/* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
+	   see Reed-Solomon EDC/ECC 11.1 */
+	WriteDOC(0, docptr, NOP);
+	WriteDOC(0, docptr, NOP);
+	WriteDOC(0, docptr, NOP);
 
-		/* Read the ECC data through the DiskOnChip ECC logic */
-		for (i = 0; i < 6; i++) {
-			eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
-		}
+	/* Read the ECC data through the DiskOnChip ECC logic */
+	for (i = 0; i < 6; i++) {
+		eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+	}
 
-		/* ignore the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+	/* ignore the ECC engine */
+	WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
 
 #ifndef USE_MEMCPY
-		/* Write the ECC data to flash */
-		for (i = 0; i < 6; i++) {
-			/* N.B. you have to increase the source address in this way or the
-			   ECC logic will not work properly */
-			WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
-		}
+	/* Write the ECC data to flash */
+	for (i = 0; i < 6; i++) {
+		/* N.B. you have to increase the source address in this way or the
+		   ECC logic will not work properly */
+		WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
+	}
 #else
-		memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
+	memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
 #endif
 
-		/* write the block status BLOCK_USED (0x5555) at the end of ECC data
-		   FIXME: this is only a hack for programming the IPL area for LinuxBIOS
-		   and should be replace with proper codes in user space utilities */
-		WriteDOC(0x55, docptr, Mil_CDSN_IO);
-		WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
+	/* write the block status BLOCK_USED (0x5555) at the end of ECC data
+	   FIXME: this is only a hack for programming the IPL area for LinuxBIOS
+	   and should be replace with proper codes in user space utilities */
+	WriteDOC(0x55, docptr, Mil_CDSN_IO);
+	WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
 
-		WriteDOC(0x00, docptr, WritePipeTerm);
+	WriteDOC(0x00, docptr, WritePipeTerm);
 
 #ifdef PSYCHO_DEBUG
-		printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-		       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-		       eccbuf[4], eccbuf[5]);
+	printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+	       eccbuf[4], eccbuf[5]);
 #endif
-	}
 
 	/* Commit the Page Program command and wait for ready
 	   see Software Requirement 11.4 item 1.*/
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 66cb1e5..92dbb47 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -41,12 +41,6 @@ static int doc_read(struct mtd_info *mtd
 		size_t *retlen, u_char *buf);
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-		size_t *retlen, u_char *buf, u_char *eccbuf,
-		struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-		size_t *retlen, const u_char *buf, u_char *eccbuf,
-		struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
 			struct mtd_oob_ops *ops);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -595,18 +589,10 @@ #endif
 static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 		    size_t *retlen, u_char *buf)
 {
-	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf,
-			struct nand_oobinfo *oobsel)
-{
 	int ret, i;
 	volatile char dummy;
 	loff_t fofs;
-	unsigned char syndrome[6];
+	unsigned char syndrome[6], eccbuf[6];
 	struct DiskOnChip *this = mtd->priv;
 	void __iomem * docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -644,56 +630,51 @@ static int doc_read_ecc(struct mtd_info 
 	WriteDOC(0, docptr, Mplus_FlashControl);
 	DoC_WaitReady(docptr);
 
-	if (eccbuf) {
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-	} else {
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-	}
+	/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+	WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+	WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
 
 	/* Let the caller know we completed it */
 	*retlen = len;
-        ret = 0;
+	ret = 0;
 
 	ReadDOC(docptr, Mplus_ReadPipeInit);
 	ReadDOC(docptr, Mplus_ReadPipeInit);
 
-	if (eccbuf) {
-		/* Read the data via the internal pipeline through CDSN IO
-		   register, see Pipelined Read Operations 11.3 */
-		MemReadDOC(docptr, buf, len);
+	/* Read the data via the internal pipeline through CDSN IO
+	   register, see Pipelined Read Operations 11.3 */
+	MemReadDOC(docptr, buf, len);
 
-		/* Read the ECC data following raw data */
-		MemReadDOC(docptr, eccbuf, 4);
-		eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
-		eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
+	/* Read the ECC data following raw data */
+	MemReadDOC(docptr, eccbuf, 4);
+	eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
+	eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
 
-		/* Flush the pipeline */
-		dummy = ReadDOC(docptr, Mplus_ECCConf);
-		dummy = ReadDOC(docptr, Mplus_ECCConf);
+	/* Flush the pipeline */
+	dummy = ReadDOC(docptr, Mplus_ECCConf);
+	dummy = ReadDOC(docptr, Mplus_ECCConf);
 
-		/* Check the ECC Status */
-		if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
-                        int nb_errors;
-			/* There was an ECC error */
+	/* Check the ECC Status */
+	if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
+		int nb_errors;
+		/* There was an ECC error */
 #ifdef ECC_DEBUG
-			printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+		printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-			/* Read the ECC syndrom through the DiskOnChip ECC logic.
-			   These syndrome will be all ZERO when there is no error */
-			for (i = 0; i < 6; i++)
-				syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+		/* Read the ECC syndrom through the DiskOnChip ECC logic.
+		   These syndrome will be all ZERO when there is no error */
+		for (i = 0; i < 6; i++)
+			syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
 
-                        nb_errors = doc_decode_ecc(buf, syndrome);
+		nb_errors = doc_decode_ecc(buf, syndrome);
 #ifdef ECC_DEBUG
-			printk("ECC Errors corrected: %x\n", nb_errors);
+		printk("ECC Errors corrected: %x\n", nb_errors);
 #endif
-                        if (nb_errors < 0) {
-				/* We return error, but have actually done the read. Not that
-				   this can be told to user-space, via sys_read(), but at least
-				   MTD-aware stuff can know about it by checking *retlen */
+		if (nb_errors < 0) {
+			/* We return error, but have actually done the
+			   read. Not that this can be told to user-space, via
+			   sys_read(), but at least MTD-aware stuff can know
+			   about it by checking *retlen */
 #ifdef ECC_DEBUG
 			printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
 				__FILE__, __LINE__, (int)from);
@@ -707,24 +688,16 @@ #ifdef ECC_DEBUG
 				eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
 				ret = -EIO;
-                        }
 		}
+	}
 
 #ifdef PSYCHO_DEBUG
-		printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-		       (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-		       eccbuf[4], eccbuf[5]);
+	printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	       (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+	       eccbuf[4], eccbuf[5]);
 #endif
-
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
-	} else {
-		/* Read the data via the internal pipeline through CDSN IO
-		   register, see Pipelined Read Operations 11.3 */
-		MemReadDOC(docptr, buf, len-2);
-		buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
-		buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
-	}
+	/* disable the ECC engine */
+	WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
 
 	/* Disable flash internally */
 	WriteDOC(0, docptr, Mplus_FlashSelect);
@@ -735,17 +708,10 @@ #endif
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf)
 {
-	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf,
-			 struct nand_oobinfo *oobsel)
-{
 	int i, before, ret = 0;
 	loff_t fto;
 	volatile char dummy;
+	char eccbuf[6];
 	struct DiskOnChip *this = mtd->priv;
 	void __iomem * docptr = this->virtadr;
 	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@@ -795,46 +761,42 @@ static int doc_write_ecc(struct mtd_info
 	/* Disable the ECC engine */
 	WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
 
-	if (eccbuf) {
-		if (before) {
-			/* Write the block status BLOCK_USED (0x5555) */
-			WriteDOC(0x55, docptr, Mil_CDSN_IO);
-			WriteDOC(0x55, docptr, Mil_CDSN_IO);
-		}
-
-		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
-		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+	if (before) {
+		/* Write the block status BLOCK_USED (0x5555) */
+		WriteDOC(0x55, docptr, Mil_CDSN_IO);
+		WriteDOC(0x55, docptr, Mil_CDSN_IO);
 	}
 
+	/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+	WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+
 	MemWriteDOC(docptr, (unsigned char *) buf, len);
 
-	if (eccbuf) {
-		/* Write ECC data to flash, the ECC info is generated by
-		   the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
-		DoC_Delay(docptr, 3);
+	/* Write ECC data to flash, the ECC info is generated by
+	   the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
+	DoC_Delay(docptr, 3);
 
-		/* Read the ECC data through the DiskOnChip ECC logic */
-		for (i = 0; i < 6; i++)
-			eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+	/* Read the ECC data through the DiskOnChip ECC logic */
+	for (i = 0; i < 6; i++)
+		eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
 
-		/* disable the ECC engine */
-		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+	/* disable the ECC engine */
+	WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
 
-		/* Write the ECC data to flash */
-		MemWriteDOC(docptr, eccbuf, 6);
+	/* Write the ECC data to flash */
+	MemWriteDOC(docptr, eccbuf, 6);
 
-		if (!before) {
-			/* Write the block status BLOCK_USED (0x5555) */
-			WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
-			WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
-		}
+	if (!before) {
+		/* Write the block status BLOCK_USED (0x5555) */
+		WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
+		WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
+	}
 
 #ifdef PSYCHO_DEBUG
-		printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-		       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-		       eccbuf[4], eccbuf[5]);
+	printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+	       eccbuf[4], eccbuf[5]);
 #endif
-	}
 
 	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
 	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);


From linux-mtd at lists.infradead.org  Thu Jun 29 03:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 29 Jun 2006 08:59:01 +0100
Subject: MTD: fix all kernel-doc warnings
Message-ID: <E1FvrQT-0007Oh-Eu@pentafluge.infradead.org>

Commit:     844d3b427ef1a4f96e54866747bdb6c6cbca4c6a
Parent:     7f8a894066b826a4baea49c2a3adbba0a56a192f
commit 844d3b427ef1a4f96e54866747bdb6c6cbca4c6a
Author:     Randy Dunlap <rdunlap at xenotime.net>
AuthorDate: Wed Jun 28 21:48:27 2006 -0700
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Thu Jun 29 08:55:00 2006 +0100

    MTD: fix all kernel-doc warnings
    
    Fix all kernel-doc warnings in MTD headers and source files:
    - add some missing struct fields;
    - correct some function parameter names;
    - use kernel-doc format for function doc. headers;
    - nand_ecc.c contains only exported interfaces, no internal ones;
    
    Signed-off-by: Randy Dunlap <rdunlap at xenotime.net>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 Documentation/DocBook/mtdnand.tmpl |    4 +++-
 drivers/mtd/nand/nand_base.c       |   16 ++++++++--------
 drivers/mtd/nand/nand_ecc.c        |    3 +--
 include/linux/mtd/nand.h           |   13 ++++++++++---
 4 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index 6e463d0..32f3856 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -1295,7 +1295,9 @@ #define NAND_BBT_SAVECONTENT	0x00002000
      </para>
 !Idrivers/mtd/nand/nand_base.c
 !Idrivers/mtd/nand/nand_bbt.c
-!Idrivers/mtd/nand/nand_ecc.c
+<!-- No internal functions for kernel-doc:
+X!Idrivers/mtd/nand/nand_ecc.c
+-->
   </chapter>
 
   <chapter id="credits">
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 80a7665..62b8613 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -155,7 +155,7 @@ static u16 nand_read_word(struct mtd_inf
 /**
  * nand_select_chip - [DEFAULT] control CE line
  * @mtd:	MTD device structure
- * @chip:	chipnumber to select, -1 for deselect
+ * @chipnr:	chipnumber to select, -1 for deselect
  *
  * Default select function for 1 chip devices.
  */
@@ -542,7 +542,6 @@ static void nand_command(struct mtd_info
  * Send command to NAND device. This is the version for the new large page
  * devices We dont have the separate regions as we have in the small page
  * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible.
- *
  */
 static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 			    int column, int page_addr)
@@ -656,7 +655,7 @@ static void nand_command_lp(struct mtd_i
 
 /**
  * nand_get_device - [GENERIC] Get chip for selected access
- * @this:	the nand chip descriptor
+ * @chip:	the nand chip descriptor
  * @mtd:	MTD device structure
  * @new_state:	the state which is requested
  *
@@ -696,13 +695,12 @@ nand_get_device(struct nand_chip *chip, 
 /**
  * nand_wait - [DEFAULT]  wait until the command is done
  * @mtd:	MTD device structure
- * @this:	NAND chip structure
+ * @chip:	NAND chip structure
  *
  * Wait for command done. This applies to erase and program only
  * Erase can take up to 400ms and program up to 20ms according to
  * general NAND and SmartMedia specs
- *
-*/
+ */
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 
@@ -896,6 +894,7 @@ static int nand_read_page_syndrome(struc
 /**
  * nand_transfer_oob - [Internal] Transfer oob to client buffer
  * @chip:	nand chip structure
+ * @oob:	oob destination address
  * @ops:	oob ops structure
  */
 static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
@@ -946,6 +945,7 @@ static uint8_t *nand_transfer_oob(struct
  *
  * @mtd:	MTD device structure
  * @from:	offset to read from
+ * @ops:	oob ops structure
  *
  * Internal function. Called with chip held.
  */
@@ -1760,7 +1760,7 @@ static int nand_do_write_oob(struct mtd_
 /**
  * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
  * @mtd:	MTD device structure
- * @from:	offset to read from
+ * @to:		offset to write to
  * @ops:	oob operation description structure
  */
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
@@ -2055,7 +2055,7 @@ static void nand_sync(struct mtd_info *m
 /**
  * nand_block_isbad - [MTD Interface] Check if block at offset is bad
  * @mtd:	MTD device structure
- * @ofs:	offset relative to mtd start
+ * @offs:	offset relative to mtd start
  */
 static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 {
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 2a163e4..dd438ca 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -65,8 +65,7 @@ static const u_char nand_ecc_precalc_tab
 };
 
 /**
- * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code
- *			for 256 byte block
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
  * @mtd:	MTD block structure
  * @dat:	raw data
  * @ecc_code:	buffer for ECC
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 6655927..2266f03 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -202,7 +202,7 @@ typedef enum {
 struct nand_chip;
 
 /**
- * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
+ * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
  * @active:		the mtd device which holds the controller currently
  * @wq:			wait queue to sleep on if a NAND operation is in progress
@@ -223,12 +223,15 @@ struct nand_hw_control {
  * @total:	total number of ecc bytes per page
  * @prepad:	padding information for syndrome based ecc generators
  * @postpad:	padding information for syndrome based ecc generators
+ * @layout:	ECC layout control struct pointer
  * @hwctl:	function to control hardware ecc generator. Must only
  *		be provided if an hardware ECC is available
  * @calculate:	function for ecc calculation or readback from ecc hardware
  * @correct:	function for ecc correction, matching to ecc generator (sw/hw)
  * @read_page:	function to read a page according to the ecc generator requirements
  * @write_page:	function to write a page according to the ecc generator requirements
+ * @read_oob:	function to read chip OOB data
+ * @write_oob:	function to write chip OOB data
  */
 struct nand_ecc_ctrl {
 	nand_ecc_modes_t	mode;
@@ -300,11 +303,15 @@ struct nand_buffers {
  * @cmdfunc:		[REPLACEABLE] hardwarespecific function for writing commands to the chip
  * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on ready
  * @ecc:		[BOARDSPECIFIC] ecc control ctructure
+ * @buffers:		buffer structure for read/write
+ * @hwcontrol:		platform-specific hardware control structure
+ * @ops:		oob operation operands
  * @erase_cmd:		[INTERN] erase command write function, selectable due to AND support
  * @scan_bbt:		[REPLACEABLE] function to scan bad block table
  * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
  * @wq:			[INTERN] wait queue to sleep on if a NAND operation is in progress
  * @state:		[INTERN] the current state of the NAND device
+ * @oob_poi:		poison value buffer
  * @page_shift:		[INTERN] number of address bits in a page (column address bits)
  * @phys_erase_shift:	[INTERN] number of address bits in a physical eraseblock
  * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry
@@ -521,7 +528,7 @@ #define NAND_LARGE_BADBLOCK_POS		0
  * struct platform_nand_chip - chip level device structure
  *
  * @nr_chips:		max. number of chips to scan for
- * @chip_offs:		chip number offset
+ * @chip_offset:	chip number offset
  * @nr_partitions:	number of partitions pointed to by partitions (or zero)
  * @partitions:		mtd partition list
  * @chip_delay:		R/B delay value in us
@@ -546,7 +553,7 @@ struct platform_nand_chip {
  * @hwcontrol:		platform specific hardware control structure
  * @dev_ready:		platform specific function to read ready/busy pin
  * @select_chip:	platform specific chip select function
- * @priv_data:		private data to transport driver specific settings
+ * @priv:		private data to transport driver specific settings
  *
  * All fields are optional and depend on the hardware driver requirements
  */


From linux-mtd at lists.infradead.org  Thu Jun 29 03:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 29 Jun 2006 08:59:01 +0100
Subject: MTD: kernel-doc fixes + additions
Message-ID: <E1FvrQT-0007P0-QK@pentafluge.infradead.org>

Commit:     ea9b6dcc152f09c207117ab121d4fa03d2db282a
Parent:     844d3b427ef1a4f96e54866747bdb6c6cbca4c6a
commit ea9b6dcc152f09c207117ab121d4fa03d2db282a
Author:     Randy Dunlap <rdunlap at xenotime.net>
AuthorDate: Wed Jun 28 21:48:38 2006 -0700
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Thu Jun 29 08:55:41 2006 +0100

    MTD: kernel-doc fixes + additions
    
    Fix some kernel-doc typos/spellos.
    Use kernel-doc syntax in places where it was almost used.
    Correct/add struct, struct field, and function param names where needed.
    
    Signed-off-by: Randy Dunlap <rdunlap at xenotime.net>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 Documentation/DocBook/mtdnand.tmpl |    7 +--
 include/linux/mtd/bbm.h            |   35 +++++++++-------
 include/linux/mtd/mtd.h            |    4 +-
 include/linux/mtd/nand.h           |    3 -
 include/linux/mtd/onenand.h        |   77 +++++++++++++++++++++---------------
 include/mtd/mtd-abi.h              |    2 -
 6 files changed, 69 insertions(+), 59 deletions(-)

diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
index 32f3856..630159c 100644
--- a/Documentation/DocBook/mtdnand.tmpl
+++ b/Documentation/DocBook/mtdnand.tmpl
@@ -109,7 +109,7 @@
 		for most of the implementations. These functions can be replaced by the
 		board driver if neccecary. Those functions are called via pointers in the
 		NAND chip description structure. The board driver can set the functions which
-		should be replaced by board dependend functions before calling nand_scan().
+		should be replaced by board dependent functions before calling nand_scan().
 		If the function pointer is NULL on entry to nand_scan() then the pointer
 		is set to the default function which is suitable for the detected chip type.
 		</para></listitem>
@@ -133,7 +133,7 @@
 	  	[REPLACEABLE]</para><para>
 		Replaceable members hold hardware related functions which can be 
 		provided by the board driver. The board driver can set the functions which
-		should be replaced by board dependend functions before calling nand_scan().
+		should be replaced by board dependent functions before calling nand_scan().
 		If the function pointer is NULL on entry to nand_scan() then the pointer
 		is set to the default function which is suitable for the detected chip type.
 		</para></listitem>
@@ -156,9 +156,8 @@
      	<title>Basic board driver</title>
 	<para>
 		For most boards it will be sufficient to provide just the
-		basic functions and fill out some really board dependend
+		basic functions and fill out some really board dependent
 		members in the nand chip description structure.
-		See drivers/mtd/nand/skeleton for reference.
 	</para>
 	<sect1>
 		<title>Basic defines</title>
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 7a7fbe8..1221b7c 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -19,21 +19,21 @@ #define NAND_MAX_CHIPS		8
 
 /**
  * struct nand_bbt_descr - bad block table descriptor
- * @param options	options for this descriptor
- * @param pages		the page(s) where we find the bbt, used with
+ * @options:		options for this descriptor
+ * @pages:		the page(s) where we find the bbt, used with
  * 			option BBT_ABSPAGE when bbt is searched,
  * 			then we store the found bbts pages here.
  *			Its an array and supports up to 8 chips now
- * @param offs		offset of the pattern in the oob area of the page
- * @param veroffs	offset of the bbt version counter in the oob are of the page
- * @param version	version read from the bbt page during scan
- * @param len		length of the pattern, if 0 no pattern check is performed
- * @param maxblocks	maximum number of blocks to search for a bbt. This number of
- *			blocks is reserved at the end of the device
+ * @offs:		offset of the pattern in the oob area of the page
+ * @veroffs:		offset of the bbt version counter in the oob area of the page
+ * @version:		version read from the bbt page during scan
+ * @len:		length of the pattern, if 0 no pattern check is performed
+ * @maxblocks:		maximum number of blocks to search for a bbt. This
+ *			number of blocks is reserved at the end of the device
  *			where the tables are written.
- * @param reserved_block_code	if non-0, this pattern denotes a reserved
+ * @reserved_block_code: if non-0, this pattern denotes a reserved
  *			(rather than bad) block in the stored bbt
- * @param pattern	pattern to identify bad block table or factory marked
+ * @pattern:		pattern to identify bad block table or factory marked
  *			good / bad blocks, can be NULL, if len = 0
  *
  * Descriptor for the bad block table marker and the descriptor for the
@@ -93,12 +93,15 @@ #define NAND_BBT_SCAN_MAXBLOCKS	4
 #define ONENAND_BADBLOCK_POS	0
 
 /**
- * struct bbt_info - [GENERIC] Bad Block Table data structure
- * @param bbt_erase_shift	[INTERN] number of address bits in a bbt entry
- * @param badblockpos		[INTERN] position of the bad block marker in the oob area
- * @param bbt			[INTERN] bad block table pointer
- * @param badblock_pattern	[REPLACEABLE] bad block scan pattern used for initial bad block scan
- * @param priv			[OPTIONAL] pointer to private bbm date
+ * struct bbm_info - [GENERIC] Bad Block Table data structure
+ * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry
+ * @badblockpos:	[INTERN] position of the bad block marker in the oob area
+ * @options:		options for this descriptor
+ * @bbt:		[INTERN] bad block table pointer
+ * @isbad_bbt:		function to determine if a block is bad
+ * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for
+ *			initial bad block scan
+ * @priv:		[OPTIONAL] pointer to private bbm date
  */
 struct bbm_info {
 	int bbt_erase_shift;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9b7a2b5..94a443d 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -77,11 +77,11 @@ typedef enum {
  *
  * @len:	number of bytes to write/read. When a data buffer is given
  *		(datbuf != NULL) this is the number of data bytes. When
- +		no data buffer is available this is the number of oob bytes.
+ *		no data buffer is available this is the number of oob bytes.
  *
  * @retlen:	number of bytes written/read. When a data buffer is given
  *		(datbuf != NULL) this is the number of data bytes. When
- +		no data buffer is available this is the number of oob bytes.
+ *		no data buffer is available this is the number of oob bytes.
  *
  * @ooblen:	number of oob bytes per page
  * @ooboffs:	offset of oob data in the oob area (only relevant when
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 2266f03..0b4cd2f 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -407,7 +407,6 @@ #define NAND_MFR_HYNIX		0xad
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
- *
  * @name:	Identify the device type
  * @id:		device ID code
  * @pagesize:	Pagesize in bytes. Either 256 or 512 or 0
@@ -526,7 +525,6 @@ #define NAND_LARGE_BADBLOCK_POS		0
 
 /**
  * struct platform_nand_chip - chip level device structure
- *
  * @nr_chips:		max. number of chips to scan for
  * @chip_offset:	chip number offset
  * @nr_partitions:	number of partitions pointed to by partitions (or zero)
@@ -549,7 +547,6 @@ struct platform_nand_chip {
 
 /**
  * struct platform_nand_ctrl - controller level device structure
- *
  * @hwcontrol:		platform specific hardware control structure
  * @dev_ready:		platform specific function to read ready/busy pin
  * @select_chip:	platform specific chip select function
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 9ce9a48..1f49721 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -23,7 +23,7 @@ extern int onenand_scan(struct mtd_info 
 /* Free resources held by the OneNAND device */
 extern void onenand_release(struct mtd_info *mtd);
 
-/**
+/*
  * onenand_state_t - chip states
  * Enumeration for OneNAND flash chip state
  */
@@ -42,9 +42,9 @@ typedef enum {
 
 /**
  * struct onenand_bufferram - OneNAND BufferRAM Data
- * @param block		block address in BufferRAM
- * @param page		page address in BufferRAM
- * @param valid		valid flag
+ * @block:		block address in BufferRAM
+ * @page:		page address in BufferRAM
+ * @valid:		valid flag
  */
 struct onenand_bufferram {
 	int block;
@@ -54,32 +54,43 @@ struct onenand_bufferram {
 
 /**
  * struct onenand_chip - OneNAND Private Flash Chip Data
- * @param base		[BOARDSPECIFIC] address to access OneNAND
- * @param chipsize	[INTERN] the size of one chip for multichip arrays
- * @param device_id	[INTERN] device ID
- * @param verstion_id	[INTERN] version ID
- * @param options	[BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about
- * @param erase_shift	[INTERN] number of address bits in a block
- * @param page_shift	[INTERN] number of address bits in a page
- * @param ppb_shift	[INTERN] number of address bits in a pages per block
- * @param page_mask	[INTERN] a page per block mask
- * @param bufferam_index	[INTERN] BufferRAM index
- * @param bufferam	[INTERN] BufferRAM info
- * @param readw		[REPLACEABLE] hardware specific function for read short
- * @param writew	[REPLACEABLE] hardware specific function for write short
- * @param command	[REPLACEABLE] hardware specific function for writing commands to the chip
- * @param wait		[REPLACEABLE] hardware specific function for wait on ready
- * @param read_bufferram	[REPLACEABLE] hardware specific function for BufferRAM Area
- * @param write_bufferram	[REPLACEABLE] hardware specific function for BufferRAM Area
- * @param read_word	[REPLACEABLE] hardware specific function for read register of OneNAND
- * @param write_word	[REPLACEABLE] hardware specific function for write register of OneNAND
- * @param scan_bbt	[REPLACEALBE] hardware specific function for scaning Bad block Table
- * @param chip_lock	[INTERN] spinlock used to protect access to this structure and the chip
- * @param wq		[INTERN] wait queue to sleep on if a OneNAND operation is in progress
- * @param state		[INTERN] the current state of the OneNAND device
- * @param ecclayout	[REPLACEABLE] the default ecc placement scheme
- * @param bbm		[REPLACEABLE] pointer to Bad Block Management
- * @param priv		[OPTIONAL] pointer to private chip date
+ * @base:		[BOARDSPECIFIC] address to access OneNAND
+ * @chipsize:		[INTERN] the size of one chip for multichip arrays
+ * @device_id:		[INTERN] device ID
+ * @density_mask:	chip density, used for DDP devices
+ * @verstion_id:	[INTERN] version ID
+ * @options:		[BOARDSPECIFIC] various chip options. They can
+ *			partly be set to inform onenand_scan about
+ * @erase_shift:	[INTERN] number of address bits in a block
+ * @page_shift:		[INTERN] number of address bits in a page
+ * @ppb_shift:		[INTERN] number of address bits in a pages per block
+ * @page_mask:		[INTERN] a page per block mask
+ * @bufferram_index:	[INTERN] BufferRAM index
+ * @bufferram:		[INTERN] BufferRAM info
+ * @readw:		[REPLACEABLE] hardware specific function for read short
+ * @writew:		[REPLACEABLE] hardware specific function for write short
+ * @command:		[REPLACEABLE] hardware specific function for writing
+ *			commands to the chip
+ * @wait:		[REPLACEABLE] hardware specific function for wait on ready
+ * @read_bufferram:	[REPLACEABLE] hardware specific function for BufferRAM Area
+ * @write_bufferram:	[REPLACEABLE] hardware specific function for BufferRAM Area
+ * @read_word:		[REPLACEABLE] hardware specific function for read
+ *			register of OneNAND
+ * @write_word:		[REPLACEABLE] hardware specific function for write
+ *			register of OneNAND
+ * @mmcontrol:		sync burst read function
+ * @block_markbad:	function to mark a block as bad
+ * @scan_bbt:		[REPLACEALBE] hardware specific function for scanning
+ *			Bad block Table
+ * @chip_lock:		[INTERN] spinlock used to protect access to this
+ *			structure and the chip
+ * @wq:			[INTERN] wait queue to sleep on if a OneNAND
+ *			operation is in progress
+ * @state:		[INTERN] the current state of the OneNAND device
+ * @page_buf:		data buffer
+ * @ecclayout:		[REPLACEABLE] the default ecc placement scheme
+ * @bbm:		[REPLACEABLE] pointer to Bad Block Management
+ * @priv:		[OPTIONAL] pointer to private chip date
  */
 struct onenand_chip {
 	void __iomem		*base;
@@ -147,9 +158,9 @@ #define ONENAND_PAGEBUF_ALLOC		(0x1000)
 #define ONENAND_MFR_SAMSUNG	0xec
 
 /**
- * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
- * @param name:		Manufacturer name
- * @param id:		manufacturer ID code of device.
+ * struct onenand_manufacturers - NAND Flash Manufacturer ID Structure
+ * @name:	Manufacturer name
+ * @id:		manufacturer ID code of device.
 */
 struct onenand_manufacturers {
         int id;
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 31329fc..1da3f7f 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -133,7 +133,7 @@ struct nand_ecclayout {
 };
 
 /**
- * struct mtd_ecc_stats - error correction status
+ * struct mtd_ecc_stats - error correction stats
  *
  * @corrected:	number of corrected bits
  * @failed:	number of uncorrectable errors


From linux-mtd at lists.infradead.org  Thu Jun 29 10:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 29 Jun 2006 15:59:01 +0100
Subject: [JFFS2][XATTR] Fix xd->refcnt race condition
Message-ID: <E1Fvxyv-0002Dx-TV@pentafluge.infradead.org>

Commit:     c6e8c6ccf96e9249805d0e9828b994f4c926ad51
Parent:     ea9b6dcc152f09c207117ab121d4fa03d2db282a
commit c6e8c6ccf96e9249805d0e9828b994f4c926ad51
Author:     KaiGai Kohei <kaigai at ak.jp.nec.com>
AuthorDate: Thu Jun 29 15:33:02 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Thu Jun 29 15:33:02 2006 +0100

    [JFFS2][XATTR] Fix xd->refcnt race condition
    
    When xd->refcnt is checked whether this xdatum should be released
    or not, atomic_dec_and_lock() is used to ensure holding the
    c->erase_completion_lock.
    
    This fix change a specification of delete_xattr_datum().
    Previously, it's only called when xd->refcnt equals zero.
    (calling it with positive xd->refcnt cause a BUG())
    If you applied this patch, the function checks whether
    xd->refcnt is zero or not under the spinlock if necessary.
    Then, it marks xd DEAD flahs and links with xattr_dead_list
    or releases it immediately when xd->refcnt become zero.
    
    Signed-off-by: KaiGai Kohei <kaigai at ak.jp.nec.com>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/xattr.c |   45 ++++++++++++++++++++++-----------------------
 1 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 18e66db..25bc1ae 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -50,9 +50,10 @@ #include "nodelist.h"
  *   is used to write xdatum to medium. xd->version will be incremented.
  * create_xattr_datum(c, xprefix, xname, xvalue, xsize)
  *   is used to create new xdatum and write to medium.
- * delete_xattr_datum(c, xd)
- *   is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows
- *   GC to reclaim those physical nodes.
+ * unrefer_xattr_datum(c, xd)
+ *   is used to delete a xdatum. When nobody refers this xdatum, JFFS2_XFLAGS_DEAD
+ *   is set on xd->flags and chained xattr_dead_list or release it immediately.
+ *   In the first case, the garbage collector release it later.
  * -------------------------------------------------- */
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
@@ -394,22 +395,24 @@ static struct jffs2_xattr_datum *create_
 	return xd;
 }
 
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
-	BUG_ON(atomic_read(&xd->refcnt));
+	if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
+		uint32_t xid = xd->xid, version = xd->version;
 
-	unload_xattr_datum(c, xd);
-	xd->flags |= JFFS2_XFLAGS_DEAD;
-	spin_lock(&c->erase_completion_lock);
-	if (xd->node == (void *)xd) {
-		BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
-		jffs2_free_xattr_datum(xd);
-	} else {
-		list_add(&xd->xindex, &c->xattr_dead_list);
+		unload_xattr_datum(c, xd);
+		xd->flags |= JFFS2_XFLAGS_DEAD;
+		if (xd->node == (void *)xd) {
+			BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID));
+			jffs2_free_xattr_datum(xd);
+		} else {
+			list_add(&xd->xindex, &c->xattr_dead_list);
+		}
+		spin_unlock(&c->erase_completion_lock);
+
+		dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xid, version);
 	}
-	spin_unlock(&c->erase_completion_lock);
-	dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version);
 }
 
 /* -------- xref related functions ------------------
@@ -580,8 +583,7 @@ static void delete_xattr_ref(struct jffs
 	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
 		  ref->ino, ref->xid, ref->xseqno);
 
-	if (atomic_dec_and_test(&xd->refcnt))
-		delete_xattr_datum(c, xd);
+	unrefer_xattr_datum(c, xd);
 }
 
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
@@ -1119,8 +1121,7 @@ int do_jffs2_setxattr(struct inode *inod
 					ref->next = c->xref_dead_list;
 					c->xref_dead_list = ref;
 					spin_unlock(&c->erase_completion_lock);
-					if (atomic_dec_and_test(&xd->refcnt))
-						delete_xattr_datum(c, xd);
+					unrefer_xattr_datum(c, xd);
 				} else {
 					ref->ic = ic;
 					ref->xd = xd;
@@ -1156,8 +1157,7 @@ int do_jffs2_setxattr(struct inode *inod
 	down_write(&c->xattr_sem);
 	if (rc) {
 		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-		if (atomic_dec_and_test(&xd->refcnt))
-			delete_xattr_datum(c, xd);
+		unrefer_xattr_datum(c, xd);
 		up_write(&c->xattr_sem);
 		return rc;
 	}
@@ -1170,8 +1170,7 @@ int do_jffs2_setxattr(struct inode *inod
 			ic->xref = ref;
 		}
 		rc = PTR_ERR(newref);
-		if (atomic_dec_and_test(&xd->refcnt))
-			delete_xattr_datum(c, xd);
+		unrefer_xattr_datum(c, xd);
 	} else if (ref) {
 		delete_xattr_ref(c, ref);
 	}


From linux-mtd at lists.infradead.org  Thu Jun 29 16:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 29 Jun 2006 21:59:01 +0100
Subject: [MTD] NAND: Fix broken sharpsl driver
Message-ID: <E1Fw3bJ-0002wV-K2@pentafluge.infradead.org>

Commit:     27a288677de33c50af980e55abec5643db4cd0b8
Parent:     c6e8c6ccf96e9249805d0e9828b994f4c926ad51
commit 27a288677de33c50af980e55abec5643db4cd0b8
Author:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
AuthorDate: Thu Jun 29 21:25:10 2006 +0200
Commit:     Thomas Gleixner <tglx at cruncher.tec.linutronix.de>
CommitDate: Thu Jun 29 21:25:10 2006 +0200

    [MTD] NAND: Fix broken sharpsl driver
    
    Remove the not longer supported NO_VIRTBLOCKS flag and remove
    an unused variable while at it.
    
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
---
 drivers/mtd/nand/sharpsl.c |    7 -------
 1 files changed, 0 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 2174365..fbeedc3 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -237,11 +237,6 @@ static int __init sharpsl_nand_init(void
 		}
 	}
 
-	if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) {
-		/* Need to use small eraseblock size for backward compatibility */
-		sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
-	}
-
 	add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
 
 	/* Return happy */
@@ -255,8 +250,6 @@ module_init(sharpsl_nand_init);
  */
 static void __exit sharpsl_nand_cleanup(void)
 {
-	struct nand_chip *this = (struct nand_chip *)&sharpsl_mtd[1];
-
 	/* Release resources, unregister device */
 	nand_release(sharpsl_mtd);
 


From linux-mtd at lists.infradead.org  Thu Jun 29 18:59:01 2006
From: linux-mtd at lists.infradead.org (Linux-MTD Mailing List)
Date: Thu, 29 Jun 2006 23:59:01 +0100
Subject: fs/jffs2/: make 2 functions static
Message-ID: <E1Fw5TR-000676-FX@pentafluge.infradead.org>

Commit:     c05d52c748da10a3f27f6e638875514153776b15
Parent:     27a288677de33c50af980e55abec5643db4cd0b8
commit c05d52c748da10a3f27f6e638875514153776b15
Author:     Adrian Bunk <bunk at stusta.de>
AuthorDate: Thu Jun 22 12:03:35 2006 +0200
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Thu Jun 29 23:08:49 2006 +0100

    fs/jffs2/: make 2 functions static
    
    This patch makes two needlessly global functions static.
    
    Signed-off-by: Adrian Bunk <bunk at stusta.de>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 fs/jffs2/malloc.c   |    2 +-
 fs/jffs2/nodelist.h |    2 --
 fs/jffs2/scan.c     |    4 ++--
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 8310c95..33f2910 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -190,7 +190,7 @@ void jffs2_free_tmp_dnode_info(struct jf
 	kmem_cache_free(tmp_dnode_info_slab, x);
 }
 
-struct jffs2_raw_node_ref *jffs2_alloc_refblock(void)
+static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void)
 {
 	struct jffs2_raw_node_ref *ret;
 
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index b16c60b..be6d4a4 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -427,8 +427,6 @@ char *jffs2_getlink(struct jffs2_sb_info
 /* scan.c */
 int jffs2_scan_medium(struct jffs2_sb_info *c);
 void jffs2_rotate_lists(struct jffs2_sb_info *c);
-int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
-				uint32_t ofs, uint32_t len);
 struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
 int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t size);
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 2bfdc33..e241346 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -274,8 +274,8 @@ #endif
 	return ret;
 }
 
-int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
-				uint32_t ofs, uint32_t len)
+static int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
+			       uint32_t ofs, uint32_t len)
 {
 	int ret;
 	size_t retlen;


