1730554d9SArtem B. Bityutskiy /* 2730554d9SArtem B. Bityutskiy * JFFS2 -- Journalling Flash File System, Version 2. 3730554d9SArtem B. Bityutskiy * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 Red Hat, Inc. 5*6088c058SDavid Woodhouse * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 6730554d9SArtem B. Bityutskiy * 7730554d9SArtem B. Bityutskiy * Created by David Woodhouse <dwmw2@infradead.org> 8730554d9SArtem B. Bityutskiy * 9730554d9SArtem B. Bityutskiy * For licensing information, see the file 'LICENCE' in this directory. 10730554d9SArtem B. Bityutskiy * 11730554d9SArtem B. Bityutskiy */ 12c00c310eSDavid Woodhouse 13730554d9SArtem B. Bityutskiy #include <linux/kernel.h> 14737b7661SAndrew Lunn #include <linux/types.h> 15730554d9SArtem B. Bityutskiy #include <linux/pagemap.h> 16e0c8e42fSArtem B. Bityutskiy #include <linux/crc32.h> 17e0c8e42fSArtem B. Bityutskiy #include <linux/jffs2.h> 18733802d9SArtem B. Bityutskiy #include <linux/mtd/mtd.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 20730554d9SArtem B. Bityutskiy #include "nodelist.h" 21730554d9SArtem B. Bityutskiy #include "debug.h" 22730554d9SArtem B. Bityutskiy 2345ca1b50SArtem B. Bityutskiy #ifdef JFFS2_DBG_SANITY_CHECKS 2445ca1b50SArtem B. Bityutskiy 2545ca1b50SArtem B. Bityutskiy void 2645ca1b50SArtem B. Bityutskiy __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, 2745ca1b50SArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 2845ca1b50SArtem B. Bityutskiy { 2945ca1b50SArtem B. Bityutskiy if (unlikely(jeb && jeb->used_size + jeb->dirty_size + 3045ca1b50SArtem B. Bityutskiy jeb->free_size + jeb->wasted_size + 3145ca1b50SArtem B. Bityutskiy jeb->unchecked_size != c->sector_size)) { 3245ca1b50SArtem B. Bityutskiy JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset); 3381e39cf0SArtem B. Bityutskiy JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", 3481e39cf0SArtem B. Bityutskiy jeb->free_size, jeb->dirty_size, jeb->used_size, 3545ca1b50SArtem B. Bityutskiy jeb->wasted_size, jeb->unchecked_size, c->sector_size); 3645ca1b50SArtem B. Bityutskiy BUG(); 3745ca1b50SArtem B. Bityutskiy } 3845ca1b50SArtem B. Bityutskiy 3945ca1b50SArtem B. Bityutskiy if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size 4045ca1b50SArtem B. Bityutskiy + c->wasted_size + c->unchecked_size != c->flash_size)) { 4145ca1b50SArtem B. Bityutskiy JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n"); 4281e39cf0SArtem B. Bityutskiy JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", 4345ca1b50SArtem B. Bityutskiy c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, 4445ca1b50SArtem B. Bityutskiy c->wasted_size, c->unchecked_size, c->flash_size); 4545ca1b50SArtem B. Bityutskiy BUG(); 4645ca1b50SArtem B. Bityutskiy } 4745ca1b50SArtem B. Bityutskiy } 4845ca1b50SArtem B. Bityutskiy 4945ca1b50SArtem B. Bityutskiy void 5045ca1b50SArtem B. Bityutskiy __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, 5145ca1b50SArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 5245ca1b50SArtem B. Bityutskiy { 5345ca1b50SArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 5445ca1b50SArtem B. Bityutskiy jffs2_dbg_acct_sanity_check_nolock(c, jeb); 5545ca1b50SArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 5645ca1b50SArtem B. Bityutskiy } 5745ca1b50SArtem B. Bityutskiy 5845ca1b50SArtem B. Bityutskiy #endif /* JFFS2_DBG_SANITY_CHECKS */ 5945ca1b50SArtem B. Bityutskiy 60730554d9SArtem B. Bityutskiy #ifdef JFFS2_DBG_PARANOIA_CHECKS 61e0c8e42fSArtem B. Bityutskiy /* 62e0c8e42fSArtem B. Bityutskiy * Check the fragtree. 63e0c8e42fSArtem B. Bityutskiy */ 64e0c8e42fSArtem B. Bityutskiy void 65e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) 66e0c8e42fSArtem B. Bityutskiy { 67ced22070SDavid Woodhouse mutex_lock(&f->sem); 68e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check_nolock(f); 69ced22070SDavid Woodhouse mutex_unlock(&f->sem); 70e0c8e42fSArtem B. Bityutskiy } 71730554d9SArtem B. Bityutskiy 72730554d9SArtem B. Bityutskiy void 73e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f) 74730554d9SArtem B. Bityutskiy { 75730554d9SArtem B. Bityutskiy struct jffs2_node_frag *frag; 76730554d9SArtem B. Bityutskiy int bitched = 0; 77730554d9SArtem B. Bityutskiy 78730554d9SArtem B. Bityutskiy for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { 79730554d9SArtem B. Bityutskiy struct jffs2_full_dnode *fn = frag->node; 80730554d9SArtem B. Bityutskiy 81730554d9SArtem B. Bityutskiy if (!fn || !fn->raw) 82730554d9SArtem B. Bityutskiy continue; 83730554d9SArtem B. Bityutskiy 84730554d9SArtem B. Bityutskiy if (ref_flags(fn->raw) == REF_PRISTINE) { 85730554d9SArtem B. Bityutskiy if (fn->frags > 1) { 86e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n", 87730554d9SArtem B. Bityutskiy ref_offset(fn->raw), fn->frags); 88730554d9SArtem B. Bityutskiy bitched = 1; 89730554d9SArtem B. Bityutskiy } 90730554d9SArtem B. Bityutskiy 91730554d9SArtem B. Bityutskiy /* A hole node which isn't multi-page should be garbage-collected 92730554d9SArtem B. Bityutskiy and merged anyway, so we just check for the frag size here, 93730554d9SArtem B. Bityutskiy rather than mucking around with actually reading the node 94730554d9SArtem B. Bityutskiy and checking the compression type, which is the real way 95730554d9SArtem B. Bityutskiy to tell a hole node. */ 96730554d9SArtem B. Bityutskiy if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) 97730554d9SArtem B. Bityutskiy && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { 9881e39cf0SArtem B. Bityutskiy JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n", 9981e39cf0SArtem B. Bityutskiy ref_offset(fn->raw)); 100730554d9SArtem B. Bityutskiy bitched = 1; 101730554d9SArtem B. Bityutskiy } 102730554d9SArtem B. Bityutskiy 103730554d9SArtem B. Bityutskiy if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) 104730554d9SArtem B. Bityutskiy && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { 10581e39cf0SArtem B. Bityutskiy JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n", 106730554d9SArtem B. Bityutskiy ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); 107730554d9SArtem B. Bityutskiy bitched = 1; 108730554d9SArtem B. Bityutskiy } 109730554d9SArtem B. Bityutskiy } 110730554d9SArtem B. Bityutskiy } 111730554d9SArtem B. Bityutskiy 112730554d9SArtem B. Bityutskiy if (bitched) { 113e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("fragtree is corrupted.\n"); 114e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree_nolock(f); 115730554d9SArtem B. Bityutskiy BUG(); 116730554d9SArtem B. Bityutskiy } 117730554d9SArtem B. Bityutskiy } 118730554d9SArtem B. Bityutskiy 119730554d9SArtem B. Bityutskiy /* 120730554d9SArtem B. Bityutskiy * Check if the flash contains all 0xFF before we start writing. 121730554d9SArtem B. Bityutskiy */ 122730554d9SArtem B. Bityutskiy void 123e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, 124e0c8e42fSArtem B. Bityutskiy uint32_t ofs, int len) 125730554d9SArtem B. Bityutskiy { 126730554d9SArtem B. Bityutskiy size_t retlen; 127730554d9SArtem B. Bityutskiy int ret, i; 128730554d9SArtem B. Bityutskiy unsigned char *buf; 129730554d9SArtem B. Bityutskiy 130730554d9SArtem B. Bityutskiy buf = kmalloc(len, GFP_KERNEL); 131730554d9SArtem B. Bityutskiy if (!buf) 132730554d9SArtem B. Bityutskiy return; 133730554d9SArtem B. Bityutskiy 134730554d9SArtem B. Bityutskiy ret = jffs2_flash_read(c, ofs, len, &retlen, buf); 135730554d9SArtem B. Bityutskiy if (ret || (retlen != len)) { 136e0c8e42fSArtem B. Bityutskiy JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", 137e0c8e42fSArtem B. Bityutskiy len, ret, retlen); 138730554d9SArtem B. Bityutskiy kfree(buf); 139730554d9SArtem B. Bityutskiy return; 140730554d9SArtem B. Bityutskiy } 141730554d9SArtem B. Bityutskiy 142730554d9SArtem B. Bityutskiy ret = 0; 143730554d9SArtem B. Bityutskiy for (i = 0; i < len; i++) 144730554d9SArtem B. Bityutskiy if (buf[i] != 0xff) 145730554d9SArtem B. Bityutskiy ret = 1; 146730554d9SArtem B. Bityutskiy 147730554d9SArtem B. Bityutskiy if (ret) { 14881e39cf0SArtem B. Bityutskiy JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data already there. The first corrupted byte is at %#08x offset.\n", 14981e39cf0SArtem B. Bityutskiy ofs, ofs + i); 150e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_buffer(buf, len, ofs); 151730554d9SArtem B. Bityutskiy kfree(buf); 152730554d9SArtem B. Bityutskiy BUG(); 153730554d9SArtem B. Bityutskiy } 154730554d9SArtem B. Bityutskiy 155730554d9SArtem B. Bityutskiy kfree(buf); 156730554d9SArtem B. Bityutskiy } 157730554d9SArtem B. Bityutskiy 15885a62db6SDavid Woodhouse void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c) 15985a62db6SDavid Woodhouse { 16085a62db6SDavid Woodhouse struct jffs2_eraseblock *jeb; 16185a62db6SDavid Woodhouse uint32_t free = 0, dirty = 0, used = 0, wasted = 0, 16285a62db6SDavid Woodhouse erasing = 0, bad = 0, unchecked = 0; 16385a62db6SDavid Woodhouse int nr_counted = 0; 16485a62db6SDavid Woodhouse int dump = 0; 16585a62db6SDavid Woodhouse 16685a62db6SDavid Woodhouse if (c->gcblock) { 16785a62db6SDavid Woodhouse nr_counted++; 16885a62db6SDavid Woodhouse free += c->gcblock->free_size; 16985a62db6SDavid Woodhouse dirty += c->gcblock->dirty_size; 17085a62db6SDavid Woodhouse used += c->gcblock->used_size; 17185a62db6SDavid Woodhouse wasted += c->gcblock->wasted_size; 17285a62db6SDavid Woodhouse unchecked += c->gcblock->unchecked_size; 17385a62db6SDavid Woodhouse } 17485a62db6SDavid Woodhouse if (c->nextblock) { 17585a62db6SDavid Woodhouse nr_counted++; 17685a62db6SDavid Woodhouse free += c->nextblock->free_size; 17785a62db6SDavid Woodhouse dirty += c->nextblock->dirty_size; 17885a62db6SDavid Woodhouse used += c->nextblock->used_size; 17985a62db6SDavid Woodhouse wasted += c->nextblock->wasted_size; 18085a62db6SDavid Woodhouse unchecked += c->nextblock->unchecked_size; 18185a62db6SDavid Woodhouse } 18285a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->clean_list, list) { 18385a62db6SDavid Woodhouse nr_counted++; 18485a62db6SDavid Woodhouse free += jeb->free_size; 18585a62db6SDavid Woodhouse dirty += jeb->dirty_size; 18685a62db6SDavid Woodhouse used += jeb->used_size; 18785a62db6SDavid Woodhouse wasted += jeb->wasted_size; 18885a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 18985a62db6SDavid Woodhouse } 19085a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->very_dirty_list, list) { 19185a62db6SDavid Woodhouse nr_counted++; 19285a62db6SDavid Woodhouse free += jeb->free_size; 19385a62db6SDavid Woodhouse dirty += jeb->dirty_size; 19485a62db6SDavid Woodhouse used += jeb->used_size; 19585a62db6SDavid Woodhouse wasted += jeb->wasted_size; 19685a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 19785a62db6SDavid Woodhouse } 19885a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->dirty_list, list) { 19985a62db6SDavid Woodhouse nr_counted++; 20085a62db6SDavid Woodhouse free += jeb->free_size; 20185a62db6SDavid Woodhouse dirty += jeb->dirty_size; 20285a62db6SDavid Woodhouse used += jeb->used_size; 20385a62db6SDavid Woodhouse wasted += jeb->wasted_size; 20485a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 20585a62db6SDavid Woodhouse } 20685a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasable_list, list) { 20785a62db6SDavid Woodhouse nr_counted++; 20885a62db6SDavid Woodhouse free += jeb->free_size; 20985a62db6SDavid Woodhouse dirty += jeb->dirty_size; 21085a62db6SDavid Woodhouse used += jeb->used_size; 21185a62db6SDavid Woodhouse wasted += jeb->wasted_size; 21285a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 21385a62db6SDavid Woodhouse } 21485a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) { 21585a62db6SDavid Woodhouse nr_counted++; 21685a62db6SDavid Woodhouse free += jeb->free_size; 21785a62db6SDavid Woodhouse dirty += jeb->dirty_size; 21885a62db6SDavid Woodhouse used += jeb->used_size; 21985a62db6SDavid Woodhouse wasted += jeb->wasted_size; 22085a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 22185a62db6SDavid Woodhouse } 22285a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erase_pending_list, list) { 22385a62db6SDavid Woodhouse nr_counted++; 22485a62db6SDavid Woodhouse free += jeb->free_size; 22585a62db6SDavid Woodhouse dirty += jeb->dirty_size; 22685a62db6SDavid Woodhouse used += jeb->used_size; 22785a62db6SDavid Woodhouse wasted += jeb->wasted_size; 22885a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 22985a62db6SDavid Woodhouse } 23085a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->free_list, list) { 23185a62db6SDavid Woodhouse nr_counted++; 23285a62db6SDavid Woodhouse free += jeb->free_size; 23385a62db6SDavid Woodhouse dirty += jeb->dirty_size; 23485a62db6SDavid Woodhouse used += jeb->used_size; 23585a62db6SDavid Woodhouse wasted += jeb->wasted_size; 23685a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 23785a62db6SDavid Woodhouse } 23885a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->bad_used_list, list) { 23985a62db6SDavid Woodhouse nr_counted++; 24085a62db6SDavid Woodhouse free += jeb->free_size; 24185a62db6SDavid Woodhouse dirty += jeb->dirty_size; 24285a62db6SDavid Woodhouse used += jeb->used_size; 24385a62db6SDavid Woodhouse wasted += jeb->wasted_size; 24485a62db6SDavid Woodhouse unchecked += jeb->unchecked_size; 24585a62db6SDavid Woodhouse } 24685a62db6SDavid Woodhouse 24785a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erasing_list, list) { 24885a62db6SDavid Woodhouse nr_counted++; 24985a62db6SDavid Woodhouse erasing += c->sector_size; 25085a62db6SDavid Woodhouse } 251e2bc322bSDavid Woodhouse list_for_each_entry(jeb, &c->erase_checking_list, list) { 252e2bc322bSDavid Woodhouse nr_counted++; 253e2bc322bSDavid Woodhouse erasing += c->sector_size; 254e2bc322bSDavid Woodhouse } 25585a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->erase_complete_list, list) { 25685a62db6SDavid Woodhouse nr_counted++; 25785a62db6SDavid Woodhouse erasing += c->sector_size; 25885a62db6SDavid Woodhouse } 25985a62db6SDavid Woodhouse list_for_each_entry(jeb, &c->bad_list, list) { 26085a62db6SDavid Woodhouse nr_counted++; 26185a62db6SDavid Woodhouse bad += c->sector_size; 26285a62db6SDavid Woodhouse } 26385a62db6SDavid Woodhouse 26485a62db6SDavid Woodhouse #define check(sz) \ 26585a62db6SDavid Woodhouse if (sz != c->sz##_size) { \ 26685a62db6SDavid Woodhouse printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \ 26785a62db6SDavid Woodhouse sz, c->sz##_size); \ 26885a62db6SDavid Woodhouse dump = 1; \ 26985a62db6SDavid Woodhouse } 27085a62db6SDavid Woodhouse check(free); 27185a62db6SDavid Woodhouse check(dirty); 27285a62db6SDavid Woodhouse check(used); 27385a62db6SDavid Woodhouse check(wasted); 27485a62db6SDavid Woodhouse check(unchecked); 27585a62db6SDavid Woodhouse check(bad); 27685a62db6SDavid Woodhouse check(erasing); 27785a62db6SDavid Woodhouse #undef check 27885a62db6SDavid Woodhouse 27985a62db6SDavid Woodhouse if (nr_counted != c->nr_blocks) { 28085a62db6SDavid Woodhouse printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n", 28185a62db6SDavid Woodhouse __func__, nr_counted, c->nr_blocks); 28285a62db6SDavid Woodhouse dump = 1; 28385a62db6SDavid Woodhouse } 28485a62db6SDavid Woodhouse 28585a62db6SDavid Woodhouse if (dump) { 28685a62db6SDavid Woodhouse __jffs2_dbg_dump_block_lists_nolock(c); 28785a62db6SDavid Woodhouse BUG(); 28885a62db6SDavid Woodhouse } 28985a62db6SDavid Woodhouse } 29085a62db6SDavid Woodhouse 291730554d9SArtem B. Bityutskiy /* 292730554d9SArtem B. Bityutskiy * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. 293730554d9SArtem B. Bityutskiy */ 294730554d9SArtem B. Bityutskiy void 295e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, 296e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 297e0c8e42fSArtem B. Bityutskiy { 298e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 299e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 300e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 301e0c8e42fSArtem B. Bityutskiy } 302e0c8e42fSArtem B. Bityutskiy 303e0c8e42fSArtem B. Bityutskiy void 304e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, 305e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 306730554d9SArtem B. Bityutskiy { 307730554d9SArtem B. Bityutskiy uint32_t my_used_size = 0; 308730554d9SArtem B. Bityutskiy uint32_t my_unchecked_size = 0; 309730554d9SArtem B. Bityutskiy uint32_t my_dirty_size = 0; 310730554d9SArtem B. Bityutskiy struct jffs2_raw_node_ref *ref2 = jeb->first_node; 311730554d9SArtem B. Bityutskiy 312730554d9SArtem B. Bityutskiy while (ref2) { 313730554d9SArtem B. Bityutskiy uint32_t totlen = ref_totlen(c, jeb, ref2); 314730554d9SArtem B. Bityutskiy 315abb536e7SKyungmin Park if (ref_offset(ref2) < jeb->offset || 316abb536e7SKyungmin Park ref_offset(ref2) > jeb->offset + c->sector_size) { 317e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", 318730554d9SArtem B. Bityutskiy ref_offset(ref2), jeb->offset); 319e0c8e42fSArtem B. Bityutskiy goto error; 320730554d9SArtem B. Bityutskiy 321730554d9SArtem B. Bityutskiy } 322730554d9SArtem B. Bityutskiy if (ref_flags(ref2) == REF_UNCHECKED) 323730554d9SArtem B. Bityutskiy my_unchecked_size += totlen; 324730554d9SArtem B. Bityutskiy else if (!ref_obsolete(ref2)) 325730554d9SArtem B. Bityutskiy my_used_size += totlen; 326730554d9SArtem B. Bityutskiy else 327730554d9SArtem B. Bityutskiy my_dirty_size += totlen; 328730554d9SArtem B. Bityutskiy 32999988f7bSDavid Woodhouse if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) { 33099988f7bSDavid Woodhouse JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n", 33199988f7bSDavid Woodhouse ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2), 332730554d9SArtem B. Bityutskiy ref_offset(jeb->last_node), jeb->last_node); 333e0c8e42fSArtem B. Bityutskiy goto error; 334730554d9SArtem B. Bityutskiy } 33599988f7bSDavid Woodhouse ref2 = ref_next(ref2); 336730554d9SArtem B. Bityutskiy } 337730554d9SArtem B. Bityutskiy 338730554d9SArtem B. Bityutskiy if (my_used_size != jeb->used_size) { 339e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n", 340730554d9SArtem B. Bityutskiy my_used_size, jeb->used_size); 341e0c8e42fSArtem B. Bityutskiy goto error; 342730554d9SArtem B. Bityutskiy } 343730554d9SArtem B. Bityutskiy 344730554d9SArtem B. Bityutskiy if (my_unchecked_size != jeb->unchecked_size) { 345e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n", 346730554d9SArtem B. Bityutskiy my_unchecked_size, jeb->unchecked_size); 347e0c8e42fSArtem B. Bityutskiy goto error; 348730554d9SArtem B. Bityutskiy } 349730554d9SArtem B. Bityutskiy 350e0c8e42fSArtem B. Bityutskiy #if 0 351e0c8e42fSArtem B. Bityutskiy /* This should work when we implement ref->__totlen elemination */ 352730554d9SArtem B. Bityutskiy if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) { 353e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n", 354730554d9SArtem B. Bityutskiy my_dirty_size, jeb->dirty_size + jeb->wasted_size); 355e0c8e42fSArtem B. Bityutskiy goto error; 356730554d9SArtem B. Bityutskiy } 357730554d9SArtem B. Bityutskiy 358730554d9SArtem B. Bityutskiy if (jeb->free_size == 0 359730554d9SArtem B. Bityutskiy && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) { 360e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n", 361730554d9SArtem B. Bityutskiy my_used_size + my_unchecked_size + my_dirty_size, 362730554d9SArtem B. Bityutskiy c->sector_size); 363e0c8e42fSArtem B. Bityutskiy goto error; 364730554d9SArtem B. Bityutskiy } 365e0c8e42fSArtem B. Bityutskiy #endif 366730554d9SArtem B. Bityutskiy 36785a62db6SDavid Woodhouse if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING))) 36885a62db6SDavid Woodhouse __jffs2_dbg_superblock_counts(c); 36985a62db6SDavid Woodhouse 370e0c8e42fSArtem B. Bityutskiy return; 371e0c8e42fSArtem B. Bityutskiy 372e0c8e42fSArtem B. Bityutskiy error: 373e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(c, jeb); 374e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(jeb); 375e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(c); 376e0c8e42fSArtem B. Bityutskiy BUG(); 377e0c8e42fSArtem B. Bityutskiy 378e0c8e42fSArtem B. Bityutskiy } 379e0c8e42fSArtem B. Bityutskiy #endif /* JFFS2_DBG_PARANOIA_CHECKS */ 380e0c8e42fSArtem B. Bityutskiy 381e0c8e42fSArtem B. Bityutskiy #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) 382730554d9SArtem B. Bityutskiy /* 383730554d9SArtem B. Bityutskiy * Dump the node_refs of the 'jeb' JFFS2 eraseblock. 384730554d9SArtem B. Bityutskiy */ 385730554d9SArtem B. Bityutskiy void 386e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, 387e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 388e0c8e42fSArtem B. Bityutskiy { 389e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 390e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(c, jeb); 391e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 392e0c8e42fSArtem B. Bityutskiy } 393e0c8e42fSArtem B. Bityutskiy 394e0c8e42fSArtem B. Bityutskiy void 395e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, 396e0c8e42fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb) 397730554d9SArtem B. Bityutskiy { 398730554d9SArtem B. Bityutskiy struct jffs2_raw_node_ref *ref; 399730554d9SArtem B. Bityutskiy int i = 0; 400730554d9SArtem B. Bityutskiy 40181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset); 402730554d9SArtem B. Bityutskiy if (!jeb->first_node) { 40381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset); 404730554d9SArtem B. Bityutskiy return; 405730554d9SArtem B. Bityutskiy } 406730554d9SArtem B. Bityutskiy 40781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG); 40899988f7bSDavid Woodhouse for (ref = jeb->first_node; ; ref = ref_next(ref)) { 40927e6b8e3SDavid Woodhouse printk("%#08x", ref_offset(ref)); 41027e6b8e3SDavid Woodhouse #ifdef TEST_TOTLEN 41127e6b8e3SDavid Woodhouse printk("(%x)", ref->__totlen); 41227e6b8e3SDavid Woodhouse #endif 41399988f7bSDavid Woodhouse if (ref_next(ref)) 414730554d9SArtem B. Bityutskiy printk("->"); 415730554d9SArtem B. Bityutskiy else 416730554d9SArtem B. Bityutskiy break; 417730554d9SArtem B. Bityutskiy if (++i == 4) { 418730554d9SArtem B. Bityutskiy i = 0; 41981e39cf0SArtem B. Bityutskiy printk("\n" JFFS2_DBG); 420730554d9SArtem B. Bityutskiy } 421730554d9SArtem B. Bityutskiy } 422730554d9SArtem B. Bityutskiy printk("\n"); 423730554d9SArtem B. Bityutskiy } 424730554d9SArtem B. Bityutskiy 425e0c8e42fSArtem B. Bityutskiy /* 426e0c8e42fSArtem B. Bityutskiy * Dump an eraseblock's space accounting. 427e0c8e42fSArtem B. Bityutskiy */ 428730554d9SArtem B. Bityutskiy void 429e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 430730554d9SArtem B. Bityutskiy { 431e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 432e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(jeb); 433e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 434e0c8e42fSArtem B. Bityutskiy } 435e0c8e42fSArtem B. Bityutskiy 436e0c8e42fSArtem B. Bityutskiy void 437e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb) 438e0c8e42fSArtem B. Bityutskiy { 439e0c8e42fSArtem B. Bityutskiy if (!jeb) 440e0c8e42fSArtem B. Bityutskiy return; 441e0c8e42fSArtem B. Bityutskiy 44281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n", 443e0c8e42fSArtem B. Bityutskiy jeb->offset); 444e0c8e42fSArtem B. Bityutskiy 44581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size); 44681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size); 44781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size); 44881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size); 44981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size); 450e0c8e42fSArtem B. Bityutskiy } 451e0c8e42fSArtem B. Bityutskiy 452e0c8e42fSArtem B. Bityutskiy void 453e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) 454e0c8e42fSArtem B. Bityutskiy { 455e0c8e42fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 456e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(c); 457e0c8e42fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 458e0c8e42fSArtem B. Bityutskiy } 459e0c8e42fSArtem B. Bityutskiy 460e0c8e42fSArtem B. Bityutskiy void 461e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) 462e0c8e42fSArtem B. Bityutskiy { 46381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n"); 464e0c8e42fSArtem B. Bityutskiy 46581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size); 46681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "used_size: %#08x\n", c->used_size); 46781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size); 46881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size); 46981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size); 47081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_size: %#08x\n", c->free_size); 47181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size); 47281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size); 47381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size); 47481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n", 475730554d9SArtem B. Bityutskiy c->sector_size * c->resv_blocks_write); 476730554d9SArtem B. Bityutskiy 477730554d9SArtem B. Bityutskiy if (c->nextblock) 47881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 479730554d9SArtem B. Bityutskiy c->nextblock->offset, c->nextblock->used_size, 480730554d9SArtem B. Bityutskiy c->nextblock->dirty_size, c->nextblock->wasted_size, 481730554d9SArtem B. Bityutskiy c->nextblock->unchecked_size, c->nextblock->free_size); 482730554d9SArtem B. Bityutskiy else 48381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nextblock: NULL\n"); 484730554d9SArtem B. Bityutskiy 485730554d9SArtem B. Bityutskiy if (c->gcblock) 48681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 487730554d9SArtem B. Bityutskiy c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, 488730554d9SArtem B. Bityutskiy c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); 489730554d9SArtem B. Bityutskiy else 49081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gcblock: NULL\n"); 491730554d9SArtem B. Bityutskiy 492730554d9SArtem B. Bityutskiy if (list_empty(&c->clean_list)) { 49381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "clean_list: empty\n"); 494730554d9SArtem B. Bityutskiy } else { 495730554d9SArtem B. Bityutskiy struct list_head *this; 496730554d9SArtem B. Bityutskiy int numblocks = 0; 497730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 498730554d9SArtem B. Bityutskiy 499730554d9SArtem B. Bityutskiy list_for_each(this, &c->clean_list) { 500730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 501730554d9SArtem B. Bityutskiy numblocks ++; 502730554d9SArtem B. Bityutskiy dirty += jeb->wasted_size; 503730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 50481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 505730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 506730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 507730554d9SArtem B. Bityutskiy } 508730554d9SArtem B. Bityutskiy } 509730554d9SArtem B. Bityutskiy 51081e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", 511730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 512730554d9SArtem B. Bityutskiy } 513730554d9SArtem B. Bityutskiy 514730554d9SArtem B. Bityutskiy if (list_empty(&c->very_dirty_list)) { 51581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "very_dirty_list: empty\n"); 516730554d9SArtem B. Bityutskiy } else { 517730554d9SArtem B. Bityutskiy struct list_head *this; 518730554d9SArtem B. Bityutskiy int numblocks = 0; 519730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 520730554d9SArtem B. Bityutskiy 521730554d9SArtem B. Bityutskiy list_for_each(this, &c->very_dirty_list) { 522730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 523730554d9SArtem B. Bityutskiy 524730554d9SArtem B. Bityutskiy numblocks ++; 525730554d9SArtem B. Bityutskiy dirty += jeb->dirty_size; 526730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 52781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 528730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 529730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 530730554d9SArtem B. Bityutskiy } 531730554d9SArtem B. Bityutskiy } 532730554d9SArtem B. Bityutskiy 53381e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", 534730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 535730554d9SArtem B. Bityutskiy } 536730554d9SArtem B. Bityutskiy 537730554d9SArtem B. Bityutskiy if (list_empty(&c->dirty_list)) { 53881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_list: empty\n"); 539730554d9SArtem B. Bityutskiy } else { 540730554d9SArtem B. Bityutskiy struct list_head *this; 541730554d9SArtem B. Bityutskiy int numblocks = 0; 542730554d9SArtem B. Bityutskiy uint32_t dirty = 0; 543730554d9SArtem B. Bityutskiy 544730554d9SArtem B. Bityutskiy list_for_each(this, &c->dirty_list) { 545730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 546730554d9SArtem B. Bityutskiy 547730554d9SArtem B. Bityutskiy numblocks ++; 548730554d9SArtem B. Bityutskiy dirty += jeb->dirty_size; 549730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 55081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 551730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 552730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 553730554d9SArtem B. Bityutskiy } 554730554d9SArtem B. Bityutskiy } 555730554d9SArtem B. Bityutskiy 55681e39cf0SArtem B. Bityutskiy printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n", 557730554d9SArtem B. Bityutskiy numblocks, dirty, dirty / numblocks); 558730554d9SArtem B. Bityutskiy } 559730554d9SArtem B. Bityutskiy 560730554d9SArtem B. Bityutskiy if (list_empty(&c->erasable_list)) { 56181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_list: empty\n"); 562730554d9SArtem B. Bityutskiy } else { 563730554d9SArtem B. Bityutskiy struct list_head *this; 564730554d9SArtem B. Bityutskiy 565730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasable_list) { 566730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 567730554d9SArtem B. Bityutskiy 568730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 56981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 570730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 571730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 572730554d9SArtem B. Bityutskiy } 573730554d9SArtem B. Bityutskiy } 574730554d9SArtem B. Bityutskiy } 575730554d9SArtem B. Bityutskiy 576730554d9SArtem B. Bityutskiy if (list_empty(&c->erasing_list)) { 57781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_list: empty\n"); 578730554d9SArtem B. Bityutskiy } else { 579730554d9SArtem B. Bityutskiy struct list_head *this; 580730554d9SArtem B. Bityutskiy 581730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasing_list) { 582730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 583730554d9SArtem B. Bityutskiy 584730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 58581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 586730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 587730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 588730554d9SArtem B. Bityutskiy } 589730554d9SArtem B. Bityutskiy } 590730554d9SArtem B. Bityutskiy } 591e2bc322bSDavid Woodhouse if (list_empty(&c->erase_checking_list)) { 592e2bc322bSDavid Woodhouse printk(JFFS2_DBG "erase_checking_list: empty\n"); 593e2bc322bSDavid Woodhouse } else { 594e2bc322bSDavid Woodhouse struct list_head *this; 595e2bc322bSDavid Woodhouse 596e2bc322bSDavid Woodhouse list_for_each(this, &c->erase_checking_list) { 597e2bc322bSDavid Woodhouse struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 598e2bc322bSDavid Woodhouse 599e2bc322bSDavid Woodhouse if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 600e2bc322bSDavid Woodhouse printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 601e2bc322bSDavid Woodhouse jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 602e2bc322bSDavid Woodhouse jeb->unchecked_size, jeb->free_size); 603e2bc322bSDavid Woodhouse } 604e2bc322bSDavid Woodhouse } 605e2bc322bSDavid Woodhouse } 606730554d9SArtem B. Bityutskiy 607730554d9SArtem B. Bityutskiy if (list_empty(&c->erase_pending_list)) { 60881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erase_pending_list: empty\n"); 609730554d9SArtem B. Bityutskiy } else { 610730554d9SArtem B. Bityutskiy struct list_head *this; 611730554d9SArtem B. Bityutskiy 612730554d9SArtem B. Bityutskiy list_for_each(this, &c->erase_pending_list) { 613730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 614730554d9SArtem B. Bityutskiy 615730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 61681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 617730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 618730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 619730554d9SArtem B. Bityutskiy } 620730554d9SArtem B. Bityutskiy } 621730554d9SArtem B. Bityutskiy } 622730554d9SArtem B. Bityutskiy 623730554d9SArtem B. Bityutskiy if (list_empty(&c->erasable_pending_wbuf_list)) { 62481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n"); 625730554d9SArtem B. Bityutskiy } else { 626730554d9SArtem B. Bityutskiy struct list_head *this; 627730554d9SArtem B. Bityutskiy 628730554d9SArtem B. Bityutskiy list_for_each(this, &c->erasable_pending_wbuf_list) { 629730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 630730554d9SArtem B. Bityutskiy 631730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 63281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 633730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 634730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 635730554d9SArtem B. Bityutskiy } 636730554d9SArtem B. Bityutskiy } 637730554d9SArtem B. Bityutskiy } 638730554d9SArtem B. Bityutskiy 639730554d9SArtem B. Bityutskiy if (list_empty(&c->free_list)) { 64081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_list: empty\n"); 641730554d9SArtem B. Bityutskiy } else { 642730554d9SArtem B. Bityutskiy struct list_head *this; 643730554d9SArtem B. Bityutskiy 644730554d9SArtem B. Bityutskiy list_for_each(this, &c->free_list) { 645730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 646730554d9SArtem B. Bityutskiy 647730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 64881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 649730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 650730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 651730554d9SArtem B. Bityutskiy } 652730554d9SArtem B. Bityutskiy } 653730554d9SArtem B. Bityutskiy } 654730554d9SArtem B. Bityutskiy 655730554d9SArtem B. Bityutskiy if (list_empty(&c->bad_list)) { 65681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_list: empty\n"); 657730554d9SArtem B. Bityutskiy } else { 658730554d9SArtem B. Bityutskiy struct list_head *this; 659730554d9SArtem B. Bityutskiy 660730554d9SArtem B. Bityutskiy list_for_each(this, &c->bad_list) { 661730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 662730554d9SArtem B. Bityutskiy 663730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 66481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 665730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 666730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 667730554d9SArtem B. Bityutskiy } 668730554d9SArtem B. Bityutskiy } 669730554d9SArtem B. Bityutskiy } 670730554d9SArtem B. Bityutskiy 671730554d9SArtem B. Bityutskiy if (list_empty(&c->bad_used_list)) { 67281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_used_list: empty\n"); 673730554d9SArtem B. Bityutskiy } else { 674730554d9SArtem B. Bityutskiy struct list_head *this; 675730554d9SArtem B. Bityutskiy 676730554d9SArtem B. Bityutskiy list_for_each(this, &c->bad_used_list) { 677730554d9SArtem B. Bityutskiy struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 678730554d9SArtem B. Bityutskiy 679730554d9SArtem B. Bityutskiy if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { 68081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", 681730554d9SArtem B. Bityutskiy jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, 682730554d9SArtem B. Bityutskiy jeb->unchecked_size, jeb->free_size); 683730554d9SArtem B. Bityutskiy } 684730554d9SArtem B. Bityutskiy } 685730554d9SArtem B. Bityutskiy } 686730554d9SArtem B. Bityutskiy } 687730554d9SArtem B. Bityutskiy 688730554d9SArtem B. Bityutskiy void 689e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) 690e0c8e42fSArtem B. Bityutskiy { 691ced22070SDavid Woodhouse mutex_lock(&f->sem); 692e0c8e42fSArtem B. Bityutskiy jffs2_dbg_dump_fragtree_nolock(f); 693ced22070SDavid Woodhouse mutex_unlock(&f->sem); 694e0c8e42fSArtem B. Bityutskiy } 695e0c8e42fSArtem B. Bityutskiy 696e0c8e42fSArtem B. Bityutskiy void 697e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f) 698730554d9SArtem B. Bityutskiy { 699730554d9SArtem B. Bityutskiy struct jffs2_node_frag *this = frag_first(&f->fragtree); 700730554d9SArtem B. Bityutskiy uint32_t lastofs = 0; 701730554d9SArtem B. Bityutskiy int buggy = 0; 702730554d9SArtem B. Bityutskiy 70381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino); 704730554d9SArtem B. Bityutskiy while(this) { 705730554d9SArtem B. Bityutskiy if (this->node) 70681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n", 707730554d9SArtem B. Bityutskiy this->ofs, this->ofs+this->size, ref_offset(this->node->raw), 708730554d9SArtem B. Bityutskiy ref_flags(this->node->raw), this, frag_left(this), frag_right(this), 709730554d9SArtem B. Bityutskiy frag_parent(this)); 710730554d9SArtem B. Bityutskiy else 71181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", 712730554d9SArtem B. Bityutskiy this->ofs, this->ofs+this->size, this, frag_left(this), 713730554d9SArtem B. Bityutskiy frag_right(this), frag_parent(this)); 714730554d9SArtem B. Bityutskiy if (this->ofs != lastofs) 715730554d9SArtem B. Bityutskiy buggy = 1; 716730554d9SArtem B. Bityutskiy lastofs = this->ofs + this->size; 717730554d9SArtem B. Bityutskiy this = frag_next(this); 718730554d9SArtem B. Bityutskiy } 719730554d9SArtem B. Bityutskiy 720730554d9SArtem B. Bityutskiy if (f->metadata) 72181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); 722730554d9SArtem B. Bityutskiy 723730554d9SArtem B. Bityutskiy if (buggy) { 724e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("frag tree got a hole in it.\n"); 725730554d9SArtem B. Bityutskiy BUG(); 726730554d9SArtem B. Bityutskiy } 727730554d9SArtem B. Bityutskiy } 728730554d9SArtem B. Bityutskiy 729e0c8e42fSArtem B. Bityutskiy #define JFFS2_BUFDUMP_BYTES_PER_LINE 32 730730554d9SArtem B. Bityutskiy void 731e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs) 732730554d9SArtem B. Bityutskiy { 733e0c8e42fSArtem B. Bityutskiy int skip; 734e0c8e42fSArtem B. Bityutskiy int i; 735e0c8e42fSArtem B. Bityutskiy 73681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n", 737e0c8e42fSArtem B. Bityutskiy offs, offs + len, len); 738e0c8e42fSArtem B. Bityutskiy i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE; 739e0c8e42fSArtem B. Bityutskiy offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1); 740e0c8e42fSArtem B. Bityutskiy 741e0c8e42fSArtem B. Bityutskiy if (skip != 0) 74281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "%#08x: ", offs); 743e0c8e42fSArtem B. Bityutskiy 744e0c8e42fSArtem B. Bityutskiy while (skip--) 745e0c8e42fSArtem B. Bityutskiy printk(" "); 746730554d9SArtem B. Bityutskiy 747730554d9SArtem B. Bityutskiy while (i < len) { 748e0c8e42fSArtem B. Bityutskiy if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) { 749e0c8e42fSArtem B. Bityutskiy if (i != 0) 750e0c8e42fSArtem B. Bityutskiy printk("\n"); 751e0c8e42fSArtem B. Bityutskiy offs += JFFS2_BUFDUMP_BYTES_PER_LINE; 75281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "%0#8x: ", offs); 753730554d9SArtem B. Bityutskiy } 754730554d9SArtem B. Bityutskiy 755e0c8e42fSArtem B. Bityutskiy printk("%02x ", buf[i]); 756e0c8e42fSArtem B. Bityutskiy 757e0c8e42fSArtem B. Bityutskiy i += 1; 758730554d9SArtem B. Bityutskiy } 759730554d9SArtem B. Bityutskiy 760e0c8e42fSArtem B. Bityutskiy printk("\n"); 761e0c8e42fSArtem B. Bityutskiy } 762e0c8e42fSArtem B. Bityutskiy 763e0c8e42fSArtem B. Bityutskiy /* 764e0c8e42fSArtem B. Bityutskiy * Dump a JFFS2 node. 765e0c8e42fSArtem B. Bityutskiy */ 766e0c8e42fSArtem B. Bityutskiy void 767e0c8e42fSArtem B. Bityutskiy __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) 768e0c8e42fSArtem B. Bityutskiy { 769e0c8e42fSArtem B. Bityutskiy union jffs2_node_union node; 770e0c8e42fSArtem B. Bityutskiy int len = sizeof(union jffs2_node_union); 771e0c8e42fSArtem B. Bityutskiy size_t retlen; 772e0c8e42fSArtem B. Bityutskiy uint32_t crc; 773e0c8e42fSArtem B. Bityutskiy int ret; 774e0c8e42fSArtem B. Bityutskiy 77581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); 776e0c8e42fSArtem B. Bityutskiy 777e0c8e42fSArtem B. Bityutskiy ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); 778e0c8e42fSArtem B. Bityutskiy if (ret || (retlen != len)) { 779e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", 780e0c8e42fSArtem B. Bityutskiy len, ret, retlen); 781e0c8e42fSArtem B. Bityutskiy return; 782e0c8e42fSArtem B. Bityutskiy } 783e0c8e42fSArtem B. Bityutskiy 78481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic)); 78581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype)); 78681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen)); 78781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc)); 788e0c8e42fSArtem B. Bityutskiy 789e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.u, sizeof(node.u) - 4); 790e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.u.hdr_crc)) { 791e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong common header CRC.\n"); 792e0c8e42fSArtem B. Bityutskiy return; 793e0c8e42fSArtem B. Bityutskiy } 794e0c8e42fSArtem B. Bityutskiy 795e0c8e42fSArtem B. Bityutskiy if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK && 796e0c8e42fSArtem B. Bityutskiy je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK) 797e0c8e42fSArtem B. Bityutskiy { 798e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n", 799e0c8e42fSArtem B. Bityutskiy je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK); 800e0c8e42fSArtem B. Bityutskiy return; 801e0c8e42fSArtem B. Bityutskiy } 802e0c8e42fSArtem B. Bityutskiy 803e0c8e42fSArtem B. Bityutskiy switch(je16_to_cpu(node.u.nodetype)) { 804e0c8e42fSArtem B. Bityutskiy 805e0c8e42fSArtem B. Bityutskiy case JFFS2_NODETYPE_INODE: 806e0c8e42fSArtem B. Bityutskiy 80781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "the node is inode node\n"); 80881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino)); 80981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version)); 81081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m); 81181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid)); 81281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid)); 81381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize)); 81481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime)); 81581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime)); 81681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime)); 81781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset)); 81881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize)); 81981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize)); 82081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr); 82181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr); 82281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags)); 82381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc)); 82481e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc)); 82581e39cf0SArtem B. Bityutskiy 826e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.i, sizeof(node.i) - 8); 827e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.i.node_crc)) { 828e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node header CRC.\n"); 829e0c8e42fSArtem B. Bityutskiy return; 830e0c8e42fSArtem B. Bityutskiy } 831e0c8e42fSArtem B. Bityutskiy break; 832e0c8e42fSArtem B. Bityutskiy 833e0c8e42fSArtem B. Bityutskiy case JFFS2_NODETYPE_DIRENT: 834e0c8e42fSArtem B. Bityutskiy 83581e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "the node is dirent node\n"); 83681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino)); 83781e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version)); 83881e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino)); 83981e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime)); 84081e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize); 84181e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "type:\t%#02x\n", node.d.type); 84281e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc)); 84381e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc)); 844e0c8e42fSArtem B. Bityutskiy 845e0c8e42fSArtem B. Bityutskiy node.d.name[node.d.nsize] = '\0'; 84681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name); 847e0c8e42fSArtem B. Bityutskiy 848e0c8e42fSArtem B. Bityutskiy crc = crc32(0, &node.d, sizeof(node.d) - 8); 849e0c8e42fSArtem B. Bityutskiy if (crc != je32_to_cpu(node.d.node_crc)) { 850e0c8e42fSArtem B. Bityutskiy JFFS2_ERROR("wrong node header CRC.\n"); 851e0c8e42fSArtem B. Bityutskiy return; 852e0c8e42fSArtem B. Bityutskiy } 853e0c8e42fSArtem B. Bityutskiy break; 854e0c8e42fSArtem B. Bityutskiy 855e0c8e42fSArtem B. Bityutskiy default: 85681e39cf0SArtem B. Bityutskiy printk(JFFS2_DBG "node type is unknown\n"); 857e0c8e42fSArtem B. Bityutskiy break; 858730554d9SArtem B. Bityutskiy } 859730554d9SArtem B. Bityutskiy } 860e0c8e42fSArtem B. Bityutskiy #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */ 861