public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH]Add JFFS2 eraseblock header support
@ 2005-09-20  7:45 zhao forrest
  2005-09-20 10:24 ` Jörn Engel
  2005-09-20 11:29 ` Artem B. Bityutskiy
  0 siblings, 2 replies; 13+ messages in thread
From: zhao forrest @ 2005-09-20  7:45 UTC (permalink / raw)
  To: dedekind, joern; +Cc: linux-mtd

[-- Attachment #1: Type: text/plain, Size: 1183 bytes --]

Hi,
This is the patch for eraseblock header, the high-level design
can be found at http://lists.infradead.org/pipermail/linux-mtd/
2005-August/013374.html.

This patch closely follows the high-level design. Here I list
some main implementation points:
1 eraseblock_header replaces clean marker, clean marker no
longer exists.
2 now eraseblock header carrys version and erase count, but the
length of eraseblock header is not constant and it allows further
extention.
3 for NAND flash, the eraseblock header is stored in OOB and it
may span several OOBs
4 old JFFS2 binaries reject mounting new JFFS2 images
5 change the type of dirent/inode nodes and adding INCOMPAT flag
there in order to make old JFFS2 binaries reject mounting new
JFFS2 images for NAND flash
6 new JFFS2 binary, when mounting an old JFFS2 image, will reject
mounting unless the old JFFS2 image doesn't use 1:N(N>1)mapping.
7 If JFFS2 finds that the version of the image is larger, it will
reject mounting the image
8 currently this patch doesn't take the "eraseblock summary" patch
into account. It's greatly appreciated if Ferenc can help to add
the missing part :)

Your comments are welcome.

Thanks,
Forrest


[-- Attachment #2: eraseblock_header.patch --]
[-- Type: application/octet-stream, Size: 39148 bytes --]

diff -auNrp ./mtd/fs/jffs2/build.c ./mtd_eraseblock_header/fs/jffs2/build.c
--- ./mtd/fs/jffs2/build.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/build.c	2005-09-20 14:33:03.000000000 +0800
@@ -337,6 +337,8 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 		c->blocks[i].first_node = NULL;
 		c->blocks[i].last_node = NULL;
 		c->blocks[i].bad_count = 0;
+		c->blocks[i].has_eraseblock_header = 0;
+		c->blocks[i].erase_count = 0;
 	}
 
 	INIT_LIST_HEAD(&c->clean_list);
