diff -auNrp mtd_9_28/fs/jffs2/erase.c mtd_9_28_EBH/fs/jffs2/erase.c --- mtd_9_28/fs/jffs2/erase.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/erase.c 2005-10-09 13:44:56.000000000 +0800 @@ -24,7 +24,7 @@ struct erase_priv_struct { struct jffs2_eraseblock *jeb; struct jffs2_sb_info *c; }; - + #ifndef __ECOS static void jffs2_erase_callback(struct erase_info *); #endif @@ -165,6 +165,7 @@ static void jffs2_erase_succeeded(struct 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); } @@ -351,7 +352,7 @@ fail: 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 @@ 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_ebh(c, jeb)) + goto filebad; jeb->first_node = jeb->last_node = NULL; jeb->free_size = c->sector_size; @@ -382,45 +381,51 @@ static void jffs2_mark_erased_block(stru } 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; } diff -auNrp mtd_9_28/fs/jffs2/fs.c mtd_9_28_EBH/fs/jffs2/fs.c --- mtd_9_28/fs/jffs2/fs.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/fs.c 2005-09-28 11:51:53.000000000 +0800 @@ -476,6 +476,7 @@ int jffs2_do_fill_super(struct super_blo } 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); diff -auNrp mtd_9_28/fs/jffs2/nodelist.h mtd_9_28_EBH/fs/jffs2/nodelist.h --- mtd_9_28/fs/jffs2/nodelist.h 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/nodelist.h 2005-10-09 13:47:18.000000000 +0800 @@ -183,7 +183,8 @@ struct jffs2_node_frag 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_eraseblock 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 @@ 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_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" diff -auNrp mtd_9_28/fs/jffs2/nodemgmt.c mtd_9_28_EBH/fs/jffs2/nodemgmt.c --- mtd_9_28/fs/jffs2/nodemgmt.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/nodemgmt.c 2005-10-09 14:34:36.000000000 +0800 @@ -258,6 +258,34 @@ static int jffs2_find_nextblock(struct j 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; + if (EBFLAGS_HAS_EBH(jeb) && c->ebh_size && jeb->used_size == ref_totlen(c, jeb, jeb->first_node) + && !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 +370,8 @@ static int jffs2_do_reserve_space(struct 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 +381,7 @@ 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 (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 diff -auNrp mtd_9_28/fs/jffs2/os-linux.h mtd_9_28_EBH/fs/jffs2/os-linux.h --- mtd_9_28/fs/jffs2/os-linux.h 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/os-linux.h 2005-09-28 10:54:01.000000000 +0800 @@ -76,7 +76,7 @@ static inline void jffs2_init_inode_info #define jffs2_is_writebuffered(c) (0) #define jffs2_cleanmarker_oob(c) (0) -#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) +#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)) @@ -122,9 +122,9 @@ 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_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); diff -auNrp mtd_9_28/fs/jffs2/scan.c mtd_9_28_EBH/fs/jffs2/scan.c --- mtd_9_28/fs/jffs2/scan.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/scan.c 2005-10-09 13:39:25.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_raw_ebh *eh, uint32_t ofs, struct jffs2_summary *s); 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 (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 @@ 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_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 */ @@ -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 (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 @@ 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)) { @@ -645,6 +657,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, 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 @@ 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_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; diff -auNrp mtd_9_28/fs/jffs2/summary.c mtd_9_28_EBH/fs/jffs2/summary.c --- mtd_9_28/fs/jffs2/summary.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/summary.c 2005-10-09 13:39:44.000000000 +0800 @@ -81,6 +81,13 @@ static int jffs2_sum_add_mem(struct jffs 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 @@ int jffs2_sum_add_dirent_mem(struct jffs 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 @@ int jffs2_sum_add_kvec(struct jffs2_sb_i 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 @@ static int jffs2_sum_process_sum_data(st 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 @@ static int jffs2_sum_write_data(struct j 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 @@ static int jffs2_sum_write_data(struct j 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 */ } diff -auNrp mtd_9_28/fs/jffs2/summary.h mtd_9_28_EBH/fs/jffs2/summary.h --- mtd_9_28/fs/jffs2/summary.h 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/summary.h 2005-09-28 10:54:01.000000000 +0800 @@ -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 @@ struct jffs2_sum_dirent_flash 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 @@ struct jffs2_sum_dirent_mem 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_write_sumnode(struct jffs2 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 @@ int jffs2_sum_scan_sumnode(struct jffs2_ #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 */ diff -auNrp mtd_9_28/fs/jffs2/wbuf.c mtd_9_28_EBH/fs/jffs2/wbuf.c --- mtd_9_28/fs/jffs2/wbuf.c 2005-09-28 10:51:57.000000000 +0800 +++ mtd_9_28_EBH/fs/jffs2/wbuf.c 2005-10-09 17:21:58.000000000 +0800 @@ -931,66 +931,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=c->fsdata_pos && jfsdata_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; } @@ -1000,86 +970,131 @@ 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_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; } - 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_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++; } - /* 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; - - n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - n.totlen = cpu_to_je32(8); - - 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; + 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, + }; + + 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)); + + 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; } @@ -1132,6 +1147,7 @@ static int jffs2_nand_set_oobinfo(struct /* 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) { @@ -1143,8 +1159,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) { @@ -1164,6 +1178,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_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; @@ -1178,6 +1207,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) @@ -1220,6 +1254,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->ebh_size = 24; /* Initialize write buffer */ init_rwsem(&c->wbuf_sem); @@ -1240,6 +1275,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->ebh_size = MTD_PROGREGION_SIZE(c->mtd); /* Initialize write buffer */ init_rwsem(&c->wbuf_sem); diff -auNrp mtd_9_28/include/linux/jffs2_fs_sb.h mtd_9_28_EBH/include/linux/jffs2_fs_sb.h --- mtd_9_28/include/linux/jffs2_fs_sb.h 2005-09-28 10:51:58.000000000 +0800 +++ mtd_9_28_EBH/include/linux/jffs2_fs_sb.h 2005-09-28 11:58:03.000000000 +0800 @@ -115,6 +115,8 @@ struct jffs2_sb_info { struct jffs2_summary *summary; /* Summary information */ + uint32_t ebh_size; /* This is the space size occupied by eraseblock_header on flash */ + /* OS-private pointer for getting back to master superblock info */ void *os_priv; }; diff -auNrp mtd_9_28/include/linux/jffs2.h mtd_9_28_EBH/include/linux/jffs2.h --- mtd_9_28/include/linux/jffs2.h 2005-09-28 10:51:58.000000000 +0800 +++ mtd_9_28_EBH/include/linux/jffs2.h 2005-10-09 11:28:03.000000000 +0800 @@ -28,6 +28,11 @@ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000 +/* JFFS2 eraseblock header compat/incompat/rocompat features set */ +#define JFFS2_EBH_COMPAT_FSET 0x00 +#define JFFS2_EBH_INCOMPAT_FSET 0x00 +#define JFFS2_EBH_ROCOMPAT_FSET 0x00 + /* Summary node MAGIC marker */ #define JFFS2_SUM_MAGIC 0x02851885 @@ -63,6 +68,7 @@ #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_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 5) #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) // Maybe later... @@ -165,11 +171,28 @@ struct jffs2_raw_summary jint32_t sum[0]; /* inode summary info */ } __attribute__((packed)); +struct jffs2_raw_ebh +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_ERASEBLOCK_HEADER */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t node_crc; + uint8_t reserved; /* reserved for future use and alignment */ + uint8_t compat_fset; + uint8_t incompat_fset; + uint8_t rocompat_fset; + jint32_t erase_count; /* the erase count of this erase block */ + jint32_t data[0]; +} __attribute__((packed)); + + union jffs2_node_union { struct jffs2_raw_inode i; struct jffs2_raw_dirent d; struct jffs2_raw_summary s; + struct jffs2_raw_ebh eh; struct jffs2_unknown_node u; };