mtd/fs/jffs2 erase.c, 1.85, 1.86 fs.c, 1.66, 1.67 nodelist.h, 1.140,
1.141 nodemgmt.c, 1.127, 1.128 os-linux.h, 1.64, 1.65 scan.c,
1.125, 1.126 summary.c, 1.4, 1.5 summary.h, 1.2, 1.3 wbuf.c,
1.100, 1.101
Forrest Zhao
forrest.zhao at intel.com
Fri Nov 4 03:06:28 EST 2005
- Previous message: mtd/Documentation/jffs3/pics journal-01.eps, 1.2, 1.3 journal-01.pdf,
1.2, 1.3 journal-01.png, 1.1, 1.2 node-01.eps, 1.2,
1.3 node-01.pdf, 1.2, 1.3 node-01.png, 1.1, 1.2 wandtree.eps,
1.2, 1.3 wandtree.pdf, 1.2, 1.3 wandtree.png, 1.1, 1.2
- Next message: mtd/fs/jffs2/ecos/src os-ecos.h,1.25,1.26
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv31513/fs/jffs2
Modified Files:
erase.c fs.c nodelist.h nodemgmt.c os-linux.h scan.c summary.c
summary.h wbuf.c
Log Message:
Clean marker is gone! This patch introduce Erase Block Header(EBH) to JFFS2. EBH resides at the beginning of each eraseb block and carries the meta data for that erase block. If you want to add new per-erase-block information, you may use EBH to make extension. Now we record the erase count of each erase block in EBH.
Also this patch modified the user-space utilities to make them accormodate to EBH.
Index: erase.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/erase.c,v
retrieving revision 1.85
retrieving revision 1.86
diff -u -r1.85 -r1.86
--- erase.c 20 Sep 2005 14:53:15 -0000 1.85
+++ erase.c 4 Nov 2005 08:06:25 -0000 1.86
@@ -24,7 +24,7 @@
struct jffs2_eraseblock *jeb;
struct jffs2_sb_info *c;
};
-
+
#ifndef __ECOS
static void jffs2_erase_callback(struct erase_info *);
#endif
@@ -165,6 +165,7 @@
list_del(&jeb->list);
list_add_tail(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock);
+ EBFLAGS_SET_EBH(jeb);
/* Ensure that kupdated calls us again to mark them clean */
jffs2_erase_pending_trigger(c);
}
@@ -173,7 +174,7 @@
{
/* For NAND, if the failure did not occur at the device level for a
specific physical page, don't bother updating the bad block table. */
- if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
+ if (jffs2_ebh_oob(c) && (bad_offset != 0xffffffff)) {
/* We had a device-level failure to erase. Let's see if we've
failed too many times. */
if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
@@ -351,7 +352,7 @@
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
- struct jffs2_raw_node_ref *marker_ref = NULL;
+ struct jffs2_raw_node_ref *ebh_ref = NULL;
size_t retlen;
int ret;
uint32_t bad_offset;
@@ -362,16 +363,14 @@
}
/* 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_ebh_oob(c)) {
- if (jffs2_cleanmarker_oob(c)) {
- if (jffs2_write_nand_cleanmarker(c, jeb))
- goto filebad;
- }
+ if (jffs2_write_nand_ebh(c, jeb))
+ goto filebad;
jeb->first_node = jeb->last_node = NULL;
jeb->free_size = c->sector_size;
@@ -382,45 +381,51 @@
} else {
struct kvec vecs[1];
- struct jffs2_unknown_node marker = {
- .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
- .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
- .totlen = cpu_to_je32(c->cleanmarker_size)
+ struct jffs2_raw_ebh ebh = {
+ .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
+ .nodetype = cpu_to_je16(JFFS2_NODETYPE_ERASEBLOCK_HEADER),
+ .totlen = cpu_to_je32(sizeof(struct jffs2_raw_ebh)),
+ .reserved = 0,
+ .compat_fset = JFFS2_EBH_COMPAT_FSET,
+ .incompat_fset = JFFS2_EBH_INCOMPAT_FSET,
+ .rocompat_fset = JFFS2_EBH_ROCOMPAT_FSET,
};
- marker_ref = jffs2_alloc_raw_node_ref();
- if (!marker_ref) {
+ ebh_ref = jffs2_alloc_raw_node_ref();
+ if (!ebh_ref) {
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n");
goto refile;
}
+ ebh.erase_count = cpu_to_je32(jeb->erase_count);
+ ebh.hdr_crc = cpu_to_je32(crc32(0, &ebh, sizeof(struct jffs2_unknown_node)-4));
+ ebh.node_crc = cpu_to_je32(crc32(0, (unsigned char *)&ebh + sizeof(struct jffs2_unknown_node) + 4,
+ sizeof(struct jffs2_raw_ebh) - sizeof(struct jffs2_unknown_node) - 4));
- marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
-
- vecs[0].iov_base = (unsigned char *) ▮
- vecs[0].iov_len = sizeof(marker);
+ vecs[0].iov_base = (unsigned char *) &ebh;
+ vecs[0].iov_len = sizeof(ebh);
ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
- if (ret || retlen != sizeof(marker)) {
+ if (ret || retlen != sizeof(ebh)) {
if (ret)
- printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
+ printk(KERN_WARNING "Write eraseblock header to block at 0x%08x failed: %d\n",
jeb->offset, ret);
else
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
- jeb->offset, sizeof(marker), retlen);
+ jeb->offset, sizeof(ebh), retlen);
- jffs2_free_raw_node_ref(marker_ref);
+ jffs2_free_raw_node_ref(ebh_ref);
goto filebad;
}
- 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;
+ ebh_ref->next_in_ino = NULL;
+ ebh_ref->next_phys = NULL;
+ ebh_ref->flash_offset = jeb->offset | REF_NORMAL;
+ ebh_ref->__totlen = c->ebh_size;
- jeb->first_node = jeb->last_node = marker_ref;
+ jeb->first_node = jeb->last_node = ebh_ref;
- jeb->free_size = c->sector_size - c->cleanmarker_size;
- jeb->used_size = c->cleanmarker_size;
+ jeb->free_size = c->sector_size - c->ebh_size;
+ jeb->used_size = c->ebh_size;
jeb->dirty_size = 0;
jeb->wasted_size = 0;
}
Index: fs.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/fs.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- fs.c 27 Sep 2005 13:17:29 -0000 1.66
+++ fs.c 4 Nov 2005 08:06:25 -0000 1.67
@@ -476,6 +476,7 @@
}
c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+ c->ebh_size = PAD(sizeof(struct jffs2_raw_ebh));
/* NAND (or other bizarre) flash... do setup accordingly */
ret = jffs2_flash_setup(c);
@@ -629,7 +630,7 @@
static int jffs2_flash_setup(struct jffs2_sb_info *c) {
int ret = 0;
- if (jffs2_cleanmarker_oob(c)) {
+ if (jffs2_ebh_oob(c)) {
/* NAND flash... do setup accordingly */
ret = jffs2_nand_flash_setup(c);
if (ret)
@@ -662,7 +663,7 @@
void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
- if (jffs2_cleanmarker_oob(c)) {
+ if (jffs2_ebh_oob(c)) {
jffs2_nand_flash_cleanup(c);
}
Index: nodelist.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodelist.h,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -r1.140 -r1.141
--- nodelist.h 7 Sep 2005 08:34:54 -0000 1.140
+++ nodelist.h 4 Nov 2005 08:06:25 -0000 1.141
@@ -183,7 +183,8 @@
struct jffs2_eraseblock
{
struct list_head list;
- int bad_count;
+ uint16_t bad_count;
+ uint16_t flags;
uint32_t offset; /* of this block in the MTD */
uint32_t unchecked_size;
@@ -196,8 +197,14 @@
struct jffs2_raw_node_ref *last_node;
struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */
+
+ uint32_t erase_count;
};
+#define EBFLAGS_SET_EBH(jeb) (jeb->flags |= 1)
+#define EBFLAGS_CLR_EBH(jeb) (jeb->flags &= ~1)
+#define EBFLAGS_HAS_EBH(jeb) ((jeb->flags & 1) == 1)
+
static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c)
{
return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024);
@@ -404,8 +411,8 @@
/* 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_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_check_nand_cleanmarker_ebh(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *data_len);
+int jffs2_write_nand_ebh(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
#endif
#include "debug.h"
Index: nodemgmt.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodemgmt.c,v
retrieving revision 1.127
retrieving revision 1.128
diff -u -r1.127 -r1.128
--- nodemgmt.c 20 Sep 2005 15:49:12 -0000 1.127
+++ nodemgmt.c 4 Nov 2005 08:06:25 -0000 1.128
@@ -258,6 +258,30 @@
return 0;
}
+/* To check if eraseblock has expected free size */
+static int has_expected_free_size(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+{
+ if (!EBFLAGS_HAS_EBH(jeb) && jeb->free_size != c->sector_size - c->cleanmarker_size)
+ return 0;
+
+ if (EBFLAGS_HAS_EBH(jeb) && c->ebh_size && jeb->free_size != c->sector_size - ref_totlen(c, jeb, jeb->first_node))
+ return 0;
+
+ if (EBFLAGS_HAS_EBH(jeb) && !c->ebh_size && jeb->free_size != c->sector_size)
+ return 0;
+
+ return 1;
+}
+
+static int need_mark_first_node_obsolete(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+{
+ if (!EBFLAGS_HAS_EBH(jeb) && c->cleanmarker_size
+ && jeb->used_size == c->cleanmarker_size && !jeb->first_node->next_in_ino)
+ return 1;
+ return 0;
+}
+
+
/* Called with alloc sem _and_ erase_completion_lock */
static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
{
@@ -342,7 +366,8 @@
jeb = c->nextblock;
- if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
+ if (!has_expected_free_size(c, jeb))
+ {
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;
}
@@ -352,8 +377,7 @@
*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 (need_mark_first_node_obsolete(c, jeb)) {
/* 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
Index: os-linux.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/os-linux.h,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -r1.64 -r1.65
--- os-linux.h 30 Sep 2005 13:59:13 -0000 1.64
+++ os-linux.h 4 Nov 2005 08:06:25 -0000 1.65
@@ -76,8 +76,8 @@
#endif
#define jffs2_is_writebuffered(c) (0)
-#define jffs2_cleanmarker_oob(c) (0)
-#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
+#define jffs2_ebh_oob(c) (0)
+#define jffs2_write_nand_ebh(c,jeb) (-EIO)
#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
@@ -112,7 +112,7 @@
c->mtd->type == MTD_RAM)
#endif
-#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
+#define jffs2_ebh_oob(c) (c->mtd->type == MTD_NANDFLASH)
#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
@@ -122,9 +122,9 @@
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_write_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_ebh(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *data_len);
+int jffs2_write_nand_ebh(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);
void jffs2_wbuf_process(void *data);
Index: scan.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/scan.c,v
retrieving revision 1.125
retrieving revision 1.126
diff -u -r1.125 -r1.126
--- scan.c 30 Sep 2005 13:59:13 -0000 1.125
+++ scan.c 4 Nov 2005 08:06:25 -0000 1.126
@@ -46,6 +46,8 @@
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_raw_ebh *eh, uint32_t ofs, struct jffs2_summary *s);
static inline int min_free(struct jffs2_sb_info *c)
{
@@ -90,7 +92,7 @@
if (!flashbuf) {
/* For NAND it's quicker to read a whole eraseblock at a time,
apparently */
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
buf_size = c->sector_size;
else
buf_size = PAGE_SIZE;
@@ -292,6 +294,11 @@
int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
+ if (EBFLAGS_HAS_EBH(jeb) && c->ebh_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 @@
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- int cleanmarkerfound = 0;
+ uint32_t data_len = 0;
#endif
ofs = jeb->offset;
@@ -330,14 +337,14 @@
D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- if (jffs2_cleanmarker_oob(c)) {
- int ret = jffs2_check_nand_cleanmarker(c, jeb);
+ if (jffs2_ebh_oob(c)) {
+ int ret = jffs2_check_nand_cleanmarker_ebh(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 */
@@ -401,12 +408,12 @@
if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- if (jffs2_cleanmarker_oob(c)) {
+ if (jffs2_ebh_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 @@
return BLK_STATE_CLEANMARKER;
}
+ if (EBFLAGS_HAS_EBH(jeb) && c->ebh_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 @@
/* 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)) {
@@ -645,6 +657,26 @@
}
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, s);
+ 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 +920,58 @@
return 0;
}
+static int jffs2_scan_eraseblock_header(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+ struct jffs2_raw_ebh *eh, uint32_t ofs, struct jffs2_summary *s)
+{
+ 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, (unsigned char *)eh + sizeof(struct jffs2_unknown_node) + 4,
+ sizeof(struct jffs2_raw_ebh) - sizeof(struct jffs2_unknown_node) - 4);
+ 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_EBH_INCOMPAT_FSET | eh->incompat_fset) != JFFS2_EBH_INCOMPAT_FSET) {
+ printk(KERN_NOTICE "The incompat_fset of fs image EBH %d exceed the incompat_fset of JFFS2 module %d. Reject to mount.\n",
+ eh->incompat_fset, JFFS2_EBH_INCOMPAT_FSET);
+ return -EINVAL;
+ }
+ if ((JFFS2_EBH_ROCOMPAT_FSET | eh->rocompat_fset) != JFFS2_EBH_ROCOMPAT_FSET) {
+ printk(KERN_NOTICE "Read-only compatible EBH feature found at offset 0x%08x\n ", jeb->offset);
+ if (!(jffs2_is_readonly(c)))
+ return -EROFS;
+ }
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw) {
+ printk(KERN_NOTICE "jffs2_scan_eraseblock_header(): allocation of node reference failed.\n");
+ return -ENOMEM;
+ }
+
+ EBFLAGS_SET_EBH(jeb);
+ 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)));
+ if (jffs2_sum_active()) {
+ jffs2_sum_add_ebh_mem(s, eh, ofs - jeb->offset);
+ }
+
+ return 0;
+}
+
static int count_list(struct list_head *l)
{
uint32_t count = 0;
Index: summary.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/summary.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- summary.c 26 Sep 2005 11:37:21 -0000 1.4
+++ summary.c 4 Nov 2005 08:06:25 -0000 1.5
@@ -81,6 +81,13 @@
dbg_summary("dirent (%u) added to summary\n",
je32_to_cpu(item->d.ino));
break;
+ case JFFS2_NODETYPE_ERASEBLOCK_HEADER:
+ s->sum_size += sizeof(struct jffs2_sum_ebh_flash) + je32_to_cpu(item->eh.totlen)
+ - sizeof(struct jffs2_raw_ebh);
+ s->sum_num++;
+ dbg_summary("eraseblock header (%x) added to summary\n",
+ je32_to_cpu(item->eh.offset));
+ break;
default:
JFFS2_WARNING("UNKNOWN node type %u\n",
je16_to_cpu(item->u.nodetype));
@@ -141,6 +148,28 @@
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
}
+int jffs2_sum_add_ebh_mem(struct jffs2_summary *s, struct jffs2_raw_ebh *eh, uint32_t ofs)
+{
+ struct jffs2_sum_ebh_mem *temp = kmalloc(sizeof(struct jffs2_sum_ebh_mem) + je32_to_cpu(eh->totlen)
+ - sizeof(struct jffs2_raw_ebh), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ temp->nodetype = eh->nodetype;
+ temp->totlen = eh->totlen;
+ temp->offset = cpu_to_je32(ofs);
+ temp->reserved = eh->reserved;
+ temp->compat_fset = eh->compat_fset;
+ temp->incompat_fset = eh->incompat_fset;
+ temp->rocompat_fset = eh->rocompat_fset;
+ temp->erase_count = eh->erase_count;
+ temp->next = NULL;
+
+ memcpy(temp->data, eh->data, je32_to_cpu(eh->totlen) - sizeof(struct jffs2_raw_ebh));
+
+ return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
/* Cleanup every collected summary information */
static void jffs2_sum_clean_collected(struct jffs2_summary *s)
@@ -260,6 +289,35 @@
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
}
+ case JFFS2_NODETYPE_ERASEBLOCK_HEADER: {
+ struct jffs2_sum_ebh_mem *temp = kmalloc(sizeof(struct jffs2_sum_ebh_mem) + je32_to_cpu(node->eh.totlen)
+ - sizeof(struct jffs2_raw_ebh), GFP_KERNEL);
+ if (!temp)
+ goto no_mem;
+
+ temp->nodetype = node->eh.nodetype;
+ temp->totlen = node->eh.totlen;
+ temp->offset = cpu_to_je32(ofs);
+ temp->reserved = node->eh.reserved;
+ temp->compat_fset = node->eh.compat_fset;
+ temp->incompat_fset = node->eh.incompat_fset;
+ temp->rocompat_fset = node->eh.rocompat_fset;
+ temp->erase_count = node->eh.erase_count;
+ temp->next = NULL;
+ switch (count) {
+ case 1:
+ memcpy(temp->data, node->eh.data, je32_to_cpu(node->eh.totlen) - sizeof(struct jffs2_raw_ebh));
+ break;
+ case 2:
+ memcpy(temp->data, invecs[1].iov_base, je32_to_cpu(node->eh.totlen) - sizeof(struct jffs2_raw_ebh));
+ break;
+ default:
+ BUG();
+ break;
+ }
+ return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+ }
+
case JFFS2_NODETYPE_PADDING:
dbg_summary("node PADDING\n");
c->summary->sum_padded += je32_to_cpu(node->u.totlen);
@@ -409,6 +467,60 @@
break;
}
+ case JFFS2_NODETYPE_ERASEBLOCK_HEADER: {
+ struct jffs2_sum_ebh_flash *speh;
+ speh = sp;
+
+ dbg_summary("Eraseblock header at 0x%08x\n",
+ jeb->offset + je32_to_cpu(speh->offset));
+
+ if (je32_to_cpu(speh->offset) != 0) {
+ printk(KERN_NOTICE "Eraseblock header offset is %d\n", je32_to_cpu(speh->offset));
+ kfree(summary);
+ return -EINVAL;
+ }
+
+ if ((JFFS2_EBH_INCOMPAT_FSET | speh->incompat_fset) != JFFS2_EBH_INCOMPAT_FSET) {
+ printk(KERN_NOTICE "The incompat_fset of fs image EBH %d exceed the incompat_fset \
+ of JFFS2 module %d. Reject to mount.\n",
+ speh->incompat_fset, JFFS2_EBH_INCOMPAT_FSET);
+ kfree(summary);
+ return -EINVAL;
+ }
+ if ((JFFS2_EBH_ROCOMPAT_FSET | speh->rocompat_fset) != JFFS2_EBH_ROCOMPAT_FSET) {
+ printk(KERN_NOTICE "Read-only compatible EBH feature found at offset 0x%08x\n ",
+ jeb->offset);
+ if (!(jffs2_is_readonly(c))) {
+ kfree(summary);
+ return -EROFS;
+ }
+ }
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw) {
+ JFFS2_NOTICE("allocation of node reference failed\n");
+ kfree(summary);
+ return -ENOMEM;
+ }
+ EBFLAGS_SET_EBH(jeb);
+ jeb->erase_count = je32_to_cpu(speh->erase_count);
+ raw->next_in_ino = NULL;
+ raw->next_phys = NULL;
+ raw->flash_offset = (jeb->offset + je32_to_cpu(speh->offset)) | REF_NORMAL;
+ raw->__totlen = PAD(je32_to_cpu(speh->totlen));
+
+ if (!jeb->first_node)
+ jeb->first_node = raw;
+ if (jeb->last_node)
+ jeb->last_node->next_phys = raw;
+ jeb->last_node = raw;
+
+ USED_SPACE(PAD(je32_to_cpu(speh->totlen)));
+ sp += sizeof(struct jffs2_sum_ebh_flash) + je32_to_cpu(speh->totlen) - sizeof(struct jffs2_raw_ebh);
+
+ break;
+ }
+
default : {
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary);
@@ -576,7 +688,7 @@
isum.totlen = cpu_to_je32(infosize);
isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
isum.padded = cpu_to_je32(c->summary->sum_padded);
- isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
+ isum.cln_mkr = cpu_to_je32(0);
isum.sum_num = cpu_to_je32(c->summary->sum_num);
wpage = c->summary->sum_buf;
@@ -617,6 +729,26 @@
break;
}
+ case JFFS2_NODETYPE_ERASEBLOCK_HEADER: {
+ struct jffs2_sum_ebh_flash *sebh_ptr = wpage;
+
+ sebh_ptr->nodetype = c->summary->sum_list_head->eh.nodetype;
+ sebh_ptr->totlen = c->summary->sum_list_head->eh.totlen;
+ sebh_ptr->offset = c->summary->sum_list_head->eh.offset;
+ sebh_ptr->reserved = c->summary->sum_list_head->eh.reserved;
+ sebh_ptr->compat_fset = c->summary->sum_list_head->eh.compat_fset;
+ sebh_ptr->incompat_fset = c->summary->sum_list_head->eh.incompat_fset;
+ sebh_ptr->rocompat_fset = c->summary->sum_list_head->eh.rocompat_fset;
+ sebh_ptr->erase_count = c->summary->sum_list_head->eh.erase_count;
+
+ memcpy(sebh_ptr->data, c->summary->sum_list_head->eh.data,
+ je32_to_cpu(c->summary->sum_list_head->eh.totlen) - sizeof(struct jffs2_raw_ebh));
+ wpage += sizeof(struct jffs2_sum_ebh_flash) + je32_to_cpu(c->summary->sum_list_head->eh.totlen)
+ - sizeof(struct jffs2_raw_ebh);
+
+ break;
+ }
+
default : {
BUG(); /* unknown node in summary information */
}
Index: summary.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/summary.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- summary.h 26 Sep 2005 11:37:21 -0000 1.2
+++ summary.h 4 Nov 2005 08:06:25 -0000 1.3
@@ -45,6 +45,7 @@
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_EBH_SIZE(x) (sizeof(struct jffs2_sum_ebh_flash) + (x))
/* Summary structures used on flash */
@@ -75,11 +76,26 @@
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_ebh_flash
+{
+ jint16_t nodetype;
+ jint32_t totlen;
+ jint32_t offset;
+ uint8_t reserved;
+ uint8_t compat_fset;
+ uint8_t incompat_fset;
+ uint8_t rocompat_fset;
+ jint32_t erase_count;
+ jint16_t dsize;
+ jint32_t data[0];
+} __attribute__((packed));
+
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
+ struct jffs2_sum_ebh_flash eh;
};
/* Summary structures used in the memory */
@@ -114,11 +130,27 @@
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_ebh_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t totlen;
+ jint32_t offset;
+ uint8_t reserved;
+ uint8_t compat_fset;
+ uint8_t incompat_fset;
+ uint8_t rocompat_fset;
+ jint32_t erase_count;
+ jint16_t dsize;
+ jint32_t data[0];
+} __attribute__((packed));
+
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
+ struct jffs2_sum_ebh_mem eh;
};
/* Summary related information stored in superblock */
@@ -159,6 +191,7 @@
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
+int jffs2_sum_add_ebh_mem(struct jffs2_summary *s, struct jffs2_raw_ebh *eh, uint32_t ofs);
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random);
@@ -176,6 +209,7 @@
#define jffs2_sum_add_padding_mem(a,b)
#define jffs2_sum_add_inode_mem(a,b,c)
#define jffs2_sum_add_dirent_mem(a,b,c)
+#define jffs2_sum_add_ebh_mem(a,b,c)
#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
#endif /* CONFIG_JFFS2_SUMMARY */
Index: wbuf.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/wbuf.c,v
retrieving revision 1.100
retrieving revision 1.101
diff -u -r1.100 -r1.101
--- wbuf.c 30 Sep 2005 13:59:13 -0000 1.100
+++ wbuf.c 4 Nov 2005 08:06:25 -0000 1.101
@@ -231,7 +231,7 @@
}
/* Do the read... */
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
else
ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
@@ -291,7 +291,7 @@
ret = -EIO;
} else
#endif
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
rewrite_buf, NULL, c->oobinfo);
else
@@ -463,7 +463,7 @@
} else
#endif
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
else
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
@@ -770,7 +770,7 @@
outvecs[splitvec].iov_len = split_ofs;
/* We did cross a page boundary, so we write some now */
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
else
ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
@@ -870,7 +870,7 @@
/* Read flash */
down_read(&c->wbuf_sem);
- if (jffs2_cleanmarker_oob(c))
+ if (jffs2_ebh_oob(c))
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
else
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
@@ -925,66 +925,36 @@
/*
* 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;
}
@@ -994,86 +964,131 @@
* 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_ebh (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_raw_ebh 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_ebh(): Bad block at %08x\n", jeb->offset));
+ return 2;
+ }
+
oob_size = c->mtd->oobsize;
+ oob_nr = (sizeof(struct jffs2_raw_ebh)+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_ebh(): 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_ebh(): 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_ebh(): 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;
+ }
+ goto out;
+ }else if (je16_to_cpu(n->nodetype) == JFFS2_NODETYPE_ERASEBLOCK_HEADER) {
+ /* Read the scattered data(in buf[]) into struct jffs2_raw_ebh */
+ while (read_in < sizeof(struct jffs2_raw_ebh)) {
+ copy_len = min_t(uint32_t, c->fsdata_len, sizeof(struct jffs2_raw_ebh) - read_in);
+ memcpy((unsigned char *)&eh + read_in, &buf[oob_size*i + c->fsdata_pos], copy_len);
+ read_in += copy_len;
+ i++;
}
- 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;
- }
-
- /* 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;
- }
+
+ node_crc = crc32(0, &eh, sizeof(struct jffs2_raw_ebh)-8);
+ if (node_crc != je32_to_cpu(eh.node_crc)) {
+ ret = 1;
+ goto out;
+ }
+
+ if ((JFFS2_EBH_INCOMPAT_FSET | eh.incompat_fset) != JFFS2_EBH_INCOMPAT_FSET) {
+ printk(KERN_NOTICE "The incompat_fset of fs image EBH %d execeed the incompat_fset \
+ of JFFS2 module %d. Reject to mount.\n", eh.incompat_fset, JFFS2_EBH_INCOMPAT_FSET);
+ ret = -EINVAL;
+ goto out;
+ }
+ if ((JFFS2_EBH_ROCOMPAT_FSET | eh.rocompat_fset) != JFFS2_EBH_ROCOMPAT_FSET) {
+ printk(KERN_NOTICE "Read-only compatible EBH feature found at offset 0x%08x\n ", jeb->offset);
+ if (!(jffs2_is_readonly(c))) {
+ ret = -EROFS;
+ goto out;
}
- 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");
- })
}
- offset += c->mtd->erasesize;
+
+ EBFLAGS_SET_EBH(jeb);
+ 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)
+int jffs2_write_nand_ebh(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
- struct jffs2_unknown_node n;
- int ret;
- size_t retlen;
+ uint32_t i = 0, written = 0, write_len = 0;
+ int ret;
+ size_t retlen;
+ struct jffs2_raw_ebh ebh = {
+ .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
+ .nodetype = cpu_to_je16(JFFS2_NODETYPE_ERASEBLOCK_HEADER),
+ .totlen = cpu_to_je32(sizeof(struct jffs2_raw_ebh)),
+ .reserved = 0,
+ .compat_fset = JFFS2_EBH_COMPAT_FSET,
+ .incompat_fset = JFFS2_EBH_INCOMPAT_FSET,
+ .rocompat_fset = JFFS2_EBH_ROCOMPAT_FSET,
+ };
- n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
- n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
- n.totlen = cpu_to_je32(8);
+ ebh.erase_count = cpu_to_je32(jeb->erase_count);
- 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;
+ ebh.hdr_crc = cpu_to_je32(crc32(0, &ebh, sizeof(struct jffs2_unknown_node)-4));
+ ebh.node_crc = cpu_to_je32(crc32(0, (unsigned char *)&ebh + sizeof(struct jffs2_unknown_node) + 4,
+ sizeof(struct jffs2_raw_ebh) - sizeof(struct jffs2_unknown_node) - 4));
+
+ while (written < sizeof(struct jffs2_raw_ebh)) {
+ write_len = min_t(uint32_t, c->fsdata_len, sizeof(struct jffs2_raw_ebh) - written);
+ ret = jffs2_flash_write_oob(c, jeb->offset + c->mtd->oobblock*i + c->fsdata_pos,
+ write_len, &retlen, (unsigned char *)&ebh + written);
+ if (ret || retlen != write_len) {
+ D1(printk(KERN_WARNING "jffs2_write_nand_ebh(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
+ return ret;
+ }
+ written += write_len;
+ i++;
}
return 0;
}
@@ -1126,6 +1141,7 @@
/* Cleanmarker is out-of-band, so inline size zero */
c->cleanmarker_size = 0;
+ c->ebh_size = 0;
/* Should we use autoplacement ? */
if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) {
@@ -1137,8 +1153,6 @@
}
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) {
@@ -1158,6 +1172,21 @@
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_raw_ebh)) {
+ 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_raw_ebh));
+ return -EINVAL;
+ }
+ return 0;
+}
+
int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{
int res;
@@ -1172,6 +1201,11 @@
return -ENOMEM;
res = jffs2_nand_set_oobinfo(c);
+ if (res) {
+ return res;
+ }
+
+ res = jffs2_nand_check_oobspace_for_ebh(c);
#ifdef BREAKME
if (!brokenbuf)
@@ -1238,6 +1272,7 @@
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
/* Cleanmarker is actually larger on the flashes */
c->cleanmarker_size = 16;
+ c->ebh_size = 24;
/* Initialize write buffer */
init_rwsem(&c->wbuf_sem);
@@ -1258,6 +1293,7 @@
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->ebh_size = MTD_PROGREGION_SIZE(c->mtd);
/* Initialize write buffer */
init_rwsem(&c->wbuf_sem);
- Previous message: mtd/Documentation/jffs3/pics journal-01.eps, 1.2, 1.3 journal-01.pdf,
1.2, 1.3 journal-01.png, 1.1, 1.2 node-01.eps, 1.2,
1.3 node-01.pdf, 1.2, 1.3 node-01.png, 1.1, 1.2 wandtree.eps,
1.2, 1.3 wandtree.pdf, 1.2, 1.3 wandtree.png, 1.1, 1.2
- Next message: mtd/fs/jffs2/ecos/src os-ecos.h,1.25,1.26
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the linux-mtd-cvs
mailing list