diff -auNrp ./mtd/fs/jffs2/debug.c ./mtd_eraseblock_header/fs/jffs2/debug.c
--- ./mtd/fs/jffs2/debug.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/debug.c	2005-09-20 14:33:05.000000000 +0800
@@ -667,6 +667,7 @@ __jffs2_dbg_dump_node(struct jffs2_sb_in
 	switch(je16_to_cpu(node.u.nodetype)) {
 
 	case JFFS2_NODETYPE_INODE:
+	case JFFS2_NODETYPE_INODE_EBH:
 
 		printk(JFFS2_DBG_LVL "the node is inode node\n");
 		printk(JFFS2_DBG_LVL "ino:\t%#08x\n",
@@ -711,6 +712,7 @@ __jffs2_dbg_dump_node(struct jffs2_sb_in
 		break;
 
 	case JFFS2_NODETYPE_DIRENT:
+	case JFFS2_NODETYPE_DIRENT_EBH:
 
 		printk(JFFS2_DBG_LVL "the node is dirent node\n");
 		printk(JFFS2_DBG_LVL "pino:\t%#08x\n",
diff -auNrp ./mtd/fs/jffs2/dir.c ./mtd_eraseblock_header/fs/jffs2/dir.c
--- ./mtd/fs/jffs2/dir.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/dir.c	2005-09-20 14:33:05.000000000 +0800
@@ -391,7 +391,7 @@ static int jffs2_symlink (struct inode *
 	down(&dir_f->sem);
 
 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 
@@ -521,7 +521,7 @@ static int jffs2_mkdir (struct inode *di
 	down(&dir_f->sem);
 
 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 
@@ -677,7 +677,7 @@ static int jffs2_mknod (struct inode *di
 	down(&dir_f->sem);
 
 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 
diff -auNrp ./mtd/fs/jffs2/erase.c ./mtd_eraseblock_header/fs/jffs2/erase.c
--- ./mtd/fs/jffs2/erase.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/erase.c	2005-09-20 14:40:26.000000000 +0800
@@ -210,6 +210,10 @@ static void jffs2_erase_callback(struct 
 	} else {
 		jffs2_erase_succeeded(priv->c, priv->jeb);
 	}	
+
+	if (!priv->jeb->has_eraseblock_header) {
+		priv->jeb->has_eraseblock_header = 1;
+	}
 	kfree(instr);
 }
 #endif /* !__ECOS */
@@ -362,16 +366,14 @@ static void jffs2_mark_erased_block(stru
 	}
 
 	/* Write the erase complete marker */	
-	D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
+	D1(printk(KERN_DEBUG "Writing eraseblock header to block at 0x%08x\n", jeb->offset));
 	bad_offset = jeb->offset;
 
 	/* Cleanmarker in oob area or no cleanmarker at all ? */
-	if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
+	if (jffs2_cleanmarker_oob(c)) {
 
-		if (jffs2_cleanmarker_oob(c)) {
-			if (jffs2_write_nand_cleanmarker(c, jeb))
-				goto filebad;
-		}
+		if (jffs2_write_nand_cleanmarker(c, jeb))
+			goto filebad;
 
 		jeb->first_node = jeb->last_node = NULL;
 		jeb->free_size = c->sector_size;
@@ -382,10 +384,14 @@ static void jffs2_mark_erased_block(stru
 	} else {
 
 		struct kvec vecs[1];
-		struct jffs2_unknown_node marker = {
+		struct jffs2_eraseblock_header marker = {
 			.magic =	cpu_to_je16(JFFS2_MAGIC_BITMASK),
-			.nodetype =	cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
-			.totlen =	cpu_to_je32(c->cleanmarker_size)
+			.nodetype =	cpu_to_je16(JFFS2_NODETYPE_ERASEBLOCK_HEADER),
+			.totlen =	cpu_to_je32(PAD(c->eraseblock_header_size)),
+			.fs_version =   cpu_to_je32(JFFS2_VERSION),
+			.erase_count =  cpu_to_je32(jeb->erase_count),
+			.dsize =        cpu_to_je16(0),
+			.data_crc =     cpu_to_je32(0)
 		};
 
 		marker_ref = jffs2_alloc_raw_node_ref();
@@ -395,6 +401,7 @@ static void jffs2_mark_erased_block(stru
 		}
 
 		marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
+		marker.node_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_eraseblock_header)-8));
 
 		vecs[0].iov_base = (unsigned char *) ▮
 		vecs[0].iov_len = sizeof(marker);
@@ -415,12 +422,12 @@ static void jffs2_mark_erased_block(stru
 		marker_ref->next_in_ino = NULL;
 		marker_ref->next_phys = NULL;
 		marker_ref->flash_offset = jeb->offset | REF_NORMAL;
-		marker_ref->__totlen = c->cleanmarker_size;
+		marker_ref->__totlen = PAD(c->eraseblock_header_size);
 			
 		jeb->first_node = jeb->last_node = marker_ref;
 			
-		jeb->free_size = c->sector_size - c->cleanmarker_size;
-		jeb->used_size = c->cleanmarker_size;
+		jeb->free_size = c->sector_size - PAD(c->eraseblock_header_size);
+		jeb->used_size = PAD(c->eraseblock_header_size);
 		jeb->dirty_size = 0;
 		jeb->wasted_size = 0;
 	}
diff -auNrp ./mtd/fs/jffs2/file.c ./mtd_eraseblock_header/fs/jffs2/file.c
--- ./mtd/fs/jffs2/file.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/file.c	2005-09-20 14:33:06.000000000 +0800
@@ -146,7 +146,7 @@ static int jffs2_prepare_write (struct f
 		memset(&ri, 0, sizeof(ri));
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 		ri.totlen = cpu_to_je32(sizeof(ri));
 		ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
 
diff -auNrp ./mtd/fs/jffs2/fs.c ./mtd_eraseblock_header/fs/jffs2/fs.c
--- ./mtd/fs/jffs2/fs.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/fs.c	2005-09-20 14:33:06.000000000 +0800
@@ -86,7 +86,7 @@ static int jffs2_do_setattr (struct inod
 	ivalid = iattr->ia_valid;
 	
 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 	ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
 
@@ -476,6 +476,7 @@ int jffs2_do_fill_super(struct super_blo
 	}
 
 	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+	c->eraseblock_header_size = sizeof(struct jffs2_eraseblock_header);
 	/* Joern -- stick alignment for weird 8-byte-page flash here */
 
 	/* NAND (or other bizarre) flash... do setup accordingly */
diff -auNrp ./mtd/fs/jffs2/gc.c ./mtd_eraseblock_header/fs/jffs2/gc.c
--- ./mtd/fs/jffs2/gc.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/gc.c	2005-09-20 14:33:06.000000000 +0800
@@ -545,6 +545,7 @@ static int jffs2_garbage_collect_pristin
 
 	switch(je16_to_cpu(node->u.nodetype)) {
 	case JFFS2_NODETYPE_INODE:
+	case JFFS2_NODETYPE_INODE_EBH:
 		crc = crc32(0, node, sizeof(node->i)-8);
 		if (je32_to_cpu(node->i.node_crc) != crc) {
 			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
@@ -563,6 +564,7 @@ static int jffs2_garbage_collect_pristin
 		break;
 
 	case JFFS2_NODETYPE_DIRENT:
+	case JFFS2_NODETYPE_DIRENT_EBH:
 		crc = crc32(0, node, sizeof(node->d)-8);
 		if (je32_to_cpu(node->d.node_crc) != crc) {
 			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
@@ -724,7 +726,7 @@ static int jffs2_garbage_collect_metadat
 	
 	memset(&ri, 0, sizeof(ri));
 	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 	ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen);
 	ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
 
@@ -769,7 +771,7 @@ static int jffs2_garbage_collect_dirent(
 	int ret;
 
 	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd.nsize = strlen(fd->name);
 	rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize);
 	rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4));
@@ -864,7 +866,7 @@ static int jffs2_garbage_collect_deletio
 				continue;
 			}
 
-			if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)
+			if ((je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) && (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT_EBH))
 				continue;
 
 			/* If the name CRC doesn't match, skip */
@@ -940,7 +942,7 @@ static int jffs2_garbage_collect_hole(st
 			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);
 			goto fill;
 		}
-		if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
+		if ((je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) && (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE_EBH)) {
 			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
 			       ref_offset(fn->raw),
 			       je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
@@ -971,7 +973,7 @@ static int jffs2_garbage_collect_hole(st
 	} else {
 	fill:
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 		ri.totlen = cpu_to_je32(sizeof(ri));
 		ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
 
@@ -1243,7 +1245,7 @@ static int jffs2_garbage_collect_dnode(s
 		comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 		ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
 		ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
 
diff -auNrp ./mtd/fs/jffs2/nodelist.h ./mtd_eraseblock_header/fs/jffs2/nodelist.h
--- ./mtd/fs/jffs2/nodelist.h	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/nodelist.h	2005-09-20 15:07:29.000000000 +0800
@@ -196,6 +196,9 @@ struct jffs2_eraseblock
 	struct jffs2_raw_node_ref *last_node;
 
 	struct jffs2_raw_node_ref *gc_node;	/* Next node to be garbage collected */
+
+	uint8_t has_eraseblock_header;
+	uint32_t erase_count;
 };
 
 static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c)
@@ -374,6 +377,8 @@ struct jffs2_node_frag *jffs2_alloc_node
 void jffs2_free_node_frag(struct jffs2_node_frag *);
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
+struct jffs2_eraseblock *jffs2_alloc_eraseblock(void);
+void jffs2_free_eraseblock(struct jffs2_eraseblock *);
 
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
@@ -404,7 +409,7 @@ void jffs2_erase_pending_blocks(struct j
 /* wbuf.c */
 int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
-int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *data_len);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 #endif
 
diff -auNrp ./mtd/fs/jffs2/nodemgmt.c ./mtd_eraseblock_header/fs/jffs2/nodemgmt.c
--- ./mtd/fs/jffs2/nodemgmt.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/nodemgmt.c	2005-09-20 14:49:38.000000000 +0800
@@ -340,7 +340,10 @@ static int jffs2_do_reserve_space(struct
 
 		jeb = c->nextblock;
 
-		if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
+		if ((!jeb->has_eraseblock_header && jeb->free_size != c->sector_size - c->cleanmarker_size) ||
+		    (jeb->has_eraseblock_header && c->eraseblock_header_size && jeb->free_size != c->sector_size - jeb->first_node->__totlen) ||
+		    (jeb->has_eraseblock_header && !c->eraseblock_header_size && jeb->free_size != c->sector_size))
+		{
 			printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
 			goto restart;
 		}
@@ -350,8 +353,8 @@ static int jffs2_do_reserve_space(struct
 	*ofs = jeb->offset + (c->sector_size - jeb->free_size);
 	*len = jeb->free_size - reserved_size;
 
-	if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
-	    !jeb->first_node->next_in_ino) {
+	if ((!jeb->has_eraseblock_header && c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && !jeb->first_node->next_in_ino)
+	     || (jeb->has_eraseblock_header && c->eraseblock_header_size && jeb->used_size == jeb->first_node->__totlen && !jeb->first_node->next_in_ino)) {
 		/* Only node in it beforehand was a CLEANMARKER node (we think). 
 		   So mark it obsolete now that there's going to be another node
 		   in the block. This will reduce used_size to zero but We've 
diff -auNrp ./mtd/fs/jffs2/os-linux.h ./mtd_eraseblock_header/fs/jffs2/os-linux.h
--- ./mtd/fs/jffs2/os-linux.h	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/os-linux.h	2005-09-20 15:04:29.000000000 +0800
@@ -122,8 +122,8 @@ static inline void jffs2_init_inode_info
 int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
 int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
 int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
-int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
-int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,uint32_t data_len);
+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *data_len);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 void jffs2_wbuf_timeout(unsigned long data);
diff -auNrp ./mtd/fs/jffs2/readinode.c ./mtd_eraseblock_header/fs/jffs2/readinode.c
--- ./mtd/fs/jffs2/readinode.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/readinode.c	2005-09-20 14:33:08.000000000 +0800
@@ -552,6 +552,7 @@ static int jffs2_get_inode_nodes(struct 
 		switch (je16_to_cpu(node->u.nodetype)) {
 			
 		case JFFS2_NODETYPE_DIRENT:
+		case JFFS2_NODETYPE_DIRENT_EBH:
 
 			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) {
 				err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart);
@@ -572,6 +573,7 @@ static int jffs2_get_inode_nodes(struct 
 			break;
 
 		case JFFS2_NODETYPE_INODE:
+		case JFFS2_NODETYPE_INODE_EBH:
 			
 			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) {
 				err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart);
diff -auNrp ./mtd/fs/jffs2/scan.c ./mtd_eraseblock_header/fs/jffs2/scan.c
--- ./mtd/fs/jffs2/scan.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/scan.c	2005-09-20 14:54:43.000000000 +0800
@@ -46,6 +46,8 @@ static int jffs2_scan_inode_node(struct 
 				 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 				 struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);
+static int jffs2_scan_eraseblock_header(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				 struct jffs2_eraseblock_header *eh, uint32_t ofs);
 
 static inline int min_free(struct jffs2_sb_info *c)
 {
@@ -292,6 +294,11 @@ int jffs2_fill_scan_buf (struct jffs2_sb
 
 int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
+	if (jeb->has_eraseblock_header && c->eraseblock_header_size) {
+		if (!jeb->first_node->next_phys && !jeb->dirty_size)
+			return BLK_STATE_CLEANMARKER;
+	}
+
 	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
 		&& (!jeb->first_node || !jeb->first_node->next_phys) )
 		return BLK_STATE_CLEANMARKER;
@@ -321,7 +328,7 @@ static int jffs2_scan_eraseblock (struct
 
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
-	int cleanmarkerfound = 0;
+	uint32_t data_len = 0;
 #endif
 
 	ofs = jeb->offset;
@@ -331,13 +338,13 @@ static int jffs2_scan_eraseblock (struct
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	if (jffs2_cleanmarker_oob(c)) {
-		int ret = jffs2_check_nand_cleanmarker(c, jeb);
+		int ret = jffs2_check_nand_cleanmarker(c, jeb, &data_len);
 		D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
 		/* Even if it's not found, we still scan to see
 		   if the block is empty. We use this information
 		   to decide whether to erase it or not. */
 		switch (ret) {
-		case 0:		cleanmarkerfound = 1; break;
+		case 0:		break;
 		case 1: 	break;
 		case 2: 	return BLK_STATE_BADBLOCK;
 		case 3:		return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
@@ -403,10 +410,10 @@ static int jffs2_scan_eraseblock (struct
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 		if (jffs2_cleanmarker_oob(c)) {
 			/* scan oob, take care of cleanmarker */
-			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
+			int ret = jffs2_check_oob_empty(c, jeb, data_len);
 			D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
 			switch (ret) {
-			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
+			case 0:		return data_len ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
 			case 1: 	return BLK_STATE_ALLDIRTY;
 			default: 	return ret;
 			}
@@ -502,6 +509,13 @@ scan_more:	
 				return BLK_STATE_CLEANMARKER;
 			}
 
+			if (jeb->has_eraseblock_header && c->eraseblock_header_size) {
+				if (!jeb->first_node->next_phys && !jeb->dirty_size) {
+					D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
+					return BLK_STATE_CLEANMARKER;
+				}
+			}
+
 			/* See how much more there is to read in this eraseblock... */
 			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 			if (!buf_len) {
@@ -570,10 +584,8 @@ scan_more:	
 			/* Eep. Node goes over the end of the erase block. */
 			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
 			       ofs, je32_to_cpu(node->totlen));
-			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
-			DIRTY_SPACE(4);
-			ofs += 4;
-			continue;
+			printk(KERN_NOTICE "Perhaps the file system was created with the wrong erase size? Reject to mount.\n");
+			return -EINVAL;
 		}
 
 		if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
@@ -586,6 +598,7 @@ scan_more:	
 
 		switch(je16_to_cpu(node->nodetype)) {
 		case JFFS2_NODETYPE_INODE:
+		case JFFS2_NODETYPE_INODE_EBH:
 			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 				D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
@@ -602,6 +615,7 @@ scan_more:	
 			break;
 			
 		case JFFS2_NODETYPE_DIRENT:
+		case JFFS2_NODETYPE_DIRENT_EBH:
 			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 				D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
@@ -645,6 +659,26 @@ scan_more:	
 			}
 			break;
 
+		case JFFS2_NODETYPE_ERASEBLOCK_HEADER:
+			if (ofs != jeb->offset) {
+				printk(KERN_NOTICE "Eraseblock header found at 0x%08x is not at the beginning of block (0x%08x)\n", ofs, jeb->offset);
+				DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
+				ofs += PAD(je32_to_cpu(node->totlen));
+			} else {
+				if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+					buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+					err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+					if (err)
+						return err;
+					buf_ofs = ofs;
+					node = (void *)buf;
+				}
+				err = jffs2_scan_eraseblock_header(c, jeb, (void *)node, ofs);
+				if (err) return err;
+				ofs += PAD(je32_to_cpu(node->totlen));
+			}
+			break;
+
 		case JFFS2_NODETYPE_PADDING:
 			if (jffs2_sum_active())
 				jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
@@ -888,6 +922,48 @@ static int jffs2_scan_dirent_node(struct
 	return 0;
 }
 
+static int jffs2_scan_eraseblock_header(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                                 struct jffs2_eraseblock_header *eh, uint32_t ofs)
+{
+	uint32_t crc, node_crc;
+	struct jffs2_raw_node_ref *raw;
+
+	D1(printk(KERN_DEBUG "jffs2_scan_eraseblock_header(): Node at 0x%08x\n", ofs));
+	crc = crc32(0, eh, sizeof(struct jffs2_eraseblock_header) - 8);
+	node_crc = je32_to_cpu(eh->node_crc);
+
+	if (crc != node_crc) {
+		printk(KERN_NOTICE "jffs2_scan_eraseblock_header(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			ofs, node_crc, crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(eh->totlen)));
+		return 0;
+	}
+
+	if (JFFS2_VERSION < je32_to_cpu(eh->fs_version)) {
+		printk(KERN_NOTICE "The version of fs image %d > the version of JFFS2 module %d. Reject to mount.\n",
+			 je32_to_cpu(eh->fs_version), JFFS2_VERSION);
+		return -EINVAL;
+	}
+
+	raw = jffs2_alloc_raw_node_ref();
+	if (!raw) {
+		printk(KERN_NOTICE "jffs2_scan_eraseblock_header(): allocation of node reference failed.\n");
+		return -ENOMEM;
+	}
+
+	jeb->has_eraseblock_header = 1;
+	jeb->erase_count = je32_to_cpu(eh->erase_count);
+
+	raw->next_in_ino = NULL;
+	raw->next_phys = NULL;
+	raw->flash_offset = ofs | REF_NORMAL;
+	raw->__totlen = PAD(je32_to_cpu(eh->totlen));
+	jeb->first_node = jeb->last_node = raw;
+
+	USED_SPACE(PAD(je32_to_cpu(eh->totlen)));
+	return 0;
+}
+
 static int count_list(struct list_head *l)
 {
 	uint32_t count = 0;
diff -auNrp ./mtd/fs/jffs2/wbuf.c ./mtd_eraseblock_header/fs/jffs2/wbuf.c
--- ./mtd/fs/jffs2/wbuf.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/wbuf.c	2005-09-20 15:11:55.000000000 +0800
@@ -934,66 +934,36 @@ exit:
 /*
  *	Check, if the out of band area is empty
  */
-int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode)
+
+int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t data_len)
 {
+	size_t offset, retlen;
+	uint32_t i = 0, j, oob_nr;
 	unsigned char *buf;
-	int 	ret = 0;
-	int	i,len,page;
-	size_t  retlen;
-	int	oob_size;
+	int oob_size, ret;
 
-	/* allocate a buffer for all oob data in this sector */
+	offset = jeb->offset;
 	oob_size = c->mtd->oobsize;
-	len = 4 * oob_size;
-	buf = kmalloc(len, GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
-		return -ENOMEM;
-	}
-	/* 
-	 * if mode = 0, we scan for a total empty oob area, else we have
-	 * to take care of the cleanmarker in the first page of the block
-	*/
-	ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf);
-	if (ret) {
-		D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-		goto out;
-	}
-	
-	if (retlen < len) {
-		D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
-			  "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
-		ret = -EIO;
-		goto out;
-	}
-	
-	/* Special check for first page */
-	for(i = 0; i < oob_size ; i++) {
-		/* Yeah, we know about the cleanmarker. */
-		if (mode && i >= c->fsdata_pos && 
-		    i < c->fsdata_pos + c->fsdata_len)
-			continue;
-
-		if (buf[i] != 0xFF) {
-			D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-				  buf[i], i, jeb->offset));
-			ret = 1; 
-			goto out;
-		}
-	}
-
-	/* we know, we are aligned :) */	
-	for (page = oob_size; page < len; page += sizeof(long)) {
-		unsigned long dat = *(unsigned long *)(&buf[page]);
-		if(dat != -1) {
-			ret = 1; 
-			goto out;
+	oob_nr = (data_len+c->fsdata_len-1)/c->fsdata_len;
+	if (oob_nr < 4) oob_nr = 4;
+	buf = kmalloc(oob_size * oob_nr, GFP_KERNEL);
+	ret = c->mtd->read_oob(c->mtd, offset, oob_size * oob_nr, &retlen, buf);
+
+	for (i=0; i<oob_nr; i++) {
+		for (j=0; j<oob_size; j++) {
+			if (data_len && j>=c->fsdata_pos && j<c->fsdata_pos + c->fsdata_len) {
+				data_len--;
+				continue;
+			}
+			if (buf[i*oob_size+j] != 0xFF) {
+				ret = 1;
+				goto out;
+			}
 		}
 	}
 
 out:
-	kfree(buf);	
-	
+	kfree(buf);
 	return ret;
 }
 
@@ -1003,86 +973,120 @@ out:
 *	only in the first page of the first physical block, but scan for bad blocks in all
 *	physical blocks
 */
-int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *data_len)
 {
-	struct jffs2_unknown_node n;
-	unsigned char buf[2 * NAND_MAX_OOBSIZE];
-	unsigned char *p;
-	int ret, i, cnt, retval = 0;
-	size_t retlen, offset;
+	size_t offset, retlen;
 	int oob_size;
+	uint32_t oob_nr, total_len;
+	unsigned char *buf;
+	int ret;
+	struct jffs2_unknown_node *n;
+	struct jffs2_eraseblock_header eh;
+	uint32_t read_in = 0, i = 0, copy_len, node_crc;
 
 	offset = jeb->offset;
+	*data_len = 0;
+
+	if (c->mtd->block_isbad (c->mtd, offset)) {
+		D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+		return 2;
+	}
+
 	oob_size = c->mtd->oobsize;
+	oob_nr = (sizeof(struct jffs2_eraseblock_header)+c->fsdata_len-1)/c->fsdata_len;
+	total_len = oob_size * oob_nr;
 
-	/* Loop through the physical blocks */
-	for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
-		/* Check first if the block is bad. */
-		if (c->mtd->block_isbad (c->mtd, offset)) {
-			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
-			return 2;
-		}
-		/*
-		   *    We read oob data from page 0 and 1 of the block.
-		   *    page 0 contains cleanmarker and badblock info
-		   *    page 1 contains failure count of this block
-		 */
-		ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf);
+	buf = kmalloc(total_len, GFP_KERNEL);
+	if (!buf) {
+		return -ENOMEM;
+	}
+	ret = c->mtd->read_oob(c->mtd, offset, total_len, &retlen, buf);
+	if (ret) {
+		D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
+		goto out;
+	}
+	if (retlen < total_len) {
+		 D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, total_len, jeb->offset));
+		ret = -EIO;
+		goto out;
+	}
 
-		if (ret) {
-			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-			return ret;
+	n = (struct jffs2_unknown_node *) &buf[c->fsdata_pos];
+	if (je16_to_cpu(n->magic) != JFFS2_MAGIC_BITMASK) {
+		D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset));
+		ret = 1;
+		goto out;
+	}
+
+	if (je16_to_cpu(n->nodetype) == JFFS2_NODETYPE_CLEANMARKER) {
+		if (je32_to_cpu(n->totlen) == 8) {
+			*data_len = 8;
+			ret = 0;
+		} else {
+			ret = 1;
 		}
-		if (retlen < (oob_size << 1)) {
-			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset));
-			return -EIO;
+		goto out;
+	}else if (je16_to_cpu(n->nodetype) == JFFS2_NODETYPE_ERASEBLOCK_HEADER) {
+		/* Read the scattered data(in buf[]) into struct jffs2_eraseblock_header */
+		while (read_in < sizeof(struct jffs2_eraseblock_header)) {
+			copy_len = min_t(uint32_t, c->fsdata_len, sizeof(struct jffs2_eraseblock_header) - read_in);
+			memcpy((unsigned char *)&eh + read_in, &buf[oob_size*i + c->fsdata_pos], copy_len);
+			read_in += copy_len;
+			i++;
 		}
 
-		/* Check cleanmarker only on the first physical block */
-		if (!cnt) {
-			n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
-			n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
-			n.totlen = cpu_to_je32 (8);
-			p = (unsigned char *) &n;
-
-			for (i = 0; i < c->fsdata_len; i++) {
-				if (buf[c->fsdata_pos + i] != p[i]) {
-					retval = 1;
-				}
-			}
-			D1(if (retval == 1) {
-				printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
-				printk(KERN_WARNING "OOB at %08x was ", offset);
-				for (i=0; i < oob_size; i++) {
-					printk("%02x ", buf[i]);
-				}
-				printk("\n");
-			})
+		node_crc = crc32(0, &eh, sizeof(struct jffs2_eraseblock_header)-8);
+		if (node_crc != je32_to_cpu(eh.node_crc)) {
+			ret = 1;
+			goto out;
 		}
-		offset += c->mtd->erasesize;
+
+		if (JFFS2_VERSION < je32_to_cpu(eh.fs_version)) {
+			printk(KERN_NOTICE "The version of fs image %d > the version of JFFS2 module %d. Reject to mount.\n",
+				je32_to_cpu(eh.fs_version), JFFS2_VERSION);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		jeb->has_eraseblock_header = 1;
+		jeb->erase_count = je32_to_cpu(eh.erase_count);
+		*data_len = je32_to_cpu(eh.totlen);
+		ret = 0;
+	}else {
+		ret = 1;
 	}
-	return retval;
+out:
+	kfree(buf);
+	return ret;
 }
 
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-	struct 	jffs2_unknown_node n;
-	int 	ret;
-	size_t 	retlen;
-
-	n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-	n.totlen = cpu_to_je32(8);
+	struct jffs2_eraseblock_header eh;
+	uint32_t i = 0, written = 0, write_len = 0;
+	int ret;
+	size_t  retlen;
 
-	ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
-	
-	if (ret) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
-		return ret;
-	}
-	if (retlen != c->fsdata_len) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len));
-		return ret;
+	eh.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	eh.nodetype = cpu_to_je16(JFFS2_NODETYPE_ERASEBLOCK_HEADER);
+	eh.fs_version = cpu_to_je32(JFFS2_VERSION);
+	eh.erase_count = cpu_to_je32(jeb->erase_count);
+	eh.dsize = cpu_to_je16(0);
+	eh.data_crc = cpu_to_je32(0);
+	eh.totlen = cpu_to_je32(sizeof(struct jffs2_eraseblock_header));
+
+	eh.hdr_crc = cpu_to_je32(crc32(0, &eh, sizeof(struct jffs2_unknown_node)-4));
+	eh.node_crc = cpu_to_je32(crc32(0, &eh, sizeof(struct jffs2_eraseblock_header)-8));
+
+	while (written < sizeof(struct jffs2_eraseblock_header)) {
+		write_len = min_t(uint32_t, c->fsdata_len, sizeof(struct jffs2_eraseblock_header) - written);
+		ret = jffs2_flash_write_oob(c, jeb->offset + c->mtd->oobblock*i + c->fsdata_pos, write_len,  &retlen, (unsigned char *)&eh + written);
+		if (ret || retlen != write_len) {
+			D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
+			return ret;
+		}
+		written += write_len;
+		i++;
 	}
 	return 0;
 }
@@ -1135,6 +1139,7 @@ static int jffs2_nand_set_oobinfo(struct
 	
 	/* Cleanmarker is out-of-band, so inline size zero */
 	c->cleanmarker_size = 0;
+	c->eraseblock_header_size = 0;
 
 	/* Should we use autoplacement ? */
 	if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) {
@@ -1146,8 +1151,6 @@ static int jffs2_nand_set_oobinfo(struct
 		}
 		c->fsdata_pos = oinfo->oobfree[0][0];
 		c->fsdata_len = oinfo->oobfree[0][1];
-		if (c->fsdata_len > 8)
-			c->fsdata_len = 8;
 	} else {
 		/* This is just a legacy fallback and should go away soon */
 		switch(c->mtd->ecctype) {
@@ -1167,6 +1170,21 @@ static int jffs2_nand_set_oobinfo(struct
 	return 0;
 }
 
+/* To check if the OOB area has enough space for eraseblock header */
+static int jffs2_nand_check_oobspace_for_ebh(struct jffs2_sb_info *c)
+{
+	uint32_t pages_per_eraseblock, available_oob_space;
+
+	pages_per_eraseblock = c->sector_size/c->mtd->oobblock;
+	available_oob_space = c->fsdata_len * pages_per_eraseblock;
+	if (available_oob_space < sizeof(struct jffs2_eraseblock_header)) {
+		printk(KERN_NOTICE "The OOB area(%d) is not big enough to hold eraseblock_header(%d), reject to mount.\n",
+			 available_oob_space, sizeof(struct jffs2_eraseblock_header));
+		return -EINVAL;
+	}
+	return 0;
+}
+
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
 {
 	int res;
@@ -1181,6 +1199,11 @@ int jffs2_nand_flash_setup(struct jffs2_
 		return -ENOMEM;
 
 	res = jffs2_nand_set_oobinfo(c);
+	if (res) {
+		return res;
+	}
+
+	res = jffs2_nand_check_oobspace_for_ebh(c);
 
 #ifdef BREAKME
 	if (!brokenbuf)
@@ -1223,6 +1246,7 @@ void jffs2_dataflash_cleanup(struct jffs
 int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
 	/* Cleanmarker is actually larger on the flashes */
 	c->cleanmarker_size = 16;
+	c->eraseblock_header_size = 40;
 
 	/* Initialize write buffer */
 	init_rwsem(&c->wbuf_sem);
@@ -1243,6 +1267,7 @@ void jffs2_nor_ecc_flash_cleanup(struct 
 int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
 	/* Cleanmarker currently occupies a whole programming region */
 	c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd);
+	c->eraseblock_header_size = MTD_PROGREGION_SIZE(c->mtd);
 
 	/* Initialize write buffer */
 	init_rwsem(&c->wbuf_sem);
diff -auNrp ./mtd/fs/jffs2/write.c ./mtd_eraseblock_header/fs/jffs2/write.c
--- ./mtd/fs/jffs2/write.c	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/fs/jffs2/write.c	2005-09-20 14:33:10.000000000 +0800
@@ -43,7 +43,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	ri->ino = cpu_to_je32(f->inocache->ino);
 
 	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 	ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
 	ri->mode = cpu_to_jemode(mode);
@@ -379,7 +379,7 @@ int jffs2_write_inode_range(struct jffs2
 		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
 
 		ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+		ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE_EBH);
 		ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
 		ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
 
@@ -503,7 +503,7 @@ int jffs2_do_create(struct jffs2_sb_info
 	down(&dir_f->sem);
 
 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 
@@ -567,7 +567,7 @@ int jffs2_do_unlink(struct jffs2_sb_info
 
 		/* Build a deletion node */
 		rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-		rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+		rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 		rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 		rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 		
@@ -677,7 +677,7 @@ int jffs2_do_link (struct jffs2_sb_info 
 
 	/* Build a deletion node */
 	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT_EBH);
 	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
 	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
 
diff -auNrp ./mtd/include/linux/jffs2_fs_sb.h ./mtd_eraseblock_header/include/linux/jffs2_fs_sb.h
--- ./mtd/include/linux/jffs2_fs_sb.h	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/include/linux/jffs2_fs_sb.h	2005-09-20 14:31:38.000000000 +0800
@@ -114,6 +114,8 @@ struct jffs2_sb_info {
 
 	struct jffs2_summary *summary;		/* Summary information */
 
+	uint32_t eraseblock_header_size;
+
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
diff -auNrp ./mtd/include/linux/jffs2.h ./mtd_eraseblock_header/include/linux/jffs2.h
--- ./mtd/include/linux/jffs2.h	2005-09-12 11:16:32.000000000 +0800
+++ ./mtd_eraseblock_header/include/linux/jffs2.h	2005-09-20 14:31:39.000000000 +0800
@@ -28,6 +28,9 @@
 #define JFFS2_EMPTY_BITMASK 0xffff
 #define JFFS2_DIRTY_BITMASK 0x0000
 
+/* JFFS2 version number */
+#define JFFS2_VERSION 0x01
+
 /* Summary node MAGIC marker */
 #define JFFS2_SUM_MAGIC	0x02851885
 
@@ -62,8 +65,13 @@
 #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
 #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
-
+#define JFFS2_NODETYPE_ERASEBLOCK_HEADER (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5)
 #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+/* The 3 types are defined in order to let old JFFS2 code reject to mount new JFFS2 fs image for NAND flash, 
+  these 3 types are introduce together with eraseblock header and 1:1 mapping*/
+#define JFFS2_NODETYPE_DIRENT_EBH (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 7)
+#define JFFS2_NODETYPE_INODE_EBH (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_SUMMARY_EBH (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
 
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
@@ -101,6 +109,20 @@ struct jffs2_unknown_node
 	jint32_t hdr_crc;
 } __attribute__((packed));
 
+struct jffs2_eraseblock_header
+{
+	jint16_t magic;
+	jint16_t nodetype; /* == JFFS2_NODETYPE_ERASEBLOCK_HEADER */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t fs_version; /* the version of this JFFS2 fs image */
+	jint32_t erase_count; /* the erase count of this erase block */
+	jint16_t dsize; /* the size of additional data behind node_crc */
+	jint32_t node_crc;
+	jint32_t data_crc;
+	jint32_t data[0];
+} __attribute__((packed));
+
 struct jffs2_raw_dirent
 {
 	jint16_t magic;
@@ -168,6 +190,7 @@ union jffs2_node_union {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
 	struct jffs2_unknown_node u;
+	struct jffs2_eraseblock_header eh;
 	struct jffs2_summary_node s;
 };
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2005-09-21 10:42 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-20  7:45 [PATCH]Add JFFS2 eraseblock header support zhao forrest
2005-09-20 10:24 ` Jörn Engel
2005-09-20 10:59   ` Artem B. Bityutskiy
2005-09-20 11:36     ` Jörn Engel
2005-09-20 11:56       ` Artem B. Bityutskiy
2005-09-20 12:27         ` Jörn Engel
2005-09-20 12:43           ` Jörn Engel
2005-09-21  2:57       ` zhao forrest
2005-09-21  7:10         ` Jörn Engel
2005-09-21 10:42           ` Ferenc Havasi
2005-09-21  2:16     ` zhao forrest
2005-09-20 11:29 ` Artem B. Bityutskiy
2005-09-21  2:22   ` zhao forrest

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